基本思想
快排是對冒泡排序的一種改進,是C.R.A.Hoare於1962年提出的一種劃分交換排序,採用了分治的策略,通常稱爲分治法
基本思想:
1、選取一個值爲基準值point
2、將小於或等於point的值放於左邊
3、將大於point的值放於右邊
4、分別對左右子序列重複前三個步驟,直到各子序列只有一個數
上述圖實例爲快速的第一輪過程,顯然是挖坑填數+分治法來實現整個快速排序過程,以序列爲一數組,以i=0指向數組第一個數字,以j=5來指向數組最後一個數字,進行快排。
第一次取下標爲0的數作爲基準值:18
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
18 | 98 | 10 | 16 | 2 | 7 |
開始時,i=0,j=5,temp=num[i]=18
此時已經將num[0]的值保存到temp中,可理解爲將num[0]這裏挖坑,可以將其他數據填充到這裏。從j=5開始向前尋找小於或等於temp的數字,j=5時,7<18,符合條件,將num[5]的值挖出填入坑num[0]中,即num[0]=num[5];i++;填完坑之後,又出現了新坑num[5],則需要再一次找數字來填這個坑,這次從i開始向後找大於temp的數字,當i=1時,即num[1]=98大於temp,符合條件,挖出num[1]的值填入坑num[5]中,即num[5]=num[1];j++;這樣又出現了新坑num[1]…以此類推,當j等於i時,將基準值賦給num[i],分別對num[i]左右子序列遞歸調用快排方法,遞歸的結束條件爲各子序列只有一個數字
代碼實現
1、以上思想中挖坑填數+分治法結合,Java實現如下
public void quick_sort(int num[], int l, int r)
{
if (l < r)
{
int i = l, j = r, temp = num[l];
while (i < j)
{
// 從右向左找第一個小於或等於x的數來填坑num[i]
while(i < j && num[j] > temp)
j--;
if(i < j)
num[i++] = num[j]; //將num[j]填到num[i]中,num[j]形成新坑
// 從左向後找第一個大於x的數
while(i < j && num[i] <= temp)
i++;
if(i < j)
num[j--] = num[i]; //將num[i]填到num[j]中,num[i]形成新坑
}
num[i] = temp;
quick_sort(s, l, i - 1); // 左邊子序列遞歸調用
quick_sort(s, i + 1, r); //右邊子序列遞歸調用
}
}
2、Golang的快排結合切片實現(用填坑法+分治Go重寫1的Java代碼超出時間限制)
注:continue語句執行是跳過本次循環(不管後面未執行的語句)繼續下一次循環
func quick_sort(nums []int){
i , j := 0 , len(nums) - 1
for i < j {
if nums[j] > nums[0] {
j--
continue
}
if nums[i] <= nums[0] {
i++
continue
}
nums[i],nums[j] = nums[j] ,nums[i]
}
nums[0],nums[i] = nums[i],nums[0]
if len(nums[:j]) > 1 {
sortArray(nums[:j]) //左邊子序列遞歸調用
}
if len(nums[j+1:]) >1 {
sortArray(nums[j+1:]) //右邊子序列遞歸調用
}
}
3、Golang slice方法,很好體現出分治思想
func sortArray(nums []int) []int {
if len(nums) <= 1 {
return nums
}
//nums[0]作爲基準值
key := nums[0]
var left, right []int
for _, e := range nums[1:] {
if e <= key {
left = append(left, e)
} else {
right = append(right, e)
}
}
return append(append(sortArray(left), key), sortArray(right)...)
}