public class SortTest {
public static int countGB = 0;
public static void main(String[] args) {
int[] array = {1, 12, 8, 9, 6, 8, 4, 7, 2, 3, 5, 4, 6, 0};
long startTime = System.currentTimeMillis(); //獲取開始時間
// int[] array1 = MP(array);//冒泡排序
// int[] array1 = XZ(array);//選擇排序
// int[] array1 = CR(array);//插入排序
// int[] array1 = XE(array);//希爾排序
// int[] array1 = GB(array);//歸併排序
// System.out.println(countGB);//歸併排序循環次數 54 最佳情況:T(n) = O(n) 最差情況:T(n) = O(nlogn) 平均情況:T(n) = O(nlogn)
// KS(array, 0, array.length - 1);//快速排序
// System.out.println(countGB);//快速排序循環次數 46 最佳情況:T(n) = O(nlogn) 最差情況:T(n) = O(n2) 平均情況:T(n) = O(nlogn)
// for (int i = 0; i < array.length; i++) {
// System.out.print(array[i] + " ");
// }
// int[] array1 = D(array);//堆排序
// System.out.println(countGB);//堆排序循環次數 49 最佳情況:T(n) = O(nlogn) 最差情況:T(n) = O(nlogn) 平均情況:T(n) = O(nlogn)
// int[] array1 = JS(array);//計數排序
// ArrayList<Integer> arrayList = new ArrayList<Integer>();
// for (int i = 0; i < array.length; i++) {
// arrayList.add(array[i]);
// }
// ArrayList array1 = T(arrayList, 10);//桶排序 556次,速度太慢了,循環次數太多了 最佳情況:T(n) = O(n+k) 最差情況:T(n) = O(n+k) 平均情況:T(n) = O(n2) k是桶的個數,選bucketSize也很重要,對於不同數組選取不一樣的bucketSize區別很大
// for (int i = 0; i < array1.size(); i++) {
// System.out.print(array1.get(i) + " ");
// }
// System.out.println();
// System.out.println(countGB);
// int[] array1=basket(array);//桶排序
// int[] array1 = radix(array);//基數排序
int[] array1 = RadixSort(array);//基數排序
long endTime = System.currentTimeMillis(); //獲取結束時間
System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
for (int i = 0; i < array1.length; i++) {
System.out.print(array1[i] + " ");
}
}
/**
* 冒泡排序
*
* @param arr
* @return
*/
public static int[] MP(int[] arr) {
if (arr.length <= 1) {
return arr;
}
int count = 0;
for (int i = 0; i < arr.length; i++) {
int flag = 0;
for (int j = 0; j < arr.length - i - 1; j++) {
count++;
if (arr[j] > arr[j + 1]) {
int temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
flag++;
}
}
if (flag == 0) {
break;
}
}
System.out.println(count);//91 最佳情況:T(n) = O(n) 最差情況:T(n) = O(n2) 平均情況:T(n) = O(n2)
return arr;
}
/**
* 選擇排序
*
* @param arr
* @return
*/
public static int[] XZ(int[] arr) {
if (arr.length <= 1) {
return arr;
}
long startTime = System.currentTimeMillis(); //獲取開始時間
// /**
// * TODO:這裏使用的方法需要一直替換數組內的值,會破壞原來的數組,但是沒關係
// */
int count = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
count++;
if (arr[i] > arr[j]) {
int change = arr[j];
arr[j] = arr[i];
arr[i] = change;
}
}
}
// /**
// * TODO:這裏使用的方法除了將最小值和未排序列的第一個值作交換外,不破壞未排序序列的順序
// */
// for(int i=0;i<arr.length;i++){
// int minIndex=i;
// for(int j=i;j<arr.length;j++){
// count++;
// if(arr[minIndex]>arr[j]){
// minIndex=j;
// }
// }
// int temp=arr[minIndex];
// arr[minIndex]=arr[i];
// arr[i]=temp;
// }
long endTime = System.currentTimeMillis(); //獲取結束時間
System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
System.out.println(count);//1、91 2、105 最佳情況:T(n) = O(n2) 最差情況:T(n) = O(n2) 平均情況:T(n) = O(n2)
return arr;
}
/**
* 插入排序
*
* @param arr
* @return
*/
public static int[] CR(int[] arr) {
long startTime = System.currentTimeMillis(); //獲取開始時間
if (arr.length <= 1) {
return arr;
}
int count = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = i - 1; j >= 0 && arr[j + 1] < arr[j]; j--) {//往後移動,只要i+1的這個值比前面已經排好序的小,就把前面的值往後移動一個位置(原理:因爲前面已經排好序了,只要找到第一個比自己小的那個位置放到那個後面就行了)
count++;
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
long endTime = System.currentTimeMillis(); //獲取結束時間
System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
System.out.println(count);//61 最佳情況:T(n) = O(n) 最壞情況:T(n) = O(n2) 平均情況:T(n) = O(n2)
return arr;
}
/**
* 希爾排序
* 插入排序升級版
*
* @param arr
* @return
*/
public static int[] XE(int[] arr) {
long startTime = System.currentTimeMillis(); //獲取開始時間
if (arr.length <= 1) {
return arr;
}
int gap = arr.length / 2;
int count = 0;
while (gap > 0) {
for (int i = gap; i < arr.length; i++) {
for (int j = i - gap; j >= 0 && arr[j + gap] < arr[j]; j = j - gap) {
count++;
int temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(" " + arr[i]);
}
System.out.println();
gap /= 2;
}
long endTime = System.currentTimeMillis(); //獲取結束時間
System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
System.out.println(count);//19 最佳情況:T(n) = O(nlog2 n) 最壞情況:T(n) = O(nlog2 n) 平均情況:T(n) =O(nlog2n)
return arr;
}
/**
* 歸併排序
*
* @param arr
* @return
*/
public static int[] GB(int[] arr) {
if (arr.length <= 1) {
return arr;
}
return merge(GB(Arrays.copyOfRange(arr, 0, arr.length / 2)), GB(Arrays.copyOfRange(arr, arr.length / 2, arr.length)));
}
/**
* 合併左右數組
*
* @param left
* @param right
* @return
*/
public static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
for (int index = 0, i = 0, j = 0; index < result.length; index++) {
countGB++;
if (i >= left.length) {
result[index] = right[j++];// <=> result[index]=right[j];j++;
} else if (j >= right.length) {
result[index] = left[i++];
} else if (left[i] > right[j]) {
result[index] = right[j++];
} else {
result[index] = left[i++];
}
}
return result;
}
/**
* 快速排序
*
* @param arr
* @return
*/
public static void KS(int[] arr, int left, int right) {
if (arr.length <= 1) return;
if (left > right) {
return;
}
int i = left, j = right, key = arr[left];
while (i < j) {
while (i < j && arr[j] > key) {//從右往左找第一個比key值小的數,找到後退出循環,這樣保留j的值,這個arr[j]就是第一個小於key的值
countGB++;
j--;
}
while (i < j && arr[i] <= key) {//從左往右找第一個比key值大的數,找到後退出循環,保留i的值,用來替換從右邊找的第一個小於key的值,這樣兩個對調之後相當於以key爲中心,左邊爲小於key的值,右邊爲大於key的值
countGB++;
i++;
}
if (i < j) {//對調,對調後arr[i]爲小於key的值,arr[j]爲大於key的值
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
arr[left] = arr[i];//將key值與小於key的值對調,這樣key的左邊就是小於key的,右邊是小於key的
arr[i] = key;//現在第i個爲key了,後面只需要對key的左右兩邊進行快排就可以了
// System.out.println("i:"+i);
KS(arr, left, i - 1);// 對key左邊的數快排
KS(arr, i + 1, right);// 對key右邊的數快排
}
/**
* 堆排序
*
* @param arr
* @return
*/
public static int[] D(int[] arr) {
if (arr.length <= 1) return arr;
for (int i = 0; i < arr.length; i++) {
buildMaxD(arr, arr.length - i);//從最後一個開始,每次建堆把最後一個位置存放最大值達到排序的目的
int temp = arr[0];
arr[0] = arr[arr.length - i - 1];
arr[arr.length - i - 1] = temp;
}
return arr;
}
/**
* 建堆
*
* @param arr
* @param currentRootNode 當前父節點位置(數組小標)
* @param size 節點總數
*/
public static void buildD(int[] arr, int currentRootNode, int size) {
// System.out.print(currentRootNode + ":" + size);
if (currentRootNode < size) {
//左子樹和右字數的位置
int leftChildNode = 2 * currentRootNode + 1;
int rightChildNode = 2 * currentRootNode + 2;
//假設節點是最大值節點的位置,max用來記錄最大值的位置
int max = currentRootNode;
if (leftChildNode < size) {
if (arr[leftChildNode] > arr[max]) {//如果左節點大於當前記錄的值,將記錄的位置換成當前位置
max = leftChildNode;
}
}
if (rightChildNode < size) {
if (arr[rightChildNode] > arr[max]) {//如果右節點大於當前記錄的值,將記錄的位置換成當前位置
max = rightChildNode;
}
}
if (max != currentRootNode) {//將當前父節點的位置上的值,與記錄的最大值位置的值進行對調,這樣當前父節點位置的值就大於子節點了
int temp = arr[currentRootNode];
arr[currentRootNode] = arr[max];
arr[max] = temp;
}
// System.out.println(":" + max);
}
}
/**
* 構建最大堆
*
* @param arr
* @param size
*/
public static void buildMaxD(int[] arr, int size) {
// 從數組的尾部開始,直到第一個元素(角標爲0)
for (int i = size / 2 - 1; i >= 0; i--) {//這裏初始值爲啥是size/2-1呢,因爲要從第一個非葉子節點開始查起,最後一個葉子節點如果是左子樹,它的值爲2x+1,x爲父節點位置,size-1=2x+1 =>x=size/2 -1
//最後一個葉子節點如果是右子樹,它的值爲2x+2,x爲父節點位置,size-1=2x+2 =>x=size/2 -3/2 所以取x=size/2-1臨界值,能夠保證第一個父節點不會漏掉,也能避免多餘的循環
buildD(arr, i, size);
countGB++;
}
}
/**
* 計數排序
*
* @param arr
* @return
*/
public static int[] JS(int[] arr) {
if (arr.length <= 1) return arr;
int bias, min = arr[0], max = arr[0];
int count = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
if (arr[i] < min) {
min = arr[i];
}
count++;
}
bias = 0 - min;
int[] bucket = new int[max - min + 1];
Arrays.fill(bucket, 0);
for (int i = 0; i < arr.length; i++) {
bucket[arr[i] + bias]++;
count++;
}
// int index=0,k=0;
// while (index<arr.length){
// if(bucket[k]!=0){
// arr[index]=k-bias;
// bucket[k]--;
// index++;
// }else {
// k++;
// }
// count++;
// }
for (int i = 0, j = 0; i < bucket.length; i++) {
while (bucket[i] > 0) {
arr[j] = i - bias;
j++;
bucket[i]--;
count++;
}
}
System.out.println(count);//計數排序循環次數 1、53 2、41 T(n) = O(n+k) 最差情況:T(n) = O(n+k) 平均情況:T(n) = O(n+k)
return arr;
}
/**
* 桶排序
* 計數排序的升級版
* 桶排序是計數排序的變種,它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的確定。把計數排序中相鄰的m個”小桶”放到一個”大桶”中,在分完桶後,對每個桶進行排序(一般用快排),然後合併成最後的結果。
*
* @param arr
* @param bucketSize 人爲設置一個BucketSize,作爲每個桶所能放置多少個不同數值(例如當BucketSize==5時,該桶可以存放{1,2,3,4,5}這幾種數字,但是容量不限,即可以存放100個3);
* @return
*/
public static ArrayList<Integer> T(ArrayList<Integer> arr, int bucketSize) {
if (arr == null || arr.size() <= 1)
return arr;
int max = arr.get(0), min = arr.get(0);
for (int i = 1; i < arr.size(); i++) {
countGB++;
if (max < arr.get(i)) {
max = arr.get(i);
}
if (min > arr.get(i)) {
min = arr.get(i);
}
}
int bucketCount = (max - min) / bucketSize + 1;
ArrayList<ArrayList> bucketArr = new ArrayList(bucketCount);
ArrayList resultArr = new ArrayList();
for (int i = 0; i < bucketCount; i++) {
countGB++;
bucketArr.add(new ArrayList<>());
}
for (int i = 0; i < arr.size(); i++) {
countGB++;
bucketArr.get((arr.get(i) - min) / bucketSize).add(arr.get(i));
}
for (int i = 0; i < bucketCount; i++) {
if (bucketSize == 1) {
for (int j = 0; j < bucketArr.get(i).size(); j++) {
countGB++;
resultArr.add(bucketArr.get(i).get(j));
}
} else {
if (bucketCount == 1) {
bucketSize--;
}
ArrayList temp = T(bucketArr.get(i), bucketSize);
for (int j = 0; j < temp.size(); j++) {
countGB++;
resultArr.add(temp.get(j));
}
}
}
return resultArr;
}
/**
* 進階版桶排序,通過整數的位數來計算 來源於百度百科
*
* @param data
* @return
*/
public static int[] basket(int data[])//data爲待排序數組
{
if (data.length < 2) {
return data;
}
int count = 0;
int n = data.length;
int bask[][] = new int[10][n];
int index[] = new int[10];
int max = Integer.toString(data[0]).length();
for (int i = 0; i < n; i++) {
count++;
max = max > (Integer.toString(data[i]).length()) ? max : (Integer.toString(data[i]).length());
}
String str;
for (int i = max - 1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
str = "";
if (Integer.toString(data[j]).length() < max) {
for (int k = 0; k < max - Integer.toString(data[j]).length(); k++) {
str += "0";
count++;
}
} else {
count++;
}
str += Integer.toString(data[j]);
bask[str.charAt(i) - '0'][index[str.charAt(i) - '0']++] = data[j];
}
int pos = 0;
for (int j = 0; j < 10; j++) {
for (int k = 0; k < index[j]; k++) {
count++;
data[pos++] = bask[j][k];
}
}
for (int x = 0; x < 10; x++) {
count++;
index[x] = 0;
}
}
System.out.println(count);//循環次數 90 ,當數組內的值最大最小值之差變大時循環次數會增加很多很多,當不同位數的值比較多時,循環次數增加,比如 1 10 100 1000
return data;
}
/**
* 基數排序
* 最佳情況:T(n) = O(n * k) 最差情況:T(n) = O(n * k) 平均情況:T(n) = O(n * k) 來源於百度百科
*
* @param number
* @return
*/
public static int[] radix(int[] number) {
if (number.length < 2) {
return number;
}
int count = 0;
int d = 0;//d表示最大的數有多少位
for (int i = 0; i < number.length; i++) {
count++;
d = d > Integer.toString(number[i]).length() ? d : Integer.toString(number[i]).length();
}
int n = 1;
int m = 1; //控制鍵值排序依據在哪一位
int[][] temp = new int[10][number.length]; //數組的第一維表示可能的餘數0-9 第二維的數組下標表示這個餘數重複的個數
int[] order = new int[10]; //數組orderp[i]用來表示該位是i的數的個數
while (m <= d) {
for (int i = 0; i < number.length; i++) {
count++;
int lsd = ((number[i] / n) % 10);//除以位數值(1 100 1000)再對10取餘得到第m位的個位數的值
temp[lsd][order[lsd]] = number[i];//表示當前餘數LSD第 order[lsd]重複的那個數是number[i]
order[lsd]++;//當前位數的個位數的值的個數 (比如129 當m=2時,當前位數爲2,當前位數的個位數是(129/10)%10等於2 如果還有一個321,那麼order[2]++的值就是兩個了
}
for (int i = 0, k = 0; i < 10; i++) {
if (order[i] != 0) {
for (int j = 0; j < order[i]; j++) {
count++;
number[k] = temp[i][j];
k++;
}
} else {
count++;
}
order[i] = 0;
}
n *= 10;
m++;
}
System.out.println(count);//循環次數78次
return number;
}
/**
* 基數排序
*
* @param array
* @return
*/
public static int[] RadixSort(int[] array) {
if (array == null || array.length < 2)
return array;
int count = 0;
// 1.先算出最大數的位數;
int maxDigit = 0;
for (int i = 0; i < array.length; i++) {
count++;
maxDigit = maxDigit > Integer.toString(array[i]).length() ? maxDigit : Integer.toString(array[i]).length();
}
int mod = 10, div = 1;
ArrayList<ArrayList<Integer>> bucketList = new ArrayList<ArrayList<Integer>>();
for (int i = 0; i < 10; i++) {
count++;
bucketList.add(new ArrayList<Integer>());
}
for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
for (int j = 0; j < array.length; j++) {
count++;
int num = (array[j] % mod) / div;//獲取第maxDigit位的個位數
bucketList.get(num).add(array[j]);
}
int index = 0;
for (int j = 0; j < bucketList.size(); j++) {
for (int k = 0; k < bucketList.get(j).size(); k++) {
count++;
array[index++] = bucketList.get(j).get(k);
}
bucketList.get(j).clear();
}
}
System.out.println(count);//循環次數80
return array;
}
}
客服測試客服
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.