快排初步理解

2021-08-20 02:23:24 字數 3091 閱讀 1494

簡而言之,快排的思想就是快速定位元素位置

如果陣列類的所有數字都是有序的,那麼挑選任意乙個元素,它的所有前項的個數是確定的,所有後項的個數也是確定的。那麼有人會說了,1,2,3,4,5,5,5,6 這樣的陣列,就5這個元素出現了3次,在亂序的狀態下可能有1,2,3,5,4,5,6,5或者1,5,3,5,2,4,6,5等等的情況,怎麼知道哪乙個5前面有幾個元素,換句話說,對於每一次出現的5,它的位置是位於三個有序的5中的哪乙個位置?這個就牽涉到陣列排序的穩定和非穩定問題了,而快速排序是非穩定的,具體後面會分析到。

快排的過程,

實現的時候步驟就是把大於選定基準元素的數放在基準元素之後,而小於基準的元素放在元素的前面。比較直觀 的實現方式就是使用陣列元素的移動。先選出基準,然後沒選擇乙個基準之外的數就和基準值比較,小於就插入到基準值前面,大於的話就插入到急轉的後面,但是這種實現方式會引發大量的元素位移,資料量大的時候步驟很多,增加了演算法的時間複雜度。

網路上的演算法實現的基準選擇都是一上來選擇陣列的第乙個元素,但是這樣並不好理解。其實基準的選擇不重要,我們可以選擇任意位置的元素作為基準,只要迴圈操作過程中保證每乙個元素都選擇到。

為便於理解,我們選擇陣列中的中間位置元素作為基準,迴圈過程中如果左方的元素值大於基準那麼,把元素放到「基準元素的右邊」,右方元素的位置如果小於基準值就放到「基準值的左方」。為什麼要加「」呢,這個左右方其實並不是通常意義上的左右。

如陣列:

11,2,54,3,1,2,19,45

選擇靠中間位置的元素,8/2選擇4位置的元素,就是1了,我們用乙個變數mid_val=1來儲存它。

然後定義兩個游標,left和right,left從0位置往後移動,而right從陣列的最後乙個位置7往前移。

先從left開始,left為0,選取元素11和基準1比較,11>1,所以11應放到1的「右方」,但是如果直接插入到1的右方就會引發元素移動位置,為避免之前說過的時間複雜度的問題,這裡把11直接放到1的位置。反正1有變數mid_val儲存記錄著,不擔心1丟失,這就是為什麼對「基準元素的右邊」和"基準值的左方」加引號的原因了。

現在左方找到乙個大於基準的值,並且把這個值放在了右邊,那麼這個位置的值11就沒有意義了

11,2,54,3,11,2,19,45

這之後就輪到right了,選right所在的值45,mid_val=1,   45>1,所以45的位置不用動,right接著向前移動,19>1,接著向前移動...

right向前的過程中在和left=0相遇之前沒有比mid_val=1還要大的元素,所以,right會一直向前直到和left相遇在left=0位置,那麼此時有left==right,也就是left在第一次和基準比較之後就一直沒有移動,那麼它所在的位置的元素11之前又「放在」了陣列的右邊,所以left停留的位置的值是無意義的,可以直接把mid_val放在left此時的位置

1,2,54,3,11,2,19,45

left和right相遇意味著針對基準進行的陣列遍歷完成,基準做選取的元素位置確定。比較重要的一點是當用游標走過的元素被「扔到」另乙個方向的時候,也就是另乙個方向的某個位置被重新賦值了,那麼游標所在的位置元素變得沒有意義,它被用來後續放置另一方向上不滿足條件的值,因為在一邊不滿足條件的值必然是另一邊上的。

可以繼續選擇4位置元素的值11,過程如下

mid_val=11,left=0,right=7;

leftmid_val;mid_val位置元素被覆蓋

2,54,3,54,2,19,45

然後比較right,right所在位置元素right>11,right--;直到走到2所在位置,rightmid_val

2,2,3,54,2,19,45

right位置用left覆蓋

