快速排序思想
排序陣列(下標從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...