快速排序曾被評為
20世紀十大演算法之一,最很多情況來說都是名副其實的最快的排序演算法。其實思路並不難,但在具體的**實現時會有很多細節容易出錯。也有一些細節如果不加注意會使排序效率意外降低。
大致思路是:從待排序陣列中選出乙個值(一般是隨即選的),對陣列進行分割,把小於軸值的放在左側,大於軸值的放在右側。然後分別對左側陣列和右側陣列繼續進行排序(遞迴進行)。一直進行下去,最後可以得到乙個有序陣列。
快速排序本質上是一種交換排序。我們最熟悉的交換排序可能應該是氣泡排序,但快速排序與氣泡排序最根本的不同是:它採用了分而治之的思想,不再是相鄰的去進行交換。這樣可以提高一些效率。
幾個需要注意的細節:
1.軸值的選擇
最簡單的選擇當然是選擇第乙個或最後乙個值,但這樣有乙個風險,如果陣列原來是正序或逆序的,這樣選擇效率可能會比較低,因為有一側的陣列元素個數是
0,這樣最終其實是乙個乙個元素排的。當然可以用隨機數確定下標,但比較麻煩。一般可以選擇中間下標值。
2.怎麼分割陣列
最直接的方法是:確定軸值後,從左側開始找到第乙個大於軸值的元素,下標為
l。從右側開始找到第乙個小於軸值的元素,下標為
r。然後,直接交換兩個值(l處和
r處的)。交換後繼續向前尋找。
個人認為這樣做比較麻煩,對邊界處理比較麻煩,對軸值也要做處理。很容易出錯。
最常用的方法是:確定軸值後(一般是中間下標處的元素),設定乙個遍歷
t parval=arr[mid]
(即是把軸值存起來)。然後把軸值和陣列最後乙個元素進行交換,這時相當於陣列最後乙個位置是空著的,等著放左側符合條件的元素。然後從陣列左側開始遍歷,找到第乙個大於(也可以找大於等於的,但那樣交換次數會多一些)軸值的元素,其下標為
l,把其放在下標為
r處(有的人實現時會判讀一下l和r
的大小關係,如果
l就r--
。其實沒有必要,不需要對
r做處理,知識多使
arr[r]
和parval
多比較了一次而已)。這時再從下標為
r處往左尋找,找到第乙個小於軸值
parval
的值,放在下標
l處。接著繼續即可。知道l和
r相遇,返回
l。幾位軸值
parval
應該在的位置。
**如下:
//快速排序
#include using namespace std;
#define n 5
遇到兩個值直接交換的
分割函式,得到分界點,左側資料都小於分界點值,右側的均大於
若使用arr[l]<=parval,arr[r]>parval這時對於分割值是最大值或最小值時會排序錯誤。比如5,4,10,3,9
此方法可能會陷入死迴圈,比如5,4,9,5
總之,這種方法需要對分割值做額外的處理,以下這種方式寫肯定是有問題的
//template //int partion(t arr,int left,int right)
//// //交換兩個值
// t temp=arr[l];
// arr[l]=arr[r];
// arr[r]=temp;
// cout<<"haha"//if(lvoid quicksort(t arr,int left,int right)
//輸出陣列內容
template void print(t arr,int size)
{ for(int i=0;i
第乙個分割方法(即直接交換的,一直沒有通過所有測試用例),希望能有高手給知道一下。
注意測試用例的全面性:比如一定要測試那些含有重複元素的陣列、分割值即是最大值或最小值的陣列。很容易發現
bug。
最近的幾點思考
在乙個競爭激烈的領域中,一定要做好定位,找好差異化的東西,差異化突出的東西,就是一家公司的特色。如果你本身在小地方發展,你自己有自己的業務,嚮往大城市的發展,捨棄已有的東西著實可惜,去大地方打拼又得從零開始,為什麼不利用好當前的業務,把業務擴充套件過去呢?也就是說,在嚮往的地方和自己的現在擁有的擅長...
工作的幾點思考
進入公司從一開始就已經有整整乙個半月。這是半個月做了什麼回憶。我真的不能告訴。該公司有沒有認真忙。通常不是乙個特別大的作業。有一點休閒。這一次,我的各種疾病就顯現出來了。玩玩手機。看看網頁,甚至和同事說說笑笑。每天晚上回去更是玩得昏天黑地。從來都不為第二天的事兒擔心。感覺自己不是乙個打工的,倒像是領...
多執行緒快速排序(思考)
在csdn看到的一位牛人實現的多執行緒快排,暫時沒細看,但是感覺有點小問題,他的多執行緒快排並沒有實現我所想要的那種平行計算的結果,我理想中的多執行緒排序 這裡特指快排 應該是類似於mapreduce的分拆和合併,在快排中,分拆是必然 和歸併一樣,基因決定嘛 分拆後的陣列可以形成佇列,按照核心數分給...