天天看點

java排序算法複雜度_常用的排序算法(Java版)

注:以下内容為筆者學習《Java程式員的基本修養》一書的學習筆記

概述:

排序是程式開發中一種非常常見的操作,指對一組任意的資料元素(或記錄)經過排序操作後,将它們變成一組按關鍵字排序的有序序列。

一旦将一組雜亂無章的記錄重排成一組有序記錄,就能快速地從這組記錄中找到目标記錄。

衡量排序算法(sorting algorithm)優劣的三個方面:時間複雜度:主要分析關鍵字的比較次數和記錄的移動次數

空間複雜度:分析排序算法中需要多少輔助記憶體

穩定性:若兩個記錄A和B的關鍵字值相等,但排序後A、B的先後次序保持不變,則稱這種排序算法是穩定的;反之就是不穩定的。

分類:内部排序(整個排序過程不需要借助于外部存儲器(如磁盤等),所有排序操作都在記憶體中完成)

主要分為:選擇排序

交換排序

插入排序

歸并排序

桶式排序

基數排序

外部排序(參與排序的資料元素非常多,資料量非常大,計算機排序時必須借助于外部存儲器)

常用的算法是多路歸并排序,即将原檔案分解成多個能夠一次性裝入記憶體的部分,分别将每一部分調入記憶體完成排序,接下來再對多個有序的子檔案進行歸并排序。

具體步驟:把兩個檔案中的一組記錄讀入記憶體的排序區,對讀入的記錄按上面講到的内部排序法進行排序,排序之後輸出到外部存儲器。不斷重複這一過程,每次讀取一組記錄,直到源檔案的所有記錄被處理完畢。

将上一步分組排序好的記錄兩組兩組的合并排序。在記憶體容量允許的情況下,每組中包含的記錄越大越好,以減少合并次數。

[選擇排序法]直接選擇排序

該排序算法思路簡單,需要經過n-1趟比較。

第1趟:程式将記錄定位在第一個資料上,拿第1個資料依次和它後面的每一個資料進行比較,如果第1個資料大于後面某個資料,就交換它們......,以此類推。經過第1趟比較,這組資料中最小的資料被選出,被排在第1位。

第2趟:程式将記錄定位在第二個資料上,拿第2個資料依次和它後面的每一個資料進行比較,如果第2個資料大于後面某個資料,就交換它們......,以此類推。經過第2趟比較,這組資料中第二小的資料被選出,被排在第2位。

......

從上面描述可知,直接選擇排序算法的關鍵就是n-1趟比較,每趟比較的目的就是選出本趟比較中最小的資料,并将該資料放在本趟比較的第1位。

示例代碼:

package com.atschool;

import java.util.Arrays;

class DataWrap implements Comparable{

int data;

String flag;

public DataWrap(int data,String flag){

this.data = data;

this.flag = flag;

}

@Override

public String toString() {

return data + flag;

}

@Override

public int compareTo(DataWrap o) {

return this.data > o.data ? 1 : (this.data == o.data ? 0 : -1);

}

}

