溫故而知新,可以爲師矣
重新過一下已經掌握的排序方法,最基礎的東西往往最關鍵!
寫在最前面
新年伊始就得了場感冒,咳嗽從19年咳到了20年,考完研也休息的差不多了,大家一起共勉!
文章框架
快速排序
package com.immunize.December.sort;
/**
* 快速排序1.2
*
* @author Mr IMMUNIZE
*
*/
public class Quick3 {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
quickSort(a, 0, a.length - 1);
// SimpleSelectSort2(a);
Print(a);
}
public static void quickSort(int[] a, int left, int right) {
int q;
if (left < right) {
q = Partition(a, left, right);
quickSort(a, left, q - 1);
quickSort(a, q + 1, right);
}
}
private static int Partition(int[] a, int left, int right) {
int i, j, s;
s = a[right];
i = left - 1;
for (j = left; j < right; j++) {
if (a[j] <= a[right]) {
i++;
Swap(a, i, j);
}
}
Swap(a, i + 1, right);
return i + 1;
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
上面這個版本是最優的改進版本,因爲快速排序的精髓在與找到最優的標準,以下附上以數組中間值作爲標準來進行比較的快排代碼:
package com.immunize.December.sort;
/**
* 快速排序1.1
*
* @author Mr IMMUNIZE
*
*/
public class Quick2 {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
QuickSort(a, 0, a.length - 1);
// SimpleSelectSort2(a);
Print(a);
}
/*
* 6 2 5 4 8 9 4 2 5 6 8 9 2 4 5 6 8 9
*
*/
public static void QuickSort(int[] a, int left, int right) {
int i, j, crit;
if (left > right)
return;
i = left - 1;
j = right + 1;
// crit = a[0];
crit = a[(left + right) / 2];
while (true) {
while (a[++i] < crit)
;
while (a[--j] > crit)
;
if (i >= j)
break;
Swap(a, i, j);
}
QuickSort(a, left, i - 1);
QuickSort(a, j + 1, right);
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
快速排序的最差時間複雜度爲O(n²),但在大多數時候的效率是很好的,必須掌握。以下排序僅附上代碼重寫,不再贅述原理
堆排序
package com.immunize.December.sort;
/**
* Heap排序:基於選擇排序的改進
*
* @author Mr IMMUNIZE
*
*/
public class Heap {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
HeapSort(a);
// SimpleSelectSort2(a);
Print(a);
}
// 堆排序
public static void HeapSort(int[] arr) {
// 構造大根堆
HeapInsert(arr);
int size = arr.length;
while (size > 1) {
// 交換大根和最後一個值,即固定最大值
Swap(arr, 0, size - 1);
// size遞減
size--;
Heapify(arr, 0, size);
}
}
// 構造大根堆(通過新插入的數上升)
public static void HeapInsert(int[] arr) {
// 定義所使用的變量
int i, curIndex, faIndex;
for (i = 0; i < arr.length; i++) {
// 確定當前索引值
curIndex = i;
// 計算父節點索引值
faIndex = (curIndex - 1) / 2;
// 遍歷,構造大根堆
while (arr[curIndex] > arr[faIndex]) {
Swap(arr, curIndex, faIndex);
// 將當前索引和父節點索引歸位
curIndex = faIndex;
faIndex = (curIndex - 1) / 2;
}
}
}
// 將剩餘的數構造成大根堆(通過頂端的數下降)
public static void Heapify(int[] arr, int index, int size) {
// 定義使用的變量
int left, right, largerIndex;
// 計算當前節點的左右節點索引
left = 2 * index + 1;
right = 2 * index + 2;
// 確保較小的子節點:左節點小於待排序節點個數
while (left < size) {
// 找到左右節點中較大的節點索引
if (arr[left] < arr[right] && right < size)
largerIndex = right;
else
largerIndex = left;
// 比較當前索引和左右節點中較大的索引處的值,若當前索引較大,則已經是大根堆,跳出循環即可。
if (arr[index] > arr[largerIndex]) {
largerIndex = index;
break;
}
Swap(arr, index, largerIndex);
// 重新指向當前索引和當前索引的左右子節點
index = largerIndex;
left = 2 * index + 1;
right = 2 * index + 2;
}
}
// 交換數組中兩個元素的值
public static void Swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
}
希爾排序
package com.immunize.December.sort;
public class Shell {
public static void main(String[] args) {
// 生成原始數組
int[] a = Generate(100, 10);
// 原始數組打印
System.out.println("原始數組:");
Print(a);
// 希爾排序後的數組打印
System.out.println("排序後的數組");
// shellSort1(a);
shellSort2(a);
Print(a);
}
public static void shellSort2(int[] a) {
int gap = a.length / 2;
int i, j;
for (; gap > 0; gap /= 2) {
for (i = gap; i < a.length; i++) {
j = i;
while (j - gap >= 0 && a[j] < a[j - gap]) {
Swap(a, j, j - gap);
j -= gap;
}
}
}
}
// 希爾排序
public static void shellSort1(int[] arr) {
int i, j, k, tmp;
int gap = arr.length / 2;
while (gap > 0) {
for (k = 0; k < gap; k++) {
for (i = k + gap; i < arr.length; i += gap) {
for (j = i - gap; j >= k; j -= gap) {
if (arr[j] > arr[j + gap]) {
Swap(arr, j, j + gap);
} else {
break;
}
}
}
}
gap /= 2;
}
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
計數排序
package com.immunize.December.sort;
public class Count {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
Print(countSort(a));
}
public static int[] countSort(int[] a) {
// 找出數組中的最大值
int max = Integer.MIN_VALUE;
for (int num : a) {
max = Math.max(max, num);
}
// 初始化計數數組
int[] count = new int[max + 1];
// 對數組計數
for (int num : a) {
count[num]++;
}
// 創建結果數組
int[] result = new int[a.length];
int index = 0;
for (int i = 0; i < count.length; i++) {
while (count[i] > 0) {
result[index++] = i;
count[i]--;
}
}
return result;
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
桶排序
package com.immunize.December.sort;
public class Radix {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
System.out.println("排序後的數組");
RadixSort(a, 3);
Print(a);
}
public static void RadixSort(int[] arr, int max) {
// count數組用來計數
int[] count = new int[arr.length];
// bucket用來當桶(在下面你就理解了什麼是桶了),放數據,取數據
int[] bucket = new int[arr.length];
// k表示第幾位,1代表個位,2代表十位,3代表百位
for (int k = 1; k <= max; k++) {
// 把count置空,防止上次循環的數據影響
for (int i = 0; i < arr.length; i++) {
count[i] = 0;
}
// 分別統計第k位是0,1,2,3,4,5,6,7,8,9的數量
// 以下便稱爲桶
// 即此循環用來統計每個桶中的數據的數量
for (int i = 0; i < arr.length; i++) {
count[getFigure(arr[i], k)]++;
}
// 利用count[i]來確定放置數據的位置
for (int i = 1; i < arr.length; i++) {
count[i] = count[i] + count[i - 1];
}
// 執行完此循環之後的count[i]就是第i個桶右邊界的位置
// 利用循環把數據裝入各個桶中,注意是從後往前裝
// 這裏是重點,一定要仔細理解
for (int i = arr.length - 1; i >= 0; i--) {
int j = getFigure(arr[i], k);
bucket[count[j] - 1] = arr[i];
count[j]--;
}
// 將桶中的數據取出來,賦值給arr
for (int i = 0, j = 0; i < arr.length; i++, j++) {
arr[i] = bucket[j];
}
}
}
// 此函數返回整型數i的第k位是什麼
public static int getFigure(int i, int k) {
int[] a = { 1, 10, 100 };
return (i / a[k - 1]) % 10;
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
冒泡排序
package com.immunize.December.sort;
public class Bubble {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
bubbleSort(a);
// SimpleSelectSort2(a);
Print(a);
}
public static void bubbleSort(int[] a) {
// 兩兩對比,每次將最大的放到最後面
int i, j;
// i爲遍歷指針,從0-a.length-2
for (i = 0; i < a.length - 1; i++) {
// j爲比較指針,從1-(a.length-i)
for (j = 1; j < a.length - i; j++) {
if (a[j] < a[j - 1])
Swap(a, j, j - 1);
}
}
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
雞尾酒排序
package com.immunize.December.sort;
import java.util.Arrays;
public class Shaker {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
ShakerSort(a);
// SimpleSelectSort2(a);
Print(a);
// Print(cocktailSort(a));
}
public static void ShakerSort(int[] a) {
int i, j, left, right, shift;
left = 0;
right = a.length - 1;
shift = 0;
while (left < right) {
for (i = left; i < right; i++) {
if (a[i] > a[i + 1]) {
Swap(a, i, i + 1);
shift = i;
}
}
right = shift;
for (j = right; j > left; j--) {
if (a[j - 1] > a[j]) {
Swap(a, j, j - 1);
shift = j;
}
}
left = shift;
}
}
public static int[] cocktailSort(int[] src) {
int len = src.length;
// 將最小值排到隊尾
for (int i = 0; i < len / 2; i++) {
for (int j = i; j < len - i - 1; j++) {
if (src[j] < src[j + 1]) {
int temp = src[j];
src[j] = src[j + 1];
src[j + 1] = temp;
}
System.out.println("交換小" + Arrays.toString(src));
}
// 將最大值排到隊頭
for (int j = len - 1 - (i + 1); j > i; j--) {
if (src[j] > src[j - 1]) {
int temp = src[j];
src[j] = src[j - 1];
src[j - 1] = temp;
}
System.out.println("交換大" + Arrays.toString(src));
}
System.out.println("第" + i + "次排序結果:" + Arrays.toString(src));
}
return src;
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
雞尾酒排序這裏多說一點,兩種寫法都在代碼中呈現出來,ShakerSort/cocktailSort都稱爲雞尾酒排序
選擇排序
package com.immunize.December.sort;
import java.util.Arrays;
public class Select {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
// Print(Arrays.copyOfRange(a, 0, a.length));
System.out.println("排序後的數組");
// selectSort1(a);
selectSort2(a);
// SimpleSelectSort2(a);
Print(a);
}
public static void selectSort1(int[] a) {
int i, j, tmp;
for (i = 0; i < a.length - 1; i++) {
// 獲取當前索引
tmp = i;
for (j = i + 1; j < a.length; j++) {
if (a[tmp] > a[j]) {
Swap(a, j, tmp);
}
}
}
}
public static void selectSort2(int[] a) {
int i, j, tmp;
for (i = 0; i < a.length - 1; i++) {
tmp = i;
Swap(a, tmp, FindMinIndex(Arrays.copyOfRange(a, i, a.length)) + i);
}
}
public static int FindMinIndex(int[] a) {
int i, min, minIndex = 0;
min = a[0];
for (i = 1; i < a.length; i++) {
if (a[i] < min) {
min = a[i];
minIndex = i;
}
}
return minIndex;
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
插入排序
package com.immunize.December.sort;
public class Insert {
public static void main(String[] args) {
// 生成一個隨機的數組
int[] a = Generate(100, 10);
// 對這個數組進行打印
System.out.println("原始數組:");
Print(a);
System.out.println("排序後的數組");
insertSort(a);
// SimpleSelectSort2(a);
Print(a);
}
// 插入排序
public static void insertSort(int[] a) {
int i, j, tmp;
// 遍歷
// i從1-末尾
for (i = 1; i < a.length; i++) {
// 當前值tmp
tmp = a[i];
// 前一個值的索引
j = i - 1;
// 當前值與每一個在其之前的數比較
while (tmp < a[j]) {
// 前值較大的話則需要往後移
a[j + 1] = a[j];
j--;
// 移動的上限是第一個值
if (j == -1) {
break;
}
}
// 跳出循環,當前值賦值到空出來的那個位置
a[j + 1] = tmp;
}
}
// Print函數
public static void Print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
break;
}
System.out.print(arr[i] + ",");
}
System.out.print("]");
System.out.println();
}
// 隨機生成n個數字,組成隨機數組函數Generate函數
public static int[] Generate(int max, int length) {
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (Math.random() * max);
}
return arr;
}
// Swap函數
public static void Swap(int[] arr, int i, int j) {
int tmp = 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
基數排序
package com.immunize.Arithmetic;
/**
* 基數排序法
*
* @author Mr IMMUNIZE
*
*/
public class RadixSort {
public static void main(String[] args) {
int[] data = { 73, 22, 93, 43, 55, 14, 28, 65, 39, 81 };
int[][] temp = new int[10][10];
int[] order = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int i, j, k, n, lsd;
k = 0;
n = 1;
System.out.println("排序前:");
Print(data);
System.out.println();
while (n <= 10) {
for (i = 0; i < 10; i++) {
// 拿到個位數數字
lsd = ((data[i] / n) % 10);
// 將該數據存放在對應的列上,21就放在第一列,89就放在第9列
temp[lsd][order[lsd]] = data[i];
// order[lsd]表示行數,行數遞增
order[lsd]++;
}
for (i = 0; i < 10; i++) {
// 重新排列,先列後行
if (order[i] != 0) {
// 先列再行,每一行只有一個數據,每一列的數據按照行序排列
for (j = 0; j < order[i]; j++) {
data[k] = temp[i][j];
k++;
}
}
order[i] = 0;
}
n *= 10;
k = 0;
}
System.out.println("排序後:");
Print(data);
}
public static void Print(int[] number) {
for (int i = 0; i < number.length; i++) {
System.out.print(number[i] + " ");
}
}
}
基數排序代碼未重寫,是直接取自我之前20191015的博客。
結語
至此,十大排序除了歸併排序其餘的都已經附上重寫代碼,而歸併排序實際上是Java中Arrays的sort方法的本質,我們明天給予說明。