題目描述:
給你一個整數數組 nums,請你將該數組採用快速排序方式進行升序排列。
輸入示例: [1,8,6,2,5,4,9,3,7]
輸出示例: [1,2,3,4,5,6,7,8,9]
解題思路:
快速排序使用分治法來把一個串(list)分爲兩個子串(sub-lists)。具體算法描述如下:
- 從數列中挑出一個元素,稱爲 “基準”(pivot);
- 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區退出之後,該基準就處於數列的中間位置。這個稱爲分區(partition)操作;
- 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
栗子描述:
來源於:快速排序
假設我們現在對 "6 1 2 7 9 3 4 5 10 8"
這個10個數進行排序。首先在這個序列中隨便找一個數作爲基準數。爲了方便,就讓第一個數6作爲基準數吧。接下來,需要將這個序列中所有比基準數大的數放在6的右邊,比基準數小的數放在6的左邊,類似3 1 2 5 4 6 9 7 10 8
這種排列。那要如何做到呢?
方法:
分別從初始序列"6 1 2 7 9 3 4 5 10 8"
兩端開始" 探測 "。先從右往左找一個小於6的數,再從左往右找一個大於6的數,然後交換他們。這裏可以用兩個變量 和 ,分別指向序列最左邊和最右邊。剛開始的時候讓指向序列的最左邊(即),指向數字6。讓哨兵指向序列的最右邊(即 ),指向數字8。
首先開始出動。因爲此處設置的基準數是最左邊的數,所以需要讓先出動,這一點非常重要(請自己想一想爲什麼)。一步一步地向左挪動(即),直到找到一個小於6的數停下來。接下來再一步一步向右挪動(即),直到找到一個數大於6的數停下來。最後停在了數字5面前, 停在了數字7面前。
現在交換和所指向的元素的值。交換之後的序列爲6 1 2 5 9 3 4 7 10 8
到此,第一次交換結束。接下來開始繼續向左挪動。他發現了4(比基準數6要小,滿足要求)之後停了下來。也繼續向右挪動的,他發現了9(比基準數6要大,滿足要求)之後停了下來。此時再次進行交換,交換之後的序列爲6 1 2 5 4 3 9 7 10 8
第二次交換結束,“探測"繼續。 繼續向左挪動,他發現了3(比基準數6要小,滿足要求)之後又停了下來。 繼續向右移動,糟啦!此時 和 相遇了, 和 都走到3面前。說明此時” 探測 "結束。我們將基準數6和3進行交換。交換之後的序列爲3 1 2 5 4 6 9 7 10 8
到此第一輪“探測”真正結束。此時以基準數6爲分界點,6左邊的數都小於等於6,6右邊的數都大於等於6。回顧一下剛纔的過程,其實的使命就是要找小於基準數的數,而的使命就是要找大於基準數的數,直到 和 碰頭爲止。
OK,解釋完畢。現在基準數6已經歸位,它正好處在序列的第6位。此時我們已經將原來的序列,以6爲分界點拆分成了兩個序列,左邊的序列是“3 1 2 5 4”
,右邊的序列是“9 7 10 8”
。接下來還需要分別處理這兩個序列。因爲6左邊和右邊的序列目前都還是很混亂的。不過不要緊,我們已經掌握了方法,接下來只要模擬剛纔的方法分別處理6左邊和右邊的序列即可。現在先來處理6左邊的序列現吧。
如果你模擬的沒有錯,調整完畢之後的序列的順序應該是2 1 3 5 4
最終得到正確的排序結果:1 2 3 4 5 6 7 8 9 10
代碼:
Python寫法:
class Solution(object):
def solution(self, nums):
if len(nums) < 2:
return nums
else:
tmp = nums[0]
less = [num for num in nums[1:] if num <= tmp]
big = [num for num in nums[1:] if num > tmp]
return self.solution(less) + [tmp] + self.solution(big)
C++寫法:
#include<iostream>
using namespace std;
int a[100],n; //定義全局變量
void quicksort(int left, int right) {
int i, j, t, temp;
if(left > right)
return;
temp = a[left]; //temp中存的就是基準數
i = left;
j = right;
while(i != j) { //順序很重要,要先從右邊開始找
while(a[j] >= temp && i < j)
j--;
while(a[i] <= temp && i < j) //再找右邊的
i++;
if(i < j) //交換兩個數在數組中的位置
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//最終將基準數歸位
a[left] = a[i];
a[i] = temp;
quicksort(left, i-1); //繼續處理左邊的,這裏是一個遞歸的過程
quicksort(i+1, right); //繼續處理右邊的 ,這裏是一個遞歸的過程
}
int main() {
int i;
cin >> n; //讀入數據
for(i = 1; i <= n; i++)
cin >> a[i];
quicksort(1, n); //快速排序調用
for(i = 1; i <= n; i++) //輸出排序後的結果
cout << a[i] <<" ";
cout << "\n";
return 0;
}
C語言:
#include <stdio.h>
int a[100],n; //定義全局變量
void quicksort(int left, int right) {
int i, j, t, temp;
if(left > right)
return;
temp = a[left]; //temp中存的就是基準數
i = left;
j = right;
while(i != j) { //順序很重要,要先從右邊開始找
while(a[j] >= temp && i < j)
j--;
while(a[i] <= temp && i < j) //再找右邊的
i++;
if(i < j) //交換兩個數在數組中的位置
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//最終將基準數歸位
a[left] = a[i];
a[i] = temp;
quicksort(left, i-1); //繼續處理左邊的,這裏是一個遞歸的過程
quicksort(i+1, right); //繼續處理右邊的 ,這裏是一個遞歸的過程
}
int main() {
int i;
//讀入數據
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d", &a[i]);
quicksort(1, n); //快速排序調用
//輸出排序後的結果
for(i = 1; i <= n; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
題目來源: