歸並排序
歸並排序是另一種不同的排序方法,因為歸並排序使用了遞歸分治的思想,所以理解起來比較容易。其基本思想是,先遞歸划分子問題,然后合並結果。把待排序列看成由兩個有序的子序列,然后合並兩個子序列,然后把子序列看成由兩個有序序列。。。。。倒着來看,其實就是先兩兩合並,然后四四合並。。。最終形成有序序列。空間復雜度為O(n),時間復雜度為O(nlogn)。
舉個栗子:

#include <iostream> #include <vector> #include <algorithm> #include <limits.h> #include "Solution.h" using namespace std; void MergeArray(int array[], int start, int mid, int end, int temp[]) { int i = start; int j = mid + 1; int k = 0; while (i <= mid && j <= end ) { if (array[i] < array[j]) { temp[k++] = array[i++]; }else { temp[k++] = array[j++]; } } while (i <= mid) { temp[k++] = array[i++]; } while (j <= end) { temp[k++] = array[j++]; } for (int i = 0; i < k; i ++) { array[start + i] = temp[i]; } } // 歸並排序,將數組前半部分后半部分分成最小單元,然后在合並 void MergeSort(int array[], int start, int end, int temp[]) { if(start < end) { int mid = (start + end)/ 2; MergeSort(array, start, mid, temp); MergeSort(array, mid + 1, end, temp); MergeArray(array, start, mid, end, temp); } } // 在這里創建臨時數組,節省內存開銷,因為以后的temp都是在遞歸李使用的。 void MergeSortmain(int array[], int len) { int start = 0; int end = len - 1; int *temp = new int[len]; MergeSort(array, start, end, temp); } void PrintArray(int array[], int len) { for (int i = 0 ; i < len; ++i) { cout << array[i] << " " ; } cout << endl; } int main() { int array[] = {3,5,3,6,7,3,7,8,1,2}; MergeSortmain(array, 10); PrintArray(array, 10); return 0; }
快速排序
快速排序一聽名字就覺得很高端,在實際應用當中快速排序確實也是表現最好的排序算法。冒泡排序雖然高端,但其實其思想是來自冒泡排序,冒泡排序是通過相鄰元素的比較和交換把最小的冒泡到最頂端,而快速排序是比較和交換小數和大數,這樣一來不僅把小數冒泡到上面同時也把大數沉到下面。
舉個栗子:對5,3,8,6,4這個無序序列進行快速排序,思路是右指針找比基准數小的,左指針找比基准數大的,交換之。
5,3,8,6,4 用5作為比較的基准,最終會把5小的移動到5的左邊,比5大的移動到5的右邊。
5,3,8,6,4 首先設置i,j兩個指針分別指向兩端,j指針先掃描(思考一下為什么?)4比5小停止。然后i掃描,8比5大停止。交換i,j位置。
5,3,4,6,8 然后j指針再掃描,這時j掃描4時兩指針相遇。停止。然后交換4和基准數。
4,3,5,6,8 一次划分后達到了左邊比5小,右邊比5大的目的。之后對左右子序列遞歸排序,最終得到有序序列。
上面留下來了一個問題為什么一定要j指針先動呢?首先這也不是絕對的,這取決於基准數的位置,因為在最后兩個指針相遇的時候,要交換基准數到相遇的位置。一般選取第一個數作為基准數,那么就是在左邊,所以最后相遇的數要和基准數交換,那么相遇的數一定要比基准數小。所以j指針先移動才能先找到比基准數小的數。
快速排序是不穩定的,其時間平均時間復雜度是O(nlgn)。
實現代碼:
#include <iostream> #include <vector> #include <algorithm> #include <limits.h> #include "Solution.h" using namespace std; int partition(vector<int> &vi, int low, int up) { int pivot = vi[up];//選擇最后一個元素作為比較元素 int i = low-1;//這個慢速移動下標必須設定為比最小下表p小1,否則兩個元素的序列比如2,1無法交換 for (int j = low; j < up; j++) { if(vi[j] <= pivot) { i++; swap(vi[i], vi[j]); } } swap(vi[i+1], vi[up]); return i+1; } //C++'s array range should be [low, up], the same as [low, up+1) void quickSort(vector<int> &vi, int low, int up) { if(low < up) { int mid = partition(vi, low, up); //Watch out! The mid position is on the place, so we don't need to consider it again. //That's why below is mid-1, not mid! Otherwise it will occur overflow error!!! quickSort(vi, low, mid-1); quickSort(vi, mid+1, up); } } void qSort(vector<int> &vi) { quickSort(vi, 0, vi.size()-1); } int main() { int a[] = {3,5,7,9,2,3,1,0,7,5,4}; vector<int> va(a, a+11); cout<<"Before quicksort:\n"; for(auto x:va) cout<<x<<" "; cout<<endl; qSort(va); cout<<"After quicksort:\n"; for(auto x:va) cout<<x<<" "; cout<<endl; return 0; }