快速排序的核心思想能夠參照分治三步法:前端
1.劃分問題 把數組元素重排後分紅左右兩塊,使得左邊的元素都小於右邊的元素ios
2.遞歸求解 再把左右兩邊分別排序算法
3.合併問題 不須要合併,由於數組已經有序後端
1 #include <iostream> 2 #include <cstdio> 3 #include <fstream> 4 using namespace std; 5 6 void quicksort(int a[],int left, int right) 7 { 8 if (left>=right) return; //遞歸結束 9 int mark = a[left]; //取第一個數爲標誌 10 int st = left; 11 int ed = right; 12 while(st<ed) 13 { 14 while(st<ed && a[ed] >= mark) ed--; //從末尾開始找比mark小的數 15 if (st<ed) a[st++] = a[ed]; //先移到前端,而後st再加一(挖洞) 16 while(st<ed && a[st] < mark) st++; //從開頭找比mark大的數 17 if (st<ed) a[ed--] = a[st]; //先移到後端,而後ed再減一(填坑) 18 } 19 a[st] = mark; //將mark移到中間 20 quicksort(a,left,st-1); 21 quicksort(a,st+1,right); 22 } 23 24 int main() 25 { 26 ifstream fin("data.in"); 27 int num ; 28 int a[100]; 29 fin >> num ; 30 for (int i=0;i<num;i++) 31 fin >> a[i]; 32 quicksort(a,0,num-1); 33 for (int i=0;i<num;i++) cout<<a[i]<<' '; 34 return 0; 35 }
快速排序的重點和難點應該在於如何劃分數組,這裏給出最經常使用的方法:以數組的第一位爲標誌位。先從末尾找到比標誌位小的數A,代表該數應該被放置在標誌位以前。而後把標誌位當作一個須要數字來填的坑,將A填入坑中,此時A本來的位置變成了一個新坑。而後咱們再從開頭尋找比標誌位大的數B,代表該數應該被放置在標誌位以後。將B填入A本來的坑中,此時B本來的位置成爲一個新坑等待下一個A來填。數組
例如咱們用快速排序的思想對下面的數組進行排序:優化
初始狀態:ui
5 3 9 6 1 4 2 7 8 標誌位爲5,因此咱們的目的是把5放在數組中間使得在5以前的數字比5小,在5以後的數字比5大。spa
執行 while(st<ed && a[ed] >= mark) ed--; 得:指針
5 3 9 6 1 4 2 7 8 7,8都大於5, 2是第一個小於5的數字code
執行 if (st<ed) a[st++] = a[ed]; 得:
2 3 9 6 1 4 2 7 8 咱們會在最後將5放到合適的位置,因此沒必要擔憂5被覆蓋,而2雖然還在原來的位置,可是咱們下一次將會用其餘數字覆蓋它
執行 while(st<ed && a[st] < mark) st++;得:
2 3 9 6 1 4 2 7 8 3小於5,9是第一個大於5的數字
執行 if (st<ed) a[ed--] = a[st]; 得:
2 3 9 6 1 4 9 7 8 ,同理9原來的位置會在下一次被其餘數字覆蓋(不難看出來是4)
如此循環下去直到兩個標誌指針碰見,表示數組已經遍歷完成。最後,應該剩下一個B的坑位尚未填,最終咱們將標誌位填到裏面,此時劃分數組完成。
因爲咱們第一個挖的坑是處於數組首的標誌位,因此咱們須要先從末尾找起,若是先從開頭找比標誌位大的數B,那麼這個數B將無地放置。
(若是咱們以最後一個數爲標誌位,那麼咱們將先從開頭找比標誌位大的數B填入最後一位,而後再找A填入B原來的位置)
劃分數組的本質是數字相對位置的交換,使得最終的數組成爲前端任意數比後端任意數小的兩個分支。對於快速排序的優化能夠將標誌位設定爲中間的某個數字而不是第一個,而後將兩個數的位置交換。這樣可使得劃分的數組先後端長度相近,使算法效率提升。