public class SelectSort {

public static void selectSort(DataWrap[] dataWraps){

System.out.println("開始排序");

int arrayLen = dataWraps.length;

for (int i = 0; i < arrayLen - 1; i++) {

int minIndex = i;

for (int j = i + 1; j < arrayLen; j++) {

if (dataWraps[minIndex].compareTo(dataWraps[j]) > 0){

minIndex = j;

}

}

if (minIndex != i){

DataWrap tmp = dataWraps[i];

dataWraps[i] = dataWraps[minIndex];

dataWraps[minIndex] =tmp;

}

System.out.println(Arrays.toString(dataWraps));

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(49,""),

new DataWrap(30,""),

new DataWrap(16,""),

new DataWrap(9,""),

new DataWrap(10,""),

new DataWrap(3,"")

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

selectSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}

直接選擇排序算法:時間複雜度: O(n * n)

空間複雜度: O(1)

穩定性: 不穩定

2. 堆排序

概念:

假設有N個資料元素的序列k0,k1,......,kn-1,當且僅當滿足如下關系時,可以将這組資料稱為小頂堆(小根堆),将滿足小頂堆的資料序列順序排成一顆完全二叉樹,則此樹所有節點的值都小于其左右子節點的值。此數的根節點的值必定最小。

ki <= k2i + 1 且 ki <= k2i + 2(其中i=0,2,......,(n-1)/2)

或者,滿足如下關系時,可以将這組資料稱為大頂堆(大根堆),将滿足大頂堆的資料序列順序排成一顆完全二叉樹,則此樹所有節點的值都大于其左右子節點的值。此數的根節點的值必定最大。

ki >= k2i + 1 且 ki >= k2i + 2(其中i=0,2,......,(n-1)/2)

堆排序算法的思路:建堆先将要排序的數組轉換為完全二叉樹。

從完全二叉樹的最後一個非葉子節點開始,保證該節點的值大于等于其左、右子節點的值。如果其子節點的值大于它本身的值,則把它和較大的子節點進行交換。最後一個節點的索引為數組長度-1,即len-1,則最後一個非葉子節點的索引應該為(len-2)/2。

向前處理前一個非葉子節點(索引為(len-2) / 2 - 1)。

向前處理前一個非葉子節點,若某個節點和它的某個子節點交換後,該子節點又有子節點,那麼系統還需要再次對該子節點進行判斷。

2. 拿堆的根節點和最後一個節點交換

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class HeapSort {

public static void heapSort(DataWrap[] dataWraps) {

System.out.println("開始排序");

int arrayLen = dataWraps.length;

for (int i = 0; i < arrayLen - 1; i++) {

buildMaxdHeap(dataWraps,arrayLen - 1 - i);

swap(dataWraps,0,arrayLen - 1 - i);

System.out.println(Arrays.toString(dataWraps));

}

}

private static void swap(DataWrap[] dataWraps, int initialIndex, int newIndex) {

DataWrap tmp = dataWraps[initialIndex];

dataWraps[initialIndex] = dataWraps[newIndex];

dataWraps[newIndex] = tmp;

}

private static void buildMaxdHeap(DataWrap[] dataWraps, int lastIndex) {

for (int i = (lastIndex - 1) / 2; i >= 0 ; i--) {

// 儲存目前正在判斷的節點 int k = i;

while (k * 2 + 1 <= lastIndex){

int biggerIndex = 2 * k + 1;

if (biggerIndex < lastIndex){

if (dataWraps[biggerIndex].compareTo(dataWraps[biggerIndex + 1]) < 0){

biggerIndex++;

}

}

if (dataWraps[k].compareTo(dataWraps[biggerIndex]) < 0){

swap(dataWraps,k,biggerIndex);

k = biggerIndex;

}else {

break;

}

}

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(49,""),

new DataWrap(30,""),

new DataWrap(45,""),

new DataWrap(12,""),

new DataWrap(33,""),

new DataWrap(21,""),

new DataWrap(16,""),

new DataWrap(9,""),

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

heapSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}

對于堆排序算法來說,假設有n個資料,需要進行n-1次建堆,每次建堆本身耗時為log2n,并且需要一個附加程式單元用于交換。是以:時間複雜度:O(n *

java排序算法複雜度_常用的排序算法(Java版)

)

空間複雜度:O(1)

穩定性: 不穩定

[交換排序法]

交換排序的主體操作是對資料組中的資料不斷地進行交換操作。交換操作主要有冒泡排序和快速排序。冒泡排序

冒泡排序是最廣為人知的交換排序之一,具有算法思路簡單、容易實作的特點。

冒泡排序的執行步驟并不固定。假設對包含n個資料的一組記錄進行排序,在最壞的情況下,需要進行n-1趟比較:依次比較0和1、1和2、2和3、......、n-2和n-1索引處的元素,如果發現第一個資料大于後一個資料,則交換它們。經過第一趟比較,最大的元素排到了最後。

依次比較0和1、1和2、2和3、......、n-3和n-2索引處的元素,如果發現第一個資料大于後一個資料,則交換它們。經過第二趟比較,第二大的元素排到了倒數第2位。

......

第n-1趟依次比較0和1索引處的元素,如果發現第一個資料大于後一個資料,則交換它們。經過第n-1趟比較,第2小(第n-1)大的元素排到了第二位。

實際上,冒泡排序的每趟交換結束後,不僅能将目前最大值擠出最後面位置,還能部分理順前面的其他元素;一旦某趟沒有交換發生,即可提前結束排序。

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class BubbleSort {

public static void bubbleSort(DataWrap[] dataWraps){

System.out.println("開始排序");

int arrayLen = dataWraps.length;

for (int i = 0; i < arrayLen - 1; i++) {

boolean flag = false;

for (int j = 0; j < arrayLen - 1 - i; j++) {

if (dataWraps[j].compareTo(dataWraps[j + 1]) > 0){

DataWrap tmp = dataWraps[j + 1];

dataWraps[j + 1] = dataWraps[j];

dataWraps[j] = tmp;

flag = true;

}

}

System.out.println(Arrays.toString(dataWraps));

if (!flag){

break;

}

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(9,""),

new DataWrap(16,""),

new DataWrap(21,""),

new DataWrap(23,""),

new DataWrap(30,""),

new DataWrap(49,""),

new DataWrap(21,""),

new DataWrap(30,"")

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

bubbleSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}

冒泡排序算法的時間效率是不确定的:在最好的情況下:初始資料序列已經處于有序狀态,執行1趟冒泡即可,做n-1次比較,無須任何交換。

在最壞的情況下:初始資料序列處于完全逆序狀态,算法要執行n-1趟冒泡,第i趟做了n-i次比較,執行n-i-1次對象交換。此時的比較總次數為n * (n -1) / 2,記錄移動總次數為n * (n - 1) * 3 / 2。時間複雜度: 不确定

空間複雜度: O(1)

穩定性: 穩定

2. 快速排序

總體步驟:選出指定的分界的值

将所有比分界值小的資料元素放在左邊

将所有比分界值大的資料元素放在右邊

第2、3步具體步驟:定義一個i變量,i變量從左邊第一個索引開始,找大于分界值的元素的索引,并用i來記錄它。

定義一個j變量,j變量從右邊第一個索引開始,找小于分界值的元素的索引,并用j來記錄它。

如果i < j,則交換i、j兩個索引處的元素。

重複執行以上1~3步,直到i >= j,可以判斷j左邊的資料元素都小于分界值,j右邊的資料元素都大于分界值,最後将分界值和j索引處的元素交換即可。

示例代碼:

package com.atschool.algothrim;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class QuickSort {

private static void swap(DataWrap[] dataWraps, int i, int j){

DataWrap tmp = dataWraps[i];

dataWraps[i] = dataWraps[j];

dataWraps[j] = tmp;

}

private static void subSort(DataWrap[] dataWraps, int start, int end){

if (start < end){

DataWrap base = dataWraps[start];

int i = start;

int j = end + 1;

while (true){

while(i < end && dataWraps[++i].compareTo(base) <= 0);

while(j > start && dataWraps[--j].compareTo(base) >= 0);

if (i < j){

swap(dataWraps,i,j);

}else {

break;

}

}

swap(dataWraps,start,j);

subSort(dataWraps,start,j - 1);

subSort(dataWraps, j + 1, end);

}

}

public static void quickSort(DataWrap[] dataWraps){

subSort(dataWraps,0,dataWraps.length - 1);

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(9,""),

new DataWrap(-16,""),

new DataWrap(21,""),

new DataWrap(23,""),

new DataWrap(-30,""),

new DataWrap(-49,""),

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(13,""),

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

quickSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}時間複雜度: 較好

空間複雜度: O(

java排序算法複雜度_常用的排序算法(Java版)

)

穩定性: 包含跳躍式交換,不穩定

[插入排序法]直接插入排序

思路:

依次将待排序的資料元素按其關鍵字值的大小插入前面的有序序列。

具體步驟:(假設有一個擁有n個元素的資料序列,排序需要進行n-1趟插入操作)将第2個元素插入前面的有序子序列中,此時前面隻有一個元素,當然是有序的

将第3個元素插入前面的有序子序列中,前面兩個元素是有序的

......

n-1. 将第n個元素插入前面的有序子序列中,前面n-1個元素是有序的。

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class InsertSort {

public static void insertSort(DataWrap[] dataWraps){

System.out.println("開始排序:");

int arrayLen = dataWraps.length;

for (int i = 1; i < arrayLen; i++) {

DataWrap tmp = dataWraps[i];

if (dataWraps[i].compareTo(dataWraps[i - 1]) < 0){

int j = i - 1;

for (; j >= 0 && dataWraps[j].compareTo(tmp) > 0 ; j--) {

dataWraps[j+1] = dataWraps[j];

}

dataWraps[j + 1] = tmp;

}

System.out.println(Arrays.toString(dataWraps));

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(9,""),

new DataWrap(-16,""),

new DataWrap(21,""),

new DataWrap(23,""),

new DataWrap(-30,""),

new DataWrap(-49,""),

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(30,"")

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

insertSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}時間複雜度: O(n * n)

空間複雜度: O(1)

穩定性: 穩定

2. 折半插入排序

是對直接插入排序的簡單改進。對于直接插入排序而言,當第i-1趟需要将第i個元素插入前面的0~i-1個元素的序列中時,它總是從i-1個元素開始,逐個比較每個元素,直到找到它的位置。

排序思路:

當第i-1趟需要将第i個元素插入前面的0~i-1個元素序列中時,它不會直接從i-1個元素開始逐個比較每個元素。而是:計算0~i-1索引的中間點,也就是用i索引處的元素和(0 + i - 1)/2索引處的元素進行比較,如果i索引處的元素大,就直接在(0+i-1) / 2 ~ i-1半個範圍内搜尋;反之,就在0 ~ (0 + i -1)/2半個範圍内搜尋,這就是所謂的折半

在半個範圍内搜尋時,再按第1步方法進行折半搜尋。

總是不斷折半,這樣就可以将搜尋範圍縮小到1/2、1/4、1/8。進而快速确定第i個元素的插入位置

一旦确定了第i個元素的插入位置,程式将該位置以後的元素整體後移一位,然後将第i個元素放入該位置

排序效果和直接插入基本相同,不過速度更快一些。

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class BinaryInsertSort {

public static void binaryInsertSort(DataWrap[] dataWraps){

System.out.println("開始排序:\n");

int arrayLen = dataWraps.length;

for (int i = 1; i < arrayLen; i++) {

DataWrap tmp = dataWraps[i];

int low = 0;

int high = i -1;

while (low <= high){

int mid = (low + high) / 2;

if (tmp.compareTo(dataWraps[mid]) > 0){

low = mid + 1;

}else {

high = mid -1;

}

}

for (int j = i; j > low; j--) {

dataWraps[j] = dataWraps[j-1];

}

dataWraps[low] = tmp;

System.out.println(Arrays.toString(dataWraps));

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(9,""),

new DataWrap(-16,""),

new DataWrap(21,""),

new DataWrap(23,""),

new DataWrap(-30,""),

new DataWrap(-49,""),

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(30,""),

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

binaryInsertSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}時間複雜度: O(n * n)

空間複雜度: O(1)

穩定性: 穩定

3. Shell排序

基本思路:通過加大插入排序中元素之間的間隔,并在這些有間隔的元素中進行插入排序,進而使資料項大跨度地移動。這些資料項排過一趟序後,Shell排序算法減少資料項的間隔再進行排序,依次進行下去。這些進行排序的資料項之間的間隔被稱為增量,習慣上用h來表示這個增量。

例如:

假設有一個包含9項資料的序列,當h增量為4時,第1趟将保證索引為0、4、8的資料元素已經有序。第1趟完成後,算法向右移一步,對索引為1、5的資料元素進行排序。這個排序過程持續進行,直到所有的資料項都已經完成了以4為增量的排序。即,所有間隔為4的資料項之間都已經排列有序。接下來應該減少增量,直到完成以1為增量的shell排序,此時資料序列将會變為有序序列。

特點:完成某個增量的排序後,相關元素達到基本有序的狀态

通過建立交錯的内部有序的資料項集合,減少直接插入排序中資料項“整體搬家”的工作量

從上面描述可知:

最終确定Shell排序算法的關鍵就在于确定h序列的值。常用的h序列由Knuth提出,該序列從1開始,通過如下公式産生:

h = 3 * h + 1

比直接插入排序更高效的原因:當h值大的時候,資料項每一趟排序需要移動元素的個數很少,但資料項移動的距離很長

當h減小時,每一趟排序需要移動的元素的個數增多,但此時資料項已經接近于它們排序後最終的位置,資料項移動的距離短。

直接插入排序是以1為增量的Shell排序

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class ShellSort {

public static void shellSort(DataWrap[] dataWraps){

System.out.println("開始排序:");

int arrayLen = dataWraps.length;

int h = 1;

while (h <= arrayLen / 3){

h = h * 3 + 1;

}

while (h > 0){

System.out.println("=======h的值:" + h + "======");

for (int i = h; i < arrayLen; i++) {

DataWrap tmp = dataWraps[i];

if (dataWraps[i].compareTo(dataWraps[i - h]) < 0){

int j = i - h;

for (; j >= 0 && dataWraps[j].compareTo(tmp) > 0 ; j-= h) {

dataWraps[j + h] = dataWraps[j];

}

dataWraps[j + h] = tmp;

}

System.out.println(Arrays.toString(dataWraps));

}

h = (h - 1) / 3;

}

}

public static void main(String[] args) {

DataWrap[] dataWrap = {

new DataWrap(9,""),

new DataWrap(-16,""),

new DataWrap(21,""),

new DataWrap(23,""),

new DataWrap(-30,""),

new DataWrap(-49,""),

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(30,"")

};

System.out.println("排序之前:\n" + Arrays.toString(dataWrap));

shellSort(dataWrap);

System.out.println("排序之後:\n" + Arrays.toString(dataWrap));

}

}時間複雜度: O(

java排序算法複雜度_常用的排序算法(Java版)

) ~ O(

java排序算法複雜度_常用的排序算法(Java版)

)

空間複雜度: O(1)

穩定性: 穩定

[歸并排序法]

思路:

将兩個(或以上)有序的序列合并成一個新的有序序列。

大概步驟:

先将程度為n的無序序列看成是n個長度為1的有序子序列,首先做到兩兩合并,得到n/2個長度為2的有序子序列,再做兩兩合并......,不斷地重複這個過程,最終可以得到一個長度為n的有序序列。也就是說,對于長度為n的資料序列,隻需經過log2n次合并。

具體步驟:定義變量i,i從0開始,依次等于A序列中每個元素的索引

定義變量j,j從0開始,依次等于B序列中每個元素的索引

拿A序列中i索引處的元素和B序列中j索引處的元素進行比較,将較小的複制到一個臨時數組

如果i索引處的元素小,則i++;如果j索引處的元素小,則j++

不斷地重複上面四個步驟,即可将A、B兩個序列中的資料元素複制到臨時數組中,直到其中一個數組中的所有元素都被複制到臨時數組中。最後将另一個數組中剩餘的元素全部複制到臨時數組中,合并即完成,再将臨時數組中的資料複制回去即可。

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class MergeSort {

public static void mergeSort(DataWrap[] dataWraps) {

sort(dataWraps,0,dataWraps.length - 1);

}

private static void sort(DataWrap[] dataWraps, int left,int right){

if (left < right){

int center = (left + right) / 2;

sort(dataWraps,left,center);

sort(dataWraps,center + 1, right);

merge(dataWraps,left,center,right);

}

}

private static void merge(DataWrap[] dataWraps, int left, int center, int right) {

DataWrap[] tmpArr = new DataWrap[dataWraps.length];

int mid = center + 1;

int third = left;

int tmp = left;

while (left <= center && mid <= right){

if (dataWraps[left].compareTo(dataWraps[mid]) <= 0){

tmpArr[third++] = dataWraps[left++];

}else {

tmpArr[third++] = dataWraps[mid++];

}

}

while(mid <= right){

tmpArr[third++] = dataWraps[mid++];

}

while (left <= center){

tmpArr[third++] = dataWraps[left++];

}

//将中間數組中的内容複制回原數組 while (tmp <= right){

dataWraps[tmp] = tmpArr[tmp++];

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(9,""),

new DataWrap(-16,""),

new DataWrap(21,""),

new DataWrap(23,""),

new DataWrap(-30,""),

new DataWrap(-49,""),

new DataWrap(21,""),

new DataWrap(30,""),

new DataWrap(30,"")

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

mergeSort(dataWraps);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}時間複雜度: O(n *

java排序算法複雜度_常用的排序算法(Java版)

)

空間複雜度: 較高

穩定性: 穩定

[桶式排序法]

該排序法不再是基于比較的排序方法,排序方式非常巧妙,需要待排序序列滿足如下兩個特征:待排序序列的所有值處于一個可枚舉範圍内

待排序序列所在的這個可枚舉範圍不應該太大,否則排序開銷太大

假設有如下待排序序列:

5, 4, 2, 4, 1

這個待排序序列處于0, 1, 2, 3, 4, 5這個可枚舉範圍内,而且這個範圍很小,可使用桶式排序:

具體步驟:對這個可枚舉範圍建構一個buckets數組,用于記錄“落入”每個桶中的元素的個數

按如下公式對上述buckets數組的元素進行重新計算

buckets[i] = buckets[i] + buckets[i-1] (1 <= i <= buckets.length)

示例代碼:

package com.atschool;

import com.atschool.domain.DataWrap;

import java.util.Arrays;

public class BucketSort {

public static void bucketSort(DataWrap[] dataWraps, int min, int max){

System.out.println("開始排序:");

int arrayLen = dataWraps.length;

DataWrap[] tmp = new DataWrap[arrayLen];

int[] buckets = new int[max - min];

for (int i = 0; i < arrayLen; i++) {

buckets[dataWraps[i].data - min]++;

}

System.out.println(Arrays.toString(buckets));

for (int i = 1; i < max - min; i++) {

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

}

System.out.println(Arrays.toString(buckets));

System.arraycopy(dataWraps,0,tmp,0,arrayLen);

//根據buckets數組中的資訊将待排序序列的各元素放入相應的位置 for (int k = arrayLen - 1; k >= 0 ; k--) {

dataWraps[--buckets[tmp[k].data - min]] = tmp[k];

}

}

public static void main(String[] args) {

DataWrap[] dataWraps = {

new DataWrap(9,""),

new DataWrap(5,""),

new DataWrap(-1,""),

new DataWrap(8,""),

new DataWrap(5,""),

new DataWrap(7,""),

new DataWrap(3,""),

new DataWrap(-3,""),

new DataWrap(1,""),

new DataWrap(3,"")

};

System.out.println("排序之前:\n" + Arrays.toString(dataWraps));

bucketSort(dataWraps, -3, 10);

System.out.println("排序之後:\n" + Arrays.toString(dataWraps));

}

}時間複雜度: 極低

空間複雜度: 較高

穩定性: 穩定

[基數排序法]

基數排序必須依賴于另外的排序方法。

總體思路:

将待排序資料裡的排序關鍵字拆分成多個排序關鍵字進行排序,然後,根據子關鍵字對待排資料進行排序。

兩種解決方案:最高位優先法MSD(Most Significant Digit first)

最低位優先法LSD(Least Significant Digit first)

例如,對如下資料序列進行排序:

192, 221, 13, 23

該序列中,每個資料至多有3位,是以可以将每個資料拆分成3個關鍵字:百位(高位)、十位、個位(低位)。

使用基數排序法時,計算機會優先選擇最地位優先法,如下所示:第1輪對個位關鍵字排序:221, 192, 12, 23

第2輪對十位關鍵字排序:13, 23, 221, 192

第3輪對百位關鍵字排序:13, 23, 192, 221

要求:對任一子關鍵字排序需要借助另一種排序方法

上述排序方法必須是穩定的

是以桶式排序算法最合适。

示例代碼:

package com.atschool;

import java.util.Arrays;

public class MultiKeyRadixSort {

public static void radixSort(int[] data, int radix, int d){

System.out.println("開始排序:");

int arrayLen = data.length;

int[] tmp = new int[arrayLen];

int[] buckets = new int[radix];

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

Arrays.fill(buckets,0);

System.arraycopy(data, 0 ,tmp, 0, arrayLen);

for (int j = 0; j < arrayLen; 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 = arrayLen - 1; m >= 0 ; m--) {

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

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

}

System.out.println("對" + rate + "位上子關鍵字排序:" + Arrays.toString(data));

rate *= radix;

}

}

public static void main(String[] args) {

int[] data = {1100,192,221,12,13};

System.out.println("排序之前:\n" + Arrays.toString(data));

radixSort(data,10,4);

System.out.println("排序之後:\n" + Arrays.toString(data));

}

}