演算法筆記 桶排序 計數排序 基數排序

2022-07-02 19:00:13 字數 3828 閱讀 5750

三種時間複雜度是 o(n) 的排序演算法:桶排序、計數排序、基數排序。因為這些排序演算法的時間複雜度是線性的,所以我們把這類排序演算法叫作線性排序(linear sort)。

桶排序(bucket sort)

將要排序的資料分到幾個有序的桶裡,每個桶裡的資料再單獨進行排序。桶內排完序之後,再把每個桶裡的資料按照順序依次取出,組成的序列就是有序的了。

桶排序對要排序資料的要求是非常苛刻的。首先,要排序的資料需要很容易就能劃分成 m 個桶,並且,桶與桶之間有著天然的大小順序。這樣每個桶內的資料都排序完之後,桶與桶之間的資料不需要再進行排序。其次,資料在各個桶之間的分布是比較均勻的。如果資料經過桶的劃分之後,有些桶裡的資料非常多,有些非常少,很不平均,那桶內資料排序的時間複雜度就不是常量級了。在極端情況下,如果資料都被劃分到乙個桶裡,那就退化為 o(nlogn) 的排序演算法了。

桶排序比較適合用在外部排序中。所謂的外部排序就是資料儲存在外部磁碟中,資料量比較大,記憶體有限,無法將資料全部載入到記憶體中。

//

先引用之前的 快排的**

function quicksort(array &$a)

function quicksortinternally(array &$a, int $l, int

$r)function partition(&$a, $l, $r): int

}[$a[$r], $a[$i]] =[$a[$i], $a[$r]];

return

$i;}/**

* 桶排序

* 假設乙個桶只能放置10個元素

* 當乙個桶內元素過多,需要繼續分桶

* @param array $numbers

* @param [type] $size

* * @return void

* @date 2018/11/25

* @author yuanliandu */

function bucketsort(array $numbers)

$result =;

for($i=0;$i

if( $length > 10

) quicksort($bucket,

0,count($bucket)-1

); $result =array_merge($result,$bucket);

}return

$result;

}$numbers = [11, 23, 45, 67, 88, 99, 22, 34, 56, 78, 90, 12, 34, 5, 6, 91, 92, 93, 93, 94, 95, 94, 95, 96, 97, 98, 99, 100

];$size = 10

;print_r(bucketsort($numbers,

10));

計數排序(counting sort)—— 其實是桶排序的一種特殊情況

當要排序的 n 個資料,所處的範圍並不大的時候,比如最大值是 k,我們就可以把資料劃分成 k 個桶。每個桶內的資料值都是相同的,省掉了桶內排序的時間

計數排序只能用在資料範圍不大的場景中,如果資料範圍 k 比要排序的資料 n 大很多,就不適合用計數排序了。而且,計數排序只能給非負整數排序,如果要排序的資料是其他型別的,要將其在不改變相對大小的情況下,轉化為非負整數。

問題:如何根據年齡給100萬使用者資料排序?

我們假設年齡的範圍最小 1 歲,最大不超過 120 歲。我們可以遍歷這 100 萬使用者,根據年齡將其劃分到這 120個桶裡,然後依次順序遍歷這 120 個桶中的元素。這樣就得到了按照年齡排序的 100 萬使用者資料。

<?php /**

* 計數排序

* 五分制

* 13個人 */

$score = [0, 1, 5, 3, 2, 4, 1, 2, 4, 2, 1, 4, 4

];print_r(countingsort($score));

function countingsort(array $score)

/*** 統計每個分數的人數

*/$temp =;

$countscore =;

foreach ($score as $key =>$value)

/*** 順序求和

*/for ($i = 1; $i <= 5; $i++)

/*** 排序

*/foreach ($score as $key =>$value)

//copy

for ($i = 0; $i < $length; $i++)

return

$score;

}

基數排序(radix sort)

假設有 10 萬個手機號碼,希望將這 10 萬個手機號碼從小到大排序,你有什麼比較快速的排序方法呢?

有這樣的規律:假設要比較兩個手機號碼 a,b 的大小,如果在前面幾位中,a手機號碼已經比 b 手機號碼大了,那後面的幾位就不用看了。

基數排序對要排序的資料是有要求的,需要可以分割出獨立的「位」來比較,而且位之間有遞進的關係,如果 a 資料的高位比 b 資料大,那剩下的低位就不用比較了。除此之外,每一位的資料範圍不能太大,要可以用線性排序演算法來排序,否則,基數排序的時間複雜度就無法做到 o(n) 了。 

<?php /**

* 基數排序

* 先根據個位排序、百位、千位........ */

$numbers =[

1234

,

4321

, 12,

31,412,

];$max = (string)max($numbers);//

求出最大數字

$loop = strlen($max);//

計算最大數字的長度,決定迴圈次數

for ($i = 0; $i < $loop; $i++)

print_r($numbers);/**

* 基數排序

* @param array $numbers

* @param [type] $loop */

function radixsort(array &$numbers, $loop)

/*** 從桶中取出數字

*/$k = 0

;

for ($i = 0; $i < 10; $i++) }}

如何實現乙個通用的、高效能的排序函式?

快速排序比較適合來實現排序函式,如何優化快速排序?最理想的分割槽點是:被分割槽點分開的兩個分割槽中,資料的數量差不多。為了提高排序演算法的效能,要盡可能地讓每次分割槽都比較平均。

①從區間的首、中、尾分別取乙個數,然後比較大小,取中間值作為分割槽點。

②如果要排序的陣列比較大,那「三數取中」可能就不夠用了,可能要「5數取中」或者「10數取中」。

①限制遞迴深度,一旦遞迴超過了設定的閾值就停止遞迴。

②在堆上模擬實現乙個函式呼叫棧,手動模擬遞迴壓棧、出棧過程,這樣就沒有系統棧大小的限制。

通用排序函式實現技巧

1.資料量不大時,可以採取用時間換空間的思路

2.資料量大時,優化快排分割槽點的選擇

3.防止堆疊溢位,可以選擇在堆上手動模擬呼叫棧解決

4.在排序區間中,當元素個數小於某個常數是,可以考慮使用o(n^2)級別的插入排序

5.用哨兵簡化**,每次排序都減少一次判斷,盡可能把效能優化到極致 

桶排序 基數排序 計數基數排序 Java

前面已經講述了很多排序演算法,但是他們的排序演算法都是基於兩個值之間的比較,通過決策樹的方法可以證明深度為d的二叉樹則最多有 一些好的排序演算法是可以達到時間複雜度是線性的,桶排序就是其中一種。比如有n個數,但是這些數的最大數不超過m。這個時候就可以定義乙個含有m個元素的陣列 初始值為0 然後遍歷n...

桶排序 基數排序 計數排序

桶排序 1.原理 將需要排序的陣列分在有限的桶裡 然後對每個桶中的數分別排序 對每個桶的操作 1.別的排序演算法 2.以遞迴的方式繼續使用桶排序 2.過程 假設待排序的一組數統一的分布在乙個範圍中,並將這一範圍劃分成幾個子範圍,也就是桶 將待排序的一組數,分檔規入這些子桶,並將桶中的資料進行排序 將...

演算法 桶排序思想 計數排序 基數排序 桶排序

二.基數排序 三.桶排序 桶排序的思想 量大但範圍最小 既能用陣列下標表示 整數 且 有很多是並列的 其他情況不一定比快速排序快。總結 include using namespace std const int m 50 const int scope 60 void main delete arr...