package com.pamc.sort;
import java.util.Arrays;
public class SortTest {
static int[] arrays = {3, 5, 15, 2, 26, 4, 19, 27, 36, 44, 38, 47, 48, 50};
static int[] arrays2 = {8, 9, 1, 6, 7, 3, 0, 5, 2, 4};
static int[] arrays3 = {1,2,5,4,3};
/**
* 冒泡排序
* 算法: 1 比較相鄰的元素。如果第一個比第二個大,就交換它們兩個;
* 2 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數;
* 3 針對所有的元素重複以上的步驟,除了最後一個;
* 4 重複步驟1~3,直到排序完成。
* <p>
* 穩定性: 穩定
* 時間複雜度:最佳情況:T(n) = O(n) 最差情況:T(n) = O(n2) 平均情況:T(n) = O(n2)
* 空間複雜度:0(1)
*
* @param arrays
* @return
*/
public static int[] bubbleSort(int[] arrays) {
if (arrays == null || arrays.length < 2) {
return arrays;
}
for (int i = 0; i < arrays.length; i++) {
//循環次數,1 內循環比外循環少一次 2 每次內循環結束,冒泡出去的i元素都是最大/最小值,不需要在比較交換。
for (int j = 0; j < arrays.length - 1 - i; j++) {
int a = arrays[j];
int b = arrays[j + 1];
if (a < b) {
int c = a;
arrays[j] = b;
arrays[j + 1] = c;
}
}
}
return arrays;
}
/**
* 選擇排序
* 初始狀態:1 無序區爲R[1..n],有序區爲空;
* 2 第i趟排序(i=1,2,3…n-1)開始時,當前有序區和無序區分別爲R[1..i-1]和R(i..n)。
* 3 該趟排序從當前無序區中-選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,使R[1..i]和R[i+1..n)分別變爲記錄個數增加1個的新有序區和記錄個數減少1個的新無序區;
* 4 n-1趟結束,數組有序化了。
* 簡單描述:數組長度n,從數組第1個元素開始不斷和後面的元素進行比較,找出最小記錄進行替換。直到n-1次循環比較結束
* <p>
* 穩定性: 不穩定
* 時間複雜度:最佳情況:T(n) = O(n^2) 最差情況:T(n) = O(n^2) 平均情況:T(n) = O(n^2)
* 空間複雜度:0(1)
*
* @param arrays
* @return
*/
public static int[] selectionSort(int[] arrays) {
if (arrays == null || arrays.length < 2) {
return arrays;
}
for (int i = 0; i < arrays.length; i++) {
int index = i;
for (int j = i + 1; j < arrays.length; j++) {
if (arrays[j] < arrays[i]) {
index = j;
}
}
//不能直接arrays[i] - arrays[index],有可能i = index。
int a = arrays[i];
int b = arrays[index];
a = a + b;
arrays[i] = a - b;
arrays[index] = a - b;
}
return arrays;
}
/**
* 插入排序
* <p>
* 算法: 1 從第一個元素開始,該元素可以認爲已經被排序;
* 2 取出下一個元素,在已經排序的元素序列中從後向前掃描。如果該元素(已排序)大於新元素,將該元素移到下一位置;
* 3 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置;將新元素插入到該位置後;
* 4 重複步驟2~5。
* 和選擇排序很像,不過是和前面的元素比較,然後插入到正確的位置。正確的位置:大於該位置前的元素,小於等於該位置後的元素。
* <p>
* 穩定性:穩定
* 時間最佳情況:T(n) = O(n) 最壞情況:T(n) = O(n^2) 平均情況:T(n) = O(n^2)
* 空間複雜度:0(1)
*
* @param arrays
* @return
*/
public static int[] insertionSort(int[] arrays) {
if (arrays == null || arrays.length < 2) {
return arrays;
}
for (int i = 0; i < arrays.length - 1; i++) {
int current = arrays[i + 1];
int preIndex = i;
while (preIndex > 0 && current < arrays[preIndex]) {
arrays[preIndex + 1] = arrays[preIndex];
preIndex--;
}
arrays[preIndex + 1] = current;
}
return arrays;
}
/**
* 希爾排序
* 希爾排序是把記錄按下表的一定增量(gap)分組,
* 對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止
* <p>
* 穩定性: 不穩定
* 時間複雜度最佳情況:T(n) = O(nlog^2 n) 最壞情況:T(n) = O(nlog^2 n) 平均情況:T(n) =O(nlog^2n)
* 空間複雜度:0(1)
*
* @param array
* @return
*/
public static int[] hillSort(int[] array) {
int len = array.length;
int temp, gap = len / 2;
printArrays(array);
while (gap > 0) {
System.out.println("-------------");
for (int i = gap; i < len; i++) {
// 1 根據gap分組,只需要一次循環
// 2 preIndex是從0到len-gap-1
// 3 i 從 gap到len-1; preIndex:0 i:gap; preIndex:1 i:gap+1; ...... ; preIndex:len-gap-1 i:len-1
// 4 所以每個array[i]和array[preIndex]間隔gap,也就是array[i]和array[preIndex]一定是按照gap進行分組的同一分組內的數據
temp = array[i];
int preIndex = i - gap;
System.out.println("i:" + i);
System.out.println("preindex:" + preIndex);
System.out.println("grap:" + gap);
while (preIndex >= 0 && array[preIndex] > temp) {
array[preIndex + gap] = array[preIndex];
preIndex -= gap;
}
array[preIndex + gap] = temp;
printArrays(array);
}
gap /= 2;
}
return array;
}
/**
* 合併排序
* 算法: 1 把長度爲n的輸入序列分成兩個長度爲n/2的子序列;
* 2 對這兩個子序列分別採用歸併排序;
* 3 不斷執行1,2步驟,直到子序列長度 n<2。將兩個排序好的子序列合併成一個最終的排序序列。
* <p>
* 穩定性: 不穩定
* 時間複雜度:最佳情況:T(n) = O(n) 最差情況:T(n) = O(nlogn) 平均情況:T(n) = O(nlogn)
* 空間複雜度: 0(n)
*
* @param arrays
* @return
*/
public static int[] mergeSort(int[] arrays) {
if (arrays == null || arrays.length < 2) {
return arrays;
}
int mid = arrays.length / 2;
int[] a = Arrays.copyOfRange(arrays, 0, mid);
int[] b = Arrays.copyOfRange(arrays, mid, arrays.length);
return merge(mergeSort(a), mergeSort(b));
}
/**
* 兩個有序數組合並,a,b數組一定是已經有序的。
*
* @param a
* @param b
* @return
*/
protected static int[] merge(int[] a, int[] b) {
int[] mergeArrays = new int[a.length + b.length];
for (int index = 0, ai = 0, bi = 0; index < mergeArrays.length; index++) {
//升序 ai判斷在前面,降序 bi放前面,判斷用>=不用>
if (ai >= a.length) {
// ai數組已經都比較完了,出現在b.length>a.length,這時候把b的剩餘內容有序的賦值給mergeArrays。
mergeArrays[index] = b[bi++];
} else if (bi >= b.length) {
// bi數組已經都比較完了,出現在a.length>b.length,這時候把a的剩餘內容有序的賦值給mergeArrays。
mergeArrays[index] = a[ai++];
} else if (a[ai] > b[bi]) {
mergeArrays[index] = b[bi++];
} else {
mergeArrays[index] = a[ai++];
}
}
return mergeArrays;
}
/**
* 快速排序方法
*
* 算法: 1 從數列中挑出一個元素,稱爲 “基準”(pivot),一般取數組大小範圍的隨機數;
* 2 定義一個分區中間數smallIndex
* 3 重新排序數列,所有元素比基準值小的擺放在smallIndex前面,所有元素比基準值大的擺在smallIndex的後面(相同的數可以到任一邊)。在這個分區退出之後,
* a[smallIndex]前面的數一定小於或等於a[smallIndex],a[smallIndex]後面的數一定大於a[smallIndex],
* 這時a[smallIndex]的排序位置就是確定的。這個稱爲分區(partition)操作;
* 4 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
* 5 當數組的start == end 時,即遞歸到最後一個數,退出遞歸。這時smallIndex == start == end
*
* @param array
* @param start
* @param end
* @return
*/
public static int[] QuickSort(int[] array, int start, int end) {
System.out.println("QuickSort "+"start:"+start+" end:"+end);
if (array.length < 1 || start < 0 || end >= array.length || start > end){
return null;
}
int smallIndex = partition(array, start, end);
System.out.println("返回 smallIndex:"+smallIndex);
//當start == end 時,即遞歸到最後一個數,退出遞歸。這時smallIndex == start == end
if (smallIndex > start){
System.out.println("---------------");
System.out.println("start 新的遞歸"+"start:"+start+" smallIndex:"+smallIndex);
QuickSort(array, start, smallIndex - 1);
}
if (smallIndex < end){
System.out.println("---------------");
System.out.println("end 新的遞歸"+" end:"+end+" smallIndex:"+smallIndex);
QuickSort(array, smallIndex + 1, end);
}
return array;
}
/**
* 快速排序算法——partition
* 算法: 1 選擇 取start 到 end之間的隨機數爲基數 pivot
* 2 將a[pivot]和a[end]進行替換,方便進行比較
* 3 將數組內小於等於a[pivot]的數放在 smallIndex 下標前面。比a[pivot]大的數放到smallIndex後面。通過兩個下標的數替換完成swap()
* 4 排序完成後a[smallIndex]前面的數一定小於或等於a[smallIndex],a[smallIndex]後面的數一定大於a[smallIndex]。
* 這樣a[smallIndex]的排序位置就固定了。
* @param array
* @param start
* @param end
* @return
*/
protected static int partition(int[] array, int start, int end) {
// 基數,取start 到 end之間的隨機數
int pivot = (int) (start + Math.random() * (end - start + 1));
// 大於privot的個數
int smallIndex = start - 1;
System.out.println("start:"+start+" end:"+end+" smallIndex:"+smallIndex+" pivot:"+pivot+" arrays:");
printArrays(Arrays.copyOfRange(array,start,end+1));
swap(array, pivot, end);
System.out.println("替換:");
printArrays(Arrays.copyOfRange(array,start,end+1));
for (int i = start; i <= end; i++) {
if (array[i] <= array[end]) {
smallIndex++;
System.out.println("i:"+i+" smallIndex:"+smallIndex);
if (i > smallIndex) {
//a[i] < a[smallIndex]。當a[i] > array[end]時 a[smallIndex+1] > array[end]。
// 所以array[i] <= array[end]且i > smallIndex時 array[i] <= a[smallIndex] 。即將array[i]和a[smallIndex]替換
// smallIndex從-1開始,如果完全順序i=smallIndex,否則i > smallIndex。
System.out.println("arrays:");
swap(array, i, smallIndex);
printArrays(Arrays.copyOfRange(array,start,end+1));
}
}
}
return smallIndex;
}
/**
* 交換數組內兩個元素
*
* @param array
* @param i
* @param j
*/
protected static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void printArrays(int[] arrays) {
int i = 0;
for (int a : arrays) {
if (i > 0){
System.out.print(",");
}
System.out.print(a);
i++;
}
System.out.println();
}
public static void main(String[] args) {
printArrays(QuickSort(arrays, 0, arrays.length - 1));
}
}
後續待更新。。。。。
十大排序算法原理和代碼示例(java)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.