標籤:
寫出一個較好的快速排序程式
- 快速排序是常用的排序演算法之一,但要想寫出一個又快又準的使用程式,就不是那麼簡單了
需要注意的事項
- 首先要寫正確。通常使用遞迴實現。其遞迴相當於二叉樹展開,因此如果要用迭代實現的話需要使用一個隊列來儲存後續遍曆資訊。
- 快速排序需要找到一個pivot值,如果順序選擇pivot則易造成N^2的複雜度,如果使用隨機數則效果最好,但開銷又太大,採取三數中值法比較合適。三數中值法指的是選取第一個值,最後一個值,數組中間的值的中值。有文獻表明可以提升5%的已耗用時間。
- 當數組長度較小時,如10個元素以下,最好使用插入排序或者選擇排序完成,以防止多次函數調用帶來的開銷。而遞迴到底層數組長度總是會變小的,因此這麼做非常有必要。
- 在合并前後兩部分數組時,採用兩邊夾方法,在前後兩部分各找到一個大於和小於的值再交換。相比通常情況下找到比pivot小的值就進行交換,能提高運行效率。
實現代碼
- 代碼如下。包括插入排序insert_sort,遞迴函式,三分中值函數三個輔助函數。
- 三分中值函數其實採用的是插入排序。通過三次比較,確定中值。
- 插值演算法使用臨時變數tmp避免了大量swap函數調用。
#include<iostream>#include<iomanip>#include<vector>#include<cstdlib>#include<ctime>#include<algorithm>using namespace std;inline void swap(vector<int>& num, int p, int q){ int t = num[p]; num[p] = num[q]; num[q] = t;}void insert_sort(vector<int>& num){ int tmp, j; for (int i = 1; i < num.size(); i++){ tmp = num[i]; for (j = i - 1; j >= 0 && num[j] > tmp; j--) num[j + 1] = num[j]; num[j + 1] =tmp; }}int quick_sort_sub(vector<int>& num, int p, int q){ if (p >= q) return 0; // if 4 elements or less, use insert sort if (p + 10 > q){ vector<int> tnum(num.begin() + p, num.begin() + q + 1); insert_sort(tnum); for (int i = 0; i < tnum.size(); i++) num[p + i] = tnum[i]; } int idx = quick_three_partition(num, p, q); swap(num, idx, q); int pivot = num[q]; int left = p, right = q - 1; while (1){ while (num[left] < pivot) ++left; while (num[right] >= pivot) --right; if (left < right) swap(num, left, right); else break; } swap(num, left, q); quick_sort_sub(num, p, left - 1); quick_sort_sub(num, left + 1, q); return left;}void quick_sort(vector<int>& num){ quick_sort_sub(num, 0, num.size() - 1);}int main(){ const int n = 10; /*int num_array[n]= {2,1}; vector<int> num(num_array, num_array + n);*/ srand( time(NULL) ); vector<int> num(n); for (auto& e : num) e = rand() % n; quick_sort(num); for (auto& e : num) cout << setw(4) << e << ‘ ‘; cout << endl; cout << "vector is sorted? : " << is_sorted(num.begin(), num.end()) << endl; return 0;}
轉載請註明Focustc,部落格地址為http://blog.csdn.net/caozhk,原文連結為點擊開啟
如何寫出一個較好的快速排序程式