6、快速排序ios
快速排序是經過一種把集合中的元素按照第一個元素(這個是動態過程變化)做爲標杆來分爲兩部分,前面一部分比他小(或等),後面一部分比它大。而後就是經過適當的程序來遞歸這個過程,當最後沒有交換說明須要退出遞歸。算法
上圖。數據結構
快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分爲兩個子序列(sub-lists)。less
步驟爲:dom
遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,可是這個算法總會退出,由於在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。ide
代碼:函數
1 #include <iostream> 2 #include <iterator> 3 #include <vector> 4 #include <ctime> 5 #include <random> 6 #include <functional> 7 #include <algorithm> 8 using namespace std; 9 int intSwap(int& a,int& b) 10 { 11 int intswaptemp=a; 12 a=b; 13 b=intswaptemp; 14 return 0; 15 } 16 /*---------------------------------------------------- 17 -----------------快速排序(STL版本)--------------------- 18 參數:迭代器、cmp 19 cmp能夠爲less、greater等函數 20 template<typename _Tp> 21 struct less_equal : public binary_function<_Tp, _Tp, bool> 22 { 23 bool 24 operator()(const _Tp& __x, const _Tp& __y) const 25 { return __x <= __y; } 26 }; 27 這個東西第一次學須要本身拿筆算寫,不須要想,由於太費勁了。 28 ----------------------------------------------------*/ 29 template<typename Conditerator,typename Compare> 30 int quickSortIter(Conditerator begin,Conditerator end,Compare cmp) 31 { 32 if(begin!=end)//遞歸終止條件 33 { 34 Conditerator left=begin;//左 35 Conditerator right=end;//右 36 Conditerator pivot=left++;//用於做爲參考相對大小的數子 37 while(left!=right) 38 { 39 if(cmp(*left,*pivot))//從begin開始下一個比較是否小於begin, left<begin(pivot) 40 ++left;//若是成立,left移向下一個未和begin比較的值 41 else 42 { 43 while((left!=right)&&cmp(*pivot,*right))//begin(pivot)<right 44 right--; 45 iter_swap(left,right); 46 } 47 } 48 if(cmp(*pivot,*left))//這裏就是爲了防止left和right重合 49 --left;//由於在上面程序中,最後會致使left和right重合,須要分離left 50 iter_swap(begin,left);//保留了pivot,經過交換到前面一組中的最後一位 51 quickSortIter(begin,left,cmp); 52 quickSortIter(right,end,cmp); 53 } 54 return 0; 55 } 56 template<typename T> 57 inline int quickSort(T begin,T end) 58 { 59 quickSortIter(begin,end, 60 less_equal<typename iterator_traits<T>::value_type>()); 61 return 0; 62 } 63 inline int QuickSortVector(vector<int> &ivec) 64 { 65 quickSort(ivec.begin(),ivec.end()); 66 return 0; 67 } 68 /*---------------------------------------------------- 69 -----------------快速排序(vector版本)------------------ 70 參數:vector<int> 71 關鍵信息:經過合適的交換來實現,以第一個begin值爲臨時交換的參考值 72 解釋同上 73 注意:必定要搞清楚>=和<=的邏輯關係,不然error或者死循環 74 ----------------------------------------------------*/ 75 int quicksort_vector(vector<int>& ivec,int begin,int end) 76 { 77 if(begin!=end) 78 { 79 int left=begin; 80 int right=end; 81 int pivot=left++;//設置參考值(用於比較) 82 while(left!=right) 83 { 84 if(ivec[pivot]>=ivec[left]) 85 ++left; 86 else 87 { 88 while((left!=right)&&(ivec[pivot]<=ivec[right])) 89 --right; 90 intSwap(ivec[left],ivec[right]); 91 } 92 } 93 if(ivec[pivot]<=ivec[left]) 94 left--; 95 intSwap(ivec[begin],ivec[left]); 96 quicksort_vector(ivec,begin,left); 97 quicksort_vector(ivec,right,end); 98 } 99 return 0; 100 } 101 inline int quicksort1(vector<int> &ivec) 102 { 103 quicksort_vector(ivec,0,ivec.size()-1); 104 return 0; 105 } 106 int main() 107 { 108 clock_t start,end; 109 vector<int> ivec,copyivec; 110 srand(14); 111 for(int i=0;i<10000;i++)//10k 112 ivec.push_back((int)rand()); 113 copyivec=ivec; 114 start=clock(); 115 QuickSortVector(ivec); 116 end=clock(); 117 for(int i=0;i<10000;i+=500) 118 cout<<ivec[i]<<'\t'; 119 cout<<endl; 120 cout<<"the time of 1 is "<<end-start<<endl; 121 start=clock(); 122 quicksort1(copyivec); 123 end=clock(); 124 for(int i=0;i<10000;i+=500) 125 cout<<ivec[i]<<'\t'; 126 cout<<endl; 127 cout<<"the time of 2 is "<<end-start<<endl; 128 129 return 0; 130 }
亂數快速排序有一個值得注意的特性,在任意輸入數據的情況下,它只須要O(n log n)的指望時間。是什麼讓隨機的基準變成一個好的選擇?ui
假設咱們排序一個數列,而後把它分爲四個部份。在中央的兩個部份將會包含最好的基準值;他們的每個至少都會比25%的元素大,且至少比25%的元素小。若是咱們能夠一致地從這兩個中央的部份選出一個元素,在到達大小爲1的數列前,咱們可能最多僅須要把數列分區2log2 n次,產生一個 O(nlogn)算法。spa
不幸地,亂數選擇只有一半的時間會從中間的部份選擇。出人意外的事實是這樣就已經足夠好了。想像你正在翻轉一枚硬幣,一直翻轉一直到有 k 次人頭那面出現。儘管這須要很長的時間,平均來講只須要 2k 次翻動。且在 100k 次翻動中得不到 k 次人頭那面的機會,是像天文數字同樣的很是小。藉由一樣的論證,快速排序的遞歸平均只要2(2log2 n)的調用深度就會終止。可是若是它的平均調用深度是O(log n)且每一階的調用樹狀過程最多有 n 個元素,則所有完成的工做量平均上是乘積,也就是 O(n log n)。code
數據結構 | 不定 |
---|---|
最差時間複雜度 | |
最優時間複雜度 | |
平均時間複雜度 | |
最差空間複雜度 | 根據實現的方式不一樣而不一樣 |