java基數排序

2021-06-02 14:17:21 字數 4173 閱讀 4750

(radixsort)則是屬於「分配式排序」(distribution sort),基數排序法又稱「桶子法」(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些「桶」中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間複雜度為o (nlog(r)m),其中r為所採取的基數,而m為堆數,在某些時候,基數排序法的效率高於其它的比較性排序法。

基數排序(radix sort)是一種非比較型整數排序演算法,其原理是將整數按位數切割成不同的數字,然後按每個位數分別比較。由於整數也可以表達字串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是只能使用於整數。基數排序的發明可以追溯到2023年赫爾曼·何樂禮在打孔卡片製表機(tabulation machine)上的貢獻[1]。

它是這樣實現的: 將所有待比較數值(正整數)統一為同樣的數字長度,數字較短的數前面補零. 然後, 從最低位開始, 依次進行一次排序.這樣從最低位排序一直到最高位排序完成以後, 數列就變成乙個有序序列.

基數排序的方式可以採用lsd(least significantdigital)或msd(most significantdigital),lsd的排序方式由鍵值的最右邊開始,而msd則相反,由鍵值的最左邊開始。

以lsd為例,假設原來有一串數值如下所示:

73,22, 93, 43, 55, 14, 28, 65, 39, 81

首先根據個位數的數值,在走訪數值時將它們分配至編號0到9的桶子中:

1 81

2 22

3 73 93 43

4 14

5 55 65

8 28

9 39

接下來將這些桶子中的數值重新串接起來,成為以下的數列:

81,22, 73, 93, 43, 14, 55, 65, 28, 39

接著再進行一次分配,這次是根據十位數來分配:

1 14

2 22 28

3 39

4 43

5 55

6 65

7 73

8 81

9 93

接下來將這些桶子中的數值重新串接起來,成為以下的數列:

14,22, 28, 39, 43, 55, 65, 73, 81, 93

這時候整個數列已經排序完畢;如果排序的物件有三位數以上,則持續進行以上的動作直至最高位數為止。

lsd的基數排序適用於位數小的數列,如果位數多的話,使用msd的效率會比較好,msd的方式恰與lsd相反,是由高位數為基底開始進行分配,其他的演算方式則都是相同。

效率

基數排序的時間複雜度是 o(k·n),其中n是排序元素個數,k是數字位數。注意這不是說這個時間複雜度一定優於o(n·log(n)),因為k的大小一般會受到 n 的影響。 以排序n個不同整數來舉例,假定這些整數以b為底,這樣每位數都有b個不同的數字,k就一定不小於logb

(n)。由於有b個不同的數字,所以就需要b個不同的桶,在每一輪比較的時候都需要平均n·log2(b) 次比較來把整數放到合適的桶中去,所以就有:

所以,基數排序的平均時間t就是:

t ≥logb(n)·n·log2(b) = log2(n)·logb(2)·n·log2(b)= log2(n)·n·logb

(2)·log2(b) = n·log2(n)

所以和比較排序相似,基數排序需要的比較次數:t ≥ n·log2(n)。故其時間複雜度為ω(n·log2(n)) = ω(n·log n) 。

時間效率:設待排序列為n個記錄,d個關鍵碼,關鍵碼的取值範圍為radix,則進行鏈式基數排序的時間複雜度為o(d(n+radix)),其中,一趟分配時間複雜度為o(n),一趟收集時間複雜度為o(n),共進行d趟分配和收集。 空間效率:需要2*radix個指向佇列的輔助空間,以及用於靜態鍊錶的n個指標。

實現的方法

最高位優先(most significant digit first)法,簡稱msd法:先按k1排序分組,同一組中記錄,關鍵碼k1相等,再對各組按k2排序分成子組,之後,對後面的關鍵碼繼續這樣的排序分組,直到按最次位關鍵碼kd對各子組排序後。再將各組連線起來,便得到乙個有序序列。

最低位優先(least significant digit first)法,簡稱lsd法:先從kd開始排序,再對kd-1進行排序,依次重複,直到對k1排序後便得到乙個有序序列。

使用範圍

基數排序從低位到高位進行,使得最後一次計數排序完成後,陣列有序。

其原理在於對於待排序的資料,整體權重未知的情況下,先按權重小的因子排序,然後按權重大的因子排序。例如比較時間,先按日排序,再按月排序,最後按年排序,僅需排序三次。

但是如果先排序高位就沒這麼簡單了。

基數排序源於老式穿孔機,排序器每次只能看到乙個列,

很多教科書上的基數排序都是對數值排序,數值的大小是已知的,與老式穿孔機不同。

將數值按位拆分再排序,是無聊並自找麻煩的事。

演算法的目的是找到最佳解決問題的方案,而不是把簡單的事搞的更複雜。

基數排序更適合用於對時間、字串等這些整體權值未知的資料進行排序。

這時候基數排序的思想才能體現出來,例如字串,如果從高位(第一位)往後排就很麻煩。

而反過來,先對影響力較小,排序排重因子較小的低位(最後一位)進行排序就非常簡單了。

這時候基數排序的思想就能體現出來。

又或者所有的數值都是以字串形式儲存,就象穿孔機一樣,每次只能對一列進行排序。

這時候基數排序也適用,例如:對進行排序

下面我們使用基數排序對字串進行排序。

對每個位迴圈呼叫計數排序。

基數排序的缺點:

不呈現時空區域性性,因為在按位對每個數進行排序的過程中,乙個數的位置可能發生巨大的變化,所以不能充分利用現代機器快取提供的優勢。同時計數排序作為中間穩定排序的話,不具有原地排序的特點,當記憶體容量比較寶貴的時候,還是有待商榷。

例項說明

package com.test.sort;

public class radixsort ;

for(int i = 0; i < data.length; i++) ;

print(data);

// 4:最大數的位數

radixsort(data, data.length, 4);

system.out.println("排序後的陣列:");

print(data);

publicstatic void radixsort(int data, int radix, int d) {

// 快取陣列

inttmp = new int[data.length];

//buckets用於記錄待排序元素的資訊

//buckets陣列定義了max-min個桶

intbuckets = new int[radix];

for(int i = 0, rate = 1; i < d; i++) {

//重置count陣列,開始統計下乙個關鍵字

arrays.fill(buckets, 0);

//將data中的元素完全複製到tmp陣列中

system.arraycopy(data, 0, tmp, 0, data.length);

//計算每個待排序資料的子關鍵字

for (int j = 0; j < data.length; j++) {

int subkey = (tmp[j] / rate) % radix;

buckets[subkey]++;

for (int j = 1; j < radix; j++) {

buckets[j] = buckets[j] + buckets[j - 1];

//按子關鍵字對指定的資料進行排序

for (int m = data.length - 1; m >= 0; m--) {

int subkey = (tmp[m] / rate) % radix;

data[--buckets[subkey]] = tmp[m];

rate *= radix;

publicstatic void print(int data) {

for(int i = 0; i < data.length; i++) {

system.out.print(data[i] +"\t");

system.out.println();

Java 基數排序

基數排序 radix sort 屬於 分配式排序 distribution sort 又稱 桶子法 bucket sort 或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些 桶 中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間複雜度為o nlog r m 其...

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

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

Java實現基數排序

在眾多的排序方法中基數排序比較特殊,它是一種不需要進行關鍵字之間比較的排序方法,利用多關鍵字的劃分,逐漸將待排序列排好序。舉個例子 現在有陣列 278,109,63,930,589,184,505,269,8,83 第一次根據各位數將陣列劃分為10個佇列 當然其中的某些佇列可能不含有元素 0 930...