快速排序 通俗易懂 例子 優化方案

2021-10-23 21:55:26 字數 4462 閱讀 3381

快速排序思想

排序陣列(下標從l到r),選擇l到r之間任意乙個資料作為povit(分割槽點)。

遍歷陣列,將小於povit到放左邊,大於povit到放右邊,將povit放中間。處理後,陣列l到r的資料分成了3部分,l到p-1之間到資料都是小於povit的,povit在中間,後面p+1到r的資料都是大於povit的。

用遞迴排序下標l到p-1之間的資料和p+1到r之間的資料,直到區間縮小為1,這時陣列就有序了。

遞迴公式:

quick_sort(l…r) = quick_sort(l…p-1) + quick_sort(p+1…r)

終止條件:

l>=r

參考**

php版

class

quicksort

private

function

quicksortinternally

(array

&$arr

, int $l

, int $r)}

/** 交換陣列元素,使樞軸記錄到位,並返回其所在位置 */

/** 此時在樞軸記錄前的資料都小於它,在其後的資料都大於它 */

private

function

partition

(array

&$arr

, int $l

, int $r

)//比樞軸記錄小的交換到左邊

$this

->

swap

($arr

,$left

,$right);

while

($left

<

$right

&&$pivot

>=

$arr

[$left])

//比樞軸記錄大大交換到右邊

$this

->

swap

($arr

,$left

,$right);

}//返回樞軸現在位置

return

$left;}

private

function

swap(&

$arr,$i

,$j)}

效能分析

時間複雜度

平均情況:o(nlogn)

最好情況:每次分割槽都能把陣列劃分成2個接近相等的小區間,為o(nlogn),

最壞情況:待排序的資料已為正序或逆序,每次劃分只得到乙個比上一次劃分少乙個記錄的子區間,另乙個為空。為o(n^2)

空間複雜度

平均情況:o(logn)

最好情況:o(logn)

最壞情況:需進行n-1次呼叫,為o(n)

快速排序優化

優化選取樞軸

如三數取中法:取三個關鍵字先進行排序,將中間數作為樞軸。一般從區間取左端、右端和中間三個數。從概率上看,取三個數均為最小或最大可能性很小,因此中間數字於中間值大可能性就提高了。

// 三數取中法

private

function

partition2

(array

&$arr

, int $left

, int $right)if

($arr

[$middle

]>

$arr

[$right])

if($arr

[$middle

]>

$arr

[$left])

$pivot

=$arr

[$left];

//...

}

優化小陣列時排序方案,如果陣列非常小,快速排序反而不如插入排序好(直接插入是簡單排序中效能最好的)。原因是快速排序用到了遞迴操作,在大量資料排序時,這點效能影響相對演算法優點可以忽略。

優化遞迴操作,對quicksortinternally實行尾遞迴優化(採用迭代可以縮減堆疊深度)

private

function

quicksortinternally1

(array

&$arr

, int $l

, int $r

)}

優化不必要的交換

private

function

partition(&

$arr

,$left

,$right

)//交換資料

$arr

[$left]=

$arr

[$right];

while

($left

<

$right

&&$pivot

>=

$arr

[$left])

//交換資料

$arr

[$right]=

$arr

[$left];

}$arr

[$left]=

$tmp

;//返回樞軸現在位置

return

$left

;}

partition方法優化,上面的例子while迴圈裡還就行了2次while迴圈,可進一步優化

function

partition

(array

&$arr

,$left

,$right)}

$this

->

swap

($arr,$i

,$right);

return$i;

}

面試相關

有時候面試會遇到這樣的問題:o(n)時間複雜度求無序陣列中第k大元素。比如2,1,9,5,7這樣一組資料,第3大元素就是5。

思路:選擇陣列a[0…n]第乙個元素作為point,對陣列a進行分割槽,這樣陣列就成了3部分,a[0…p-1],a[p],a[p+1…n-1]。

如果arr.length - p = k,那麼a[p]就是要求解的元素;

如果arr.length - p < k,那麼元素出現在a[0…p-1]區間,在a[0…p-1]這個區間查詢;

如果arr.length - p > k,則在a[p+1…arr.length-1]區間查詢。

時間複雜度分析:第一次分割槽查詢,對大小為n的陣列進行分割槽操作,遍歷n個元素。第二次分割槽查詢,只需對n/2個元素進行分割槽操作,遍歷n/2個元素。以此類推,分割槽遍歷對元素個數為n/2、n/4、n/8、一直到1。把元素個數相加n+n/2+n/4+…+1和為2n-1。時間複雜度為o(n)。

參考**

/**

* 查詢第k大元素

* @param array $arr

* @param int $k

* @return 第k大元素在陣列中下標

*/public

function

findkmax

(array

&$arr

, int $k)if

($k<

$left

||$k

>

$right+1

)$pivot

=$this

->

partition

($arr

,$left

,$right);

//陣列中大於等於pivot的元素個數

$right_num

=count

($arr)-

$pivot

;while

($right_num

!=$k

)else

$right_num

=count

($arr)-

$pivot;}

return

$pivot

;}

查詢第k小元素

參考**

public

function

findkmin

($arr,$k

)if($k

<1||

$k>

$right+1

)$pivot

=$this

->

partition

($arr

,$left

,$right);

while

($pivot

!=$k-1

)else

}return

$pivot

;}

氣泡排序 通俗易懂

氣泡排序是一種簡單的排序演算法,它也是一種穩定排序演算法。其實現原理是重複走訪過要排序的元素列,依次比較兩個相鄰的元素,如果當該對元素順序不正確時進行交換過來。一直重複這個過程,直到沒有任何兩個相鄰元素可以交換,就表明完成了排序。注意 一般情況下,稱某個排序演算法穩定 指的是當待排序序列中有相同的元...

字典排序演算法(通俗易懂)

我們先看乙個例子。示例 1 2 3的全排列如下 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 我們這裡是通過字典序法找出來的。那麼什麼是字典序法呢?從上面的全排列也可以看出來了,從左往右依次增大,對這就是字典序法。可是如何用演算法來實現字典序法全排列呢?你主要看紅色字型部分...

Druid通俗易懂的快速入門

通俗點來說它是個不但繼承了tomcat dbcp2資料庫連線池的優點,還支援擴充套件外掛程式的資料庫連線池,其中最常用的三個外掛程式 start wall log4j帶給druid強大的後台監控 防禦sql注入和日誌等功能。再簡單點來說,它會有乙個自己的後台監控頁面,像這樣 依賴 com.aliba...