八大內部排序以及穩定性
阿新 • • 發佈:2018-12-27
穩定性的定義:如果佇列中存在相等的兩個數字,如果數字在排序過程中不發生變化,則是穩定的排序,如果發生了變化則是不穩定的排序。
回憶的過程:以後看過,長時間沒寫了,從頭寫一遍,跟以前寫的比較比較看看自己有什麼改進。
初級菜鳥,如果問題望指出,多多溝通,有利於成長。
1. 交換排序:氣泡排序、快排排序。
(1) 冒泡思路:每次迴圈大的往下沉,每次迴圈迴圈的長度-1。swap方法為自定義方法交換在部落格最後面
(2) 快排思路:設定一個標誌位,從前面找比標誌位小的從後面找比標誌位大的,分治遞迴。<span style="font-size:18px;">/* * 氣泡排序 交換排序顧名思義,假如某個位置的資料是確定的,尋找相應條件的資料進行交換, 例如:陣列{ 49, 38, 65, 97, 76, 13, * 27, 49 }。我採用從小到大的排序方式 假如49就是已經確定位置的資料,從資料38開始遍歷,38小於49,交換位置。以此類推。 * */ public static int[] bubbleSort(int arr[]) { int le = arr.length - 1; while (le >= 0) { int inter = arr[0]; int index = 0; for (int j = 1; j <= le; j++) { if (arr[j] < inter) /* * 對於穩定性的概念也不是絕對的,如果此處的條件是arr[j] <= inter * 那麼這個氣泡排序就是不穩定的排序,所有有的時候穩定是相對的跟自己定義的條件有關係的 */ swap(arr, index, j); else inter = arr[j]; index = j; } le--; } return arr; }</span>
<span style="font-size:18px;">public static void quickSort(int arr[], int from, int to) { if (from >= to) return; // 標誌位,將比標誌位小的放到某個數的前面,將比標誌位大的放到標誌位的後面,遞迴解決--分治法 int temp = arr[from]; // 每次交換的位置 int index = from; int start = from; int end = to; while (start < end) { // 從後往前找比標誌位元素小的, while (start < end && arr[end] >= temp) end--; if (arr[end] < temp) { arr[index] = arr[end]; index = end; } while (start < end && arr[start] < temp) start++; if (arr[start] > temp) { arr[index] = arr[start]; index = start; } } // 在最後一個交換的位置新增標誌位,標誌位可以將問題分解為兩個不同的問題 arr[index] = temp; quickSort(arr, from, index - 1); quickSort(arr, index + 1, to); }</span>
2. 插入排序:插入排序、希爾排序。
(1) 插入排序:設定一個標誌位,假設第一元素是排好序的,與第下一個元素進行比較,大與直接進行下一個,小於需要找到該元素插入的恰當的位置。
<span style="font-size:18px;">public static void insertSort(int arr[]) { int le = arr.length - 1; // 元素比較的位置 int start = 1; int temp = arr[0]; while (start <= le) { if (arr[start] < temp) { int index = start - 1; int inNum = arr[start]; /* * 移動元素: 38,49,,65, 76, 97,13, 27, 49 * 例如如果start在13位置,需要找到13的恰當的位置,與前一個元素(97)進行比較,如果前一個元素(97)>13, * 則將這個元素往後移動,找到13位置的過程也就是不斷的將元素往後推一個位置,如果小於則直接進行下一輪的迴圈,即start++ * ; */ while (index >= 0 && inNum <= arr[index]) { arr[index + 1] = arr[index]; index--; } if (index == -1) arr[0] = inNum; else arr[index + 1] = inNum; } else temp = arr[start]; start++; } }</span>
(2) 希爾排序:主要就是取步長,比較步長之間數字的大小
<span style="font-size:18px;"> public static void shellSort(int arr[]) {
/*
* 希爾本質上和插入排序是一樣的,但是它比較的不是相鄰元素的大小而是比較步長之間的元素的大小,說不太清楚,舉個例子: 陣列49, 38,
* 65, 97, 76, 13, 27, 49 。如果步長為3,則39,97,27一組之間比較,
* 38,76,49之間比較,等等。我自己理解哈:這樣做的好處可以把相對小的數前移,相對大的數後移,這樣就避免了插入排序中插入13的時候,
* 移動那麼多數。
*/
int step = arr.length / 2;
int le = arr.length - 1;
int m = 0;
// 元素比較的位置
while (step > 0) {
int temp = arr[0];
int start = step;
while (start <= le) {
temp = arr[start - step];
if (arr[start] < temp) {
int index = start - step;
int inNum = arr[start];
/*
* 移動元素: 38,49,,65, 76, 97,13, 27, 49
* 例如如果start在13位置,需要找到13的恰當的位置,與前一個元素(97)進行比較,如果前一個元素(97)>
* 13, 則將這個元素往後移動,找到13位置的過程也就是不斷的將元素往後推一個位置,如果小於則直接進行下一輪的迴圈,
* 即start++ ;
*/
while (index >= 0 && inNum <= arr[index]) {
arr[index + step] = arr[index];
index -= step;
}
arr[index + step] = inNum;
}
start++;
}
step--;
}
}</span>
3.選擇排序
(1) 選擇排序:每次迴圈選擇陣列中最小的或者最大的。
<span style="font-size:18px;">public static void selectSort(int arr[]) {
for (int i = 0; i < arr.length; i++) {
//每次迴圈之前I之前的元素是已經被排序好的,i之後是未排序的,假設當前元素I是最小的,在I之後去尋找比I小的。
int min = arr[i];
int index = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < min) {
min = arr[j];
index = j;
}
}
swap(arr, i, index);
}
}</span>
(2) 堆排序:構建大頂堆或者小頂堆,交換第一元素和最後元素,繼續構建堆的過程。
<span style="font-size:18px;">/*
* 從i = arr.length / 2
* -1(-1是因為陣列的下標從0開始的)一半元素開始進行操作的,所以首先要知道當前節點有一個節點還是有兩個節點 這個方法是完成構建小頂堆
*/
public static int[] heapSort(int arr[], int i, int le) {
while (i >= 0 && 2 * i + 1 <= le) {
// 右節點
int r = 2 * i + 2;
// 左節點
int l = 2 * i + 1;
int min = 0;
int minIndex = 0;
/*
* 判斷當前節點是有一個孩子節點還是兩個孩子節點,第一次(step=3)判斷的時候
* 當r=le時說明有兩個孩子節點,否則有個一個孩子節點,其他的次數(step=2,1,0)均有兩個節點
*/
if (r <= le) {
// 取孩子節點中最小的節點
if (arr[r] > arr[l]) {
min = arr[l];
minIndex = l;
} else {
min = arr[r];
minIndex = r;
}
// 判斷最小的節點和父節點大小,
if (min < arr[i]) {
swap(arr, i, minIndex);
/*
* 在交換之後,元素的位置發生變化了,在i位置的元素不需要做什麼,因為下一個進行操作的是i-1,依次往下進行,
* 它會自動的檢測到他的父節點是不是小於它的兩個子節點,但是它的子節點並不知道交換之後滿足不滿足這個要求,
* 所以需要檢查一下-ps:這個你按照陣列把堆畫出來,然後自己交換13和49的時候你就會發現了,父節點49子節點65,
* 27
*/
heapSort(arr, minIndex, le);
}
} else {
/*
* 當前節點只有一個孩子節點時,只有在第一次執行的時候可能發生,所以直接比較即可
*/
if (arr[i] > arr[l])
swap(arr, i, l);
}
i--;
}
// heapSortRemove(arr, 0, le);
return arr;
}
/*
* 小頂堆排序,每次將最小的交換到最後一個節點,切長度-1,然後在進行構建小頂堆
*/
public static int[] heapSortRemove(int arr[], int le) {
while (le >= 0) {
int temp = arr[0];
arr[0] = arr[le];
arr[le] = temp;
le--;
/*
* 呼叫heapSort方法時,因為它只換了最後一個元素和第一個元素,所以檢查第一元素即可
*/
heapSort(arr, 0, le);
}
return arr;
}</span>
注意:大頂堆在每一次交換的時候將最大的交換到最後一個位置,所以大頂堆的結果陣列是從小到大排列的。 小頂堆則是恰恰相反,從大到小。
4.歸併排序
思路:主要應用分治法,將問題分解成小的問題,進行排序,然後合併進行排序。
<span style="font-size:18px;">/*
* 將陣列分成兩部分,(0,3)、(4,7)-再分成兩部分(0,1)(2-3)等,直到(0,0)停止 ,之後合併(0,1),(0,3),(0,7)。
*/
public static void mergeSort(int arr[], int from, int to, int temp[]) {
if (from < to) {
int mid = (from + to) / 2;
mergeSort(arr, from, mid, temp);
mergeSort(arr, mid + 1, to, temp);
mergearray(arr, from, mid, to, temp);
}
}
/*
* 如果是兩個元素(0,1),將兩個元素兩個元素排序,,如果是4個(0,4)元素將四個元素排序,temp作為中間陣列,將排序的值,暫時儲存下來,
* 之後儲存到arr中。
*/
public static void mergearray(int arr[], int from, int mid, int to, int temp[]) {
int i = from;
int inter = mid + 1;
int k = 0;
while (from <= mid && inter <= to) {
if (arr[from] < arr[inter])
temp[k++] = arr[from++];
else
temp[k++] = arr[inter++];
}
while (from <= mid)
temp[k++] = arr[from++];
while (inter <= to)
temp[k++] = arr[inter++];
for (int j = 0; j < k; j++) {
arr[j + i] = temp[j];
}
}
</span>
5.交換方法swap
<span style="font-size:18px;">public static void swap(int arr[], int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}</span>
6.主函式
<span style="font-size:18px;">public static void main(String[] args) {
int arr[] = { 49, 38, 65, 97, 76, 13, 27, 49, 24 };
// 氣泡排序
// int a[] = bubbleSort(arr);
// 快排排序
// quickSort(arr, 0, a,rr.length - 1);
// 插入排序
// insertSort(arr);
// 希爾排序
// shellSort(arr);
// 選擇排序
// selectSort(arr);
// 堆排序
// arr = heapSort(arr, arr.length / 2 - 1, arr.length - 1);
// arr = heapSortRemove(arr, arr.length - 1);
// 歸併排序
int temp[] = new int[arr.length];
mergeSort(arr, 0, arr.length - 1, temp);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}</span>
6. 各個排序演算法的穩定性
轉載位置:http://www.cnblogs.com/pangxiaodong/archive/2011/08/19/2145260.html
基數排序我並沒有寫,這個我沒研究,有空會有後續的。