引言
只要設計到數據,就會涉及到數據的排序問題,比如給你隨機給你五個整數 3,1,5,2,4 。讓你從小到大進行排序,那我們該怎樣纔是實現對這些整數的排序呢 ?
答案是多種多樣的,比如用插入排序、希爾排序、堆排序、歸併排序、快速排序等等,這些排序方法都可以實現對整數排序,而這篇文章要講的就是快速排序
本文將從以下幾個問題對快速排序進行分析和講解:
- 什麼是快速排序?
- 快速排序的大概過程是什麼?
- 怎樣用代碼實現快速排序?
- 快速排序的代碼詳解。
一、什麼是快速排序?
下面看百度百科對快速排序的定義:
快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
簡單理解:還記得歸併排序的思想嗎,歸併排序就是先分再合。而快速排序(下面簡稱快排)有一個分的過程(不是歸併排序裏的一個數組分成兩部分),快排的分一共分兩大步。
- 首先找一個基準數(可以選數組的任意一個位置,這篇文章選的是數組的第一個數)。第一步就是把基準數變換位置,這個位置前面的數都比基準數小,後面的數都比基準數大(這裏排序是從小到大排序)。
- 開始分,以基準數爲界限,分成兩部分(兩部分都不包含基準數)。再對上面的兩部分都執行上面的1過程即可。
截止到現在爲止,只需要知道快排的兩大步是什麼就可以了,下面看一個動圖:
二、快速排序的大概過程是什麼?
我們用快速排序講一個例子來說明,要排序的數組爲3,1,5,2,4.
第一步:定基準數,並把基準數移動到合適的位置。
一般來說,基準數最終的位置(在這個位置前面的數都比基準數小,後面的數都比基準數大)都在基準數起始位置的後面(我選的基準數的數組的第一個元素),那應該讓基準數移動到哪個位置呢?
我們要設置兩個哨兵 i 和 j ,第一個哨兵 i 的位置是數組第一個元素的位置,哨兵 j 的位置數數組的最後一個元素的位置
首先哨兵 j 往前移動,在不和哨兵 i 碰頭的情況下,如果發現了一個比基準數小的數,那就暫停移動,這時候輪到了哨兵 i 往後移動,在不和哨兵 j 碰頭的情況下,如果發現了一個比基準數大的數,那就停止移動,然後哨兵 i 和 哨兵 j 交換他倆的元素,下面看圖理解。
首先發現哨兵 j 比 基準數大,所以前移,移動到一個比基準數小的位置,哨兵 i 後移,移動到一個比基準數大的位置
這時候交換哨兵 i 和 j 的值。
下面繼續哨兵j前移,哨兵i後移操作,但是哨兵 j 前移發現和 i 碰頭了,那就結束哨兵的移動,把哨兵 i 和基準數的值互換。
經過上面的操作,就完成了基準數的移動,達到了基準數前面的數都比基準數小,基準數後面的數都比基準數大的目的
下面看用代碼怎麼實現上面圖片的一系列操作
void QuickSort(int arr[],int first,int last) { if(first>last)//控制遞歸結束 return ; int i=first,j=last; int temp=arr[first];//基準數 while(i!=j)//i和j不碰頭 { //順序很重要,要先從右往左找 while(arr[j]>=temp&&i<j) j--; //上面循環結束的條件有兩種, //一是查到了比基準數小的, //二是 i與j碰頭了 while(arr[i]<=temp && i<j) i++; //循環結束條件同上 //下面交換兩個數在數組中的位置 if(i<j) //兩個循環結束的條件都不是i和j碰頭 { int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } } //最終一定會碰頭,交換基準數和碰頭那個位置的數 arr[first]=arr[i]; arr[i]=temp; //QuickSort(arr,first,i-1);分的前一部分 //QuickSort(arr,i+1,last); 分的後一部分 }
我相信只要上面的圖片過程看懂了,那麼看懂這段代碼基本沒啥問題了。
第二步就是分了,也就是上面函數的後兩行,分成兩部分,遞歸調用
三、怎樣用代碼實現快速排序?
下面看完整的代碼
#include<iostream> using namespace std; //快速排序函數 不穩定 void QuickSort(int arr[],int first,int last) { if(first>last)//控制遞歸結束 return ; int i=first,j=last; int temp=arr[first];//基準數 while(i!=j)//i和j不碰頭 { //順序很重要,要先從右往左找 while(arr[j]>=temp&&i<j) j--; //上面循環結束的條件有兩種, //一是查到了比基準數小的, //二是 i與j碰頭了 while(arr[i]<=temp && i<j) i++; //循環結束條件同上 //下面交換兩個數在數組中的位置 if(i<j) //兩個循環結束的條件都不是i和j碰頭 { int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } } //最終一定會碰頭,交換基準數和碰頭那個位置的數 arr[first]=arr[i]; arr[i]=temp; QuickSort(arr,first,i-1);//分的前一部分 QuickSort(arr,i+1,last); //分的後一部分 } //輸出數組的值 void printf(int arr[],int len) { for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } int main() { //要排序的數組 int arr[]={3, 44,38, 5,47,15,36,26,27,2 ,46,4 ,19,50,48}; int len=15;//要排序的數組長度 //排序 QuickSort(arr,0,len-1); //輸出 printf(arr,len); return 0; }
運行結果:
四、快速排序代碼詳解
- 實現基準數的移動,注意兩個哨兵移動時,移動要哨兵 j 先移動,然後再哨兵 i 移動
- 實現分的過程,注意以什麼爲分割線進行分
本文參考以及引用:
啊哈算法!
如果對其他的算法還有興趣,可以點擊下面的鏈接。
創作不易,如果本文對你起到了一些幫助,何不點個贊再走呢!!!