1. 程式人生 > >三種排序:快排,歸並,堆排

三種排序:快排,歸並,堆排

new swap 簡單 數組合並 col 最大 heapsort 堆排序 大神

轉自:http://www.cnblogs.com/LUO77/p/5798149.html

(一)快排

快排考的是最多次的。之前看大神寫的算法很簡單,思想也很好。就一直用他的思想去思考快排了。挖坑法。

拿走第一個元素作為標兵元素,即挖坑,然後從後面找一個比它小的填坑,然後又形成一個坑,再從前面找一個比標兵大的填坑,又形成一個坑。……最後一個坑填入標兵就好。

然後就是遞歸了。再在標兵左邊排序,右邊排序。

 1 void QSort(int* num, int start, int end) {
 2     if(num == NULL||start >= end)
3 return; 4 int tmp = num[start]; 5 int i = start, j = end; 6 while (i<j) { 7 while (i<j&&num[j]>tmp) { 8 j--; 9 } 10 if (i<j) 11 num[i++] = num[j]; 12 while (i<j&&num[i]<tmp) {
13 i++; 14 } 15 if (i<j) 16 num[j--] = num[i]; 17 } 18 num[i] = tmp; 19 QSort(num, start, i - 1); 20 QSort(num, i + 1, end); 21 }

歸並:

歸並的思想就是分治-組合。

先divide,然後merge。

divide的思想比較簡單,找到middle,再劃分A[start,,,,,middle],A[middle+1...end]

對於左邊在遞歸劃分,劃分直至只剩一個元素,然後再merge。merge的時候需要一個臨時數組。merge的時候是A[first...middle]和A[middle+1……end]合並。

對於右邊在遞歸劃分,劃分直至只剩一個元素,然後再merge。

左邊和右邊都有序了,然後再將兩個數組合並為一個數組。最後整個數組都有序了。(先處理左邊,再處理右邊)

 1 void merge(int* A, int start, int middle, int last, int *tmp) {
 2 
 3     int i1 = start, j1 = middle;
 4     int i2 = middle+1, j2 = last;
 5     int index = 0;
 6     while (i1<=j1&&i2<=j2) {
 7         if (A[i1]<=A[i2])
 8             tmp[index++] = A[i1++];
 9         else tmp[index++] = A[i2++];
10     }
11     while (i1 <= j1) {
12         tmp[index++] = A[i1++];
13     }
14     while (i2 <= j2) {
15         tmp[index++] = A[i2++];
16     }
17     for (int i = 0; i<index; i++) {
18         A[start + i] = tmp[i];
19     }
20     return;
21 }
22 void divide(int* A, int start, int end, int* tmp) {
23     if (start<end) {
24         int middle = (start + end) / 2;
25         divide(A, start, middle, tmp);
26         divide(A, middle+1, end, tmp);
27         merge(A, start, middle, end, tmp);
28     }
29 }
30 void mergesort(int* A, int size) {
31     if (A == NULL || size == 0 || size == 1)
32         return;
33     int* tmp = new int[size];
34     divide(A, 0, size - 1, tmp);
35     delete[] tmp;
36     return;
37 }

堆排序(以最大堆為例子):
1.首先要構建一個最大堆(從size/2-1位置開始維護堆,葉子節點默認已經是一個最大堆了,維護到根節點,則已經構成一個最大堆)
2.交換根節點(此時根節點是最大值),和最後一個節點,破壞了最大堆的性質,此時繼續維護最大堆(維護最大堆的過程就是類似直接插入排序,找到維護點合適插入的位置,保證最大堆性質不被破壞就好)
3.循環交換最後一個節點和根節點,每次維護最大堆的規模減一(找到最大,找到次大,次次大……),到最後到根節點,也就排序完成了。

 1 void swap(int& a, int& b) {
 2     a ^= b;
 3     b ^= a;
 4     a ^= b;
 5 }
 6 void HeapAdjust(int* A, int size, int start) {
 7     int i = start;
 8     int j = 2 * i + 1;
 9     int tmp = A[i];
10     while (j <= size) {
11         if (j + 1 <= size&&A[j + 1]>A[j])
12             j++;
13         if (A[j] <= tmp)
14             break;
15         A[i] = A[j];
16         i = j;
17         j = 2 * i + 1;
18     }
19     A[i] = tmp;
20     return;
21 }
22 
23 void CreateHeap(int* A, int size) {
24     for (int i = size / 2 - 1; i >= 0; i--)
25         HeapAdjust(A, size - 1, i);
26 }
27 
28 void HeapSort(int* A, int size) {
29     if (A == NULL || size == 0 || size == 1)
30         return;
31     CreateHeap(A, size);
32     for (int i = size - 1; i >= 1;) {
33         swap(A[0], A[i--]);
34         HeapAdjust(A, i, 0);
35     }
36 }

三種排序:快排,歸並,堆排