日常操作中常見的排序方法有:冒泡排序、快速排序、選擇排序、插入排序、希爾排序,甚至還有基數排序、雞尾酒排序、桶排序、鴿巢排序、歸並排序等。
以下常見算法的定義
- 1. 插入排序:插入排序基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據,算法適用於少量數據的排序,時間復雜度為O(n^2)。是穩定的排序方法。插入排序的基本思想是:每步將一個待排序的紀錄,按其關鍵碼值的大小插入前面已經排序的文件中適當位置上,直到全部插入完為止。
- 2. 選擇排序:選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工作原理是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完。 選擇排序是不穩定的排序方法。
- 3. 冒泡排序:冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端。
- 4. 快速排序:快速排序(Quicksort)是對冒泡排序的一種改進。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然后再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
- 5. 歸並排序:歸並排序是建立在歸並操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為二路歸並。
- 6. 希爾排序:希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本。希爾排序是非穩定排序算法。希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。
一、冒泡排序
冒泡排序是一種簡單的排序算法。它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。
/** * 冒泡法排序 * 比較相鄰的元素。如果第一個比第二個小,就交換他們兩個。 * 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最后一對。在這一點,最后的元素應該會是最小的數。 * 針對所有的元素重復以上的步驟,除了最后一個。 * 持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。 * * @param numbers * 需要排序的整型數組 */ public static void bubbleSort01(int[] numbers) { int temp; // 記錄臨時中間值 int size = numbers.length; // 數組大小 for (int i = 0; i < size - 1; i++) { for (int j = i + 1; j < size; j++) { if (numbers[i] < numbers[j]) { // 交換兩數的位置
temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; } } } }
注意:以上不知是什么排序,將基准位置的元素和后面的元素進行比較,如果基准位置值比后面元素小,則交換位置,交換后的元素為新的基准元素。以下才是真正的冒泡排序。
public static void bubbleSort(int[] a) { int temp; int size = a.length; for(int i=1; i<size; i++) { for(int j=0; j<size-i; j++) { if(a[j] < a[j+1]) { temp = a[j]; a[j]=a[j+1]; a[j+1]=temp; } } for(int aa : a) System.out.print(aa+","); System.out.println(); } }
二、快速排序
快速排序使用分治法策略來把一個序列分為兩個子序列。
/** * 快速排序 * * 從數列中挑出一個元素,稱為“基准” * 重新排序數列,所有元素比基准值小的擺放在基准前面,所有元素比基准值大的擺在基准的后面(相同的數可以到任一邊)。在這個分割之后, * 該基准是它的最后位置。這個稱為分割(partition)操作。 * 遞歸地把小於基准值元素的子數列和大於基准值元素的子數列排序。 * * @param numbers * @param start * @param end */ public static void quickSort(int[] numbers, int start, int end) { if (start < end) { int base = numbers[start]; // 選定的基准值(第一個數值作為基准值) int temp; // 記錄臨時中間值 int i = start, j = end; do { while ((numbers[i] < base) && (i < end)) i++; while ((numbers[j] > base) && (j > start)) j--; if (i <= j) { temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; i++; j--; } } while (i <= j); if (start < j) quickSort(numbers, start, j); if (end > i) quickSort(numbers, i, end); } }
如下為完全符合快速排序定義的算法:
public static void quickSort01(int[] a, int start, int end) { if(start >= end) return; int i = start; int j = end; int base = a[start]; while(i != j) { while(a[j] >= base && j > i) j--; while(a[i] <= base && i < j) i++; if(i < j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } } a[start] = a[i]; a[i] = base; te(a, start, i - 1); te(a, i + 1, end); }
三、選擇排序
選擇排序是一種簡單直觀的排序方法,每次尋找序列中的最小值,然后放在最末尾的位置。
/** * 選擇排序 * 在未排序序列中找到最小元素,存放到排序序列的起始位置 * 再從剩余未排序元素中繼續尋找最小元素,然后放到排序序列起始位置。 * 以此類推,直到所有元素均排序完畢。 * * @param numbers */ public static void selectSort(int[] numbers) { int size = numbers.length; int temp; for (int i = 0; i < size; i++) { int k = i; for (int j = size - 1; j >i; j--) { if (numbers[j] < numbers[k]) { k = j; } } temp = numbers[i]; numbers[i] = numbers[k]; numbers[k] = temp; } }
四、插入排序
插入排序的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從后向前掃描,找到相應位置並插入。其具體步驟參見代碼及注釋。
/** * 插入排序 * * 從第一個元素開始,該元素可以認為已經被排序 * 取出下一個元素,在已經排序的元素序列中從后向前掃描 * 如果該元素(已排序)大於新元素,將該元素移到下一位置 * 重復步驟3,直到找到已排序的元素小於或者等於新元素的位置 * 將新元素插入到該位置中 * 重復步驟2 * @param numbers */ public static void insertSort(int[] numbers) { int size = numbers.length, temp, j; for(int i=1; i<size; i++) { temp = numbers[i]; for(j = i; j > 0 && temp < numbers[j-1]; j--) numbers[j] = numbers[j-1]; numbers[j] = temp; } }
五、歸並排序
歸並排序是建立在歸並操作上的一種有效的排序算法,歸並是指將兩個已經排序的序列合並成一個序列的操作。
/** * 歸並排序 * * 申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合並后的序列 * 設定兩個指針,最初位置分別為兩個已經排序序列的起始位置 * 比較兩個指針所指向的元素,選擇相對小的元素放入到合並空間,並移動指針到下一位置 * 重復步驟3直到某一指針達到序列尾 * 將另一序列剩下的所有元素直接復制到合並序列尾 * * @param numbers */ public static void mergeSort(int[] numbers, int left, int right) { int t = 1;// 每組元素個數 int size = right - left + 1; while (t < size) { int s = t;// 本次循環每組元素個數 t = 2 * s; int i = left; while (i + (t - 1) < size) { merge(numbers, i, i + (s - 1), i + (t - 1)); i += t; } if (i + (s - 1) < right) merge(numbers, i, i + (s - 1), right); } }
/** * 歸並算法實現 * * @param data * @param p * @param q * @param r */ private static void merge(int[] data, int p, int q, int r) { int[] B = new int[data.length]; int s = p; int t = q + 1; int k = p; while (s <= q && t <= r) { if (data[s] <= data[t]) { B[k] = data[s]; s++; } else { B[k] = data[t]; t++; } k++; } if (s == q + 1) B[k++] = data[t++]; else B[k++] = data[s++]; for (int i = p; i <= r; i++) data[i] = B[i]; }
