快速排序
1. 原理分析
-
快速排序在日常編程中是比較常見的一種排序手段。它的實現相比較於冒泡排序來說可能複雜一些,因爲他用到了遞歸的思想,其實只要理解其排序的思想,我們會發現快速排序也沒有那麼難。
-
在快速排序中,我們使用了分治法,簡言之就是分而治之。那麼根據什麼來分呢?
-
這裏我們需要選取一個基準值,給他去個名字叫key吧。基準值我們一般選取數組的第一個元素的值:key = array[0] (當然了, 你可以選取數組中的任意一個值來作爲基準值)
然後就是比較環節了,我們拿這個基準值去跟其他的每一值去比較,比基準值大的就放在它的右邊,比基準值小的就放在它的左邊。這樣原來的數組就別分成了基準值的做和右兩部分,然後左邊部分和右邊部分有按照這種辦法來繼續分區而治。這裏就體現了分治法的精髓。再深入思考一下,這個過程是不是很像遞歸的過程呢(二叉樹的遍歷過程也和這個很像的)。所以這裏也用到了遞歸的思想。
-
口說無憑,下面來舉個例子。
定義一個數組:int a[] = {33,12,8,46,5,88}
-
首先選取一個基準值key(一般選a[0]),key = a[0]
-
然後定義兩個下標(用來遍歷數組),i,j;分別用來表示數組的第一個元素的下標和最後一個元素的下標。i = 0,j = len-1;
-
33 12 8 46 5 88
i------------------j
開始移動時,j移動到5的位置,此時a[j] < a[i](不滿足的話執行j--,即j繼續向左移動,直到該條件滿足),前面我們已經將a[i]的值保存到key中了,即已經將a[i]的值挖出了,使a[i]=a[j],然後開始移動i,即i++,移動到12位置發現:
46比33大,就將a[j]=a[i],以此比較。當i>=j時,第一輪比較停止,此時a[i]=key;[5 12 8] 33 [46 88]
到此,原來的的數據被分成了兩組
繼續遞歸對兩邊的繼續分組
最終,的到正確的排序。
-
二、實現代碼講解
void quick_sort(int a[],int low,int high)
{
int i = 0,j = o,key = 0;
i = low;
j = high;
key = a[low]; //根據用戶傳入的值選取基準值
while(i < j)
{
//從j開始,找到比key小的數,放在i的位置
while(i < j && a[j] >= key)
{
j--;
}
if(i < j)
{
a[i] = a[j]; //將比a[i]大的值放到a[i]位置
}
while(i < j && a[i] <= key)
{
i++; //i開始向後查找比key大的值
}
if(i < j)
{
a[j] = a[i];
}
}
//循環結束後,a[i]的值沒有變,將key放到a[i]
a[i] = key;
//對左右的搬去進行遞歸快排
qiuck_sort(a,low,i-1); //對左搬去進行塊排
qiuck_sort(a,j+1,high); //對右半區進行快排
}
三、總結
- 快速排序中事件複雜度會根據數據的位置不同而有所不同,如選取的基準值在中間,這樣這種排序方法的空間複雜度最低爲O(nlogn),相反,若每次選取的基準值都是最大最小值的話,那麼其空間複雜度爲O(n^2),所以該算法是不穩定的。