2,2,3,54,54,19,45

然後right--和left相遇,使用者mid_val覆蓋該位置的值

2,2,3,11,54,19,45

11的位置確定。

過程中,當左方資料遇到大於基準值的時候,說明這個元素應位於右方,所以覆蓋掉右方的元素,然後右方游標移動。如果右方的元素值小於基準那麼說明這個元素應在左方,覆蓋左方的值,然後操作左方游標移動。

元素賦值覆蓋時不能覆蓋當前方向未做比較的值,而是應該覆蓋已經抽取比較完成的位置的值。首次覆蓋比較特殊覆蓋的是基準值,而後續覆蓋的是之前非己方方向的,且已經經過比較的值(無意義的值)。不論是抽取的是基準還是游標所在的位置的值,只要其所在的方位需要變化,那麼變化完成後,在變化之前其所在的位置就變得沒有意義,值只起到佔位的作用,可以用來放置應該存在於其方位的任何元素值。

現在應該比較能夠理解一開始選取陣列第乙個元素位置作為基準的情況了,當抽取完成基準之後,基準位置值就沒有意義了,可以用它來存放大於或者小於基準值所在方位的任何元素。陣列遍歷過程中在左邊找大的放到右邊佔位的地方,在右邊找小的放到左邊佔位的地方。

最後就是遞迴了,當乙個元素的位置確定後,把陣列相當於切成兩段,在對這兩段陣列做快排,遞迴執行下去,直到全部的元素的位置確定。

演算法實現如下:

c語言void quicksort(int nums,int start,int end)

else//左方的值是小於基準的

left++;//左方游標後移}}

nums[left] = mid_val;//迴圈都退說明不滿足left回到之前的關於快排非穩定排序的問題上,對於如陣列1,2,3,5,4,5,6,5的情況,如果選擇基準為第二個5,那麼當左邊的游標走到第乙個5的時候,5和5是非小於的狀態,按照<=就覆蓋的做法,第乙個5被覆蓋到第二個5上,然後右邊的游標又是乙個5,右方大於才覆蓋,非大於情況下繼續前移,直到4,覆蓋左方的值變成1,2,3,4,4,5,6,5,然後left右移動和right相遇,left=rght,響應位置賦值為基準5,變成1,2,3,4,5,5,6,5,4之後的第乙個5是選擇的基準的值,它原來是第二個5,現在變成了第乙個5,順序被打亂了,所以是非穩定的排序。

值得注意的是針對和基準值相等的情況,不能左邊和右邊比較都同時存在=的情況,如》=和<=同時存在,這不能滿足「非此即彼」的原則,即左方大的應在右方和右方小的應在左方,而不是左方大於或等於的在右方和右方小於或等於的在左方,相等的時候會造成左右混亂。等於的情況只能在一方處理。

好了,絮絮叨叨的顯得比較囉嗦,但是個人認為還算是比較細緻,可以給理解快排的童鞋一些幫助。

快排2 經典快排和荷蘭國旗快排

基礎知識見 建議先閱讀基礎知識,並自己手推一遍 演算法原理 第一步 取陣列最後乙個數作為num,將陣列中的 num的數放在陣列的左邊,num的數放在陣列的右邊,這是可以理解為分成了兩個陣列 第二步 然後將 num的部分當成乙個陣列,繼續第一步 num的部分同理 第三步 若陣列的大小 2,則結束。流程...

python實現快排演算法 python快排演算法詳解

快排是python經典演算法之一。1 下面講解的是什麼是快排和快排的圖示。2 快排是一種解決排序問題的運算方法。3 快排的原理 在陣列中任意選擇乙個數字作為基準,用陣列的資料和基準資料進行比較,比基準數字打的數字的基準數字的右邊,比基準數字小的數字在基準數字的左邊,第一次排序之後分為比基準資料大或比...

分治 快排 快選

快排模板 include using namespace std const int n 1e5 10 int n,a n void quick sort int q,int l,int r quick sort q,l,j quick sort q,j 1,r intmain 快速選擇演算法 選擇...