排序三:桶排序、計(jì)數(shù)排序、基數(shù)排序

這一篇我們來看三種時(shí)間復(fù)雜度為O(n)的排序算法:桶排序、計(jì)數(shù)排序、基數(shù)排序。我們把這類時(shí)間復(fù)雜度為O(n)的排序算法叫做線性排序。這類排序算法之所以能夠做到線性時(shí)間,其實(shí)是因?yàn)樗鼈兌疾皇腔诒容^來實(shí)現(xiàn)排序的。

1. 桶排序

1.1 什么是桶排序

桶排序的基本思想就是將數(shù)據(jù)拆分到多個(gè)有大小區(qū)分的桶里面,然后分別對(duì)每個(gè)桶里面的數(shù)據(jù)進(jìn)行排序,完成每個(gè)桶里面的數(shù)據(jù)的排序之后,按照桶與桶之間的數(shù)據(jù)的大小關(guān)系,依次合并數(shù)據(jù)就得到了所要的有序序列


桶排序過程示意圖

1.2 桶排序的性能分析

假設(shè)我們要將n條數(shù)據(jù)進(jìn)行排序,如果我們有m個(gè)桶,我們把這n條數(shù)據(jù)均勻的劃分到這m個(gè)桶里面,每個(gè)桶里的數(shù)據(jù)就是k=n/m。然后我們對(duì)每個(gè)桶使用快速排序進(jìn)行排序,時(shí)間復(fù)雜度就是O(klogk)。m個(gè)桶總的時(shí)間復(fù)雜度就是O(mklogk)。因?yàn)閗=n/m。所以整個(gè)事件復(fù)雜度就是O(nlog(n/m))。當(dāng)m接近n的時(shí)候,log(n/m)就是一個(gè)非常小的常數(shù),整個(gè)桶排序的時(shí)間復(fù)雜度就接近O(n)。

它的空間復(fù)雜度O(n),但是并不是需要兩倍的數(shù)據(jù)內(nèi)存才能進(jìn)行排序,因?yàn)榕判蜻^程中存儲(chǔ)的只是實(shí)際數(shù)據(jù)的索引

桶內(nèi)排序時(shí)選用穩(wěn)定排序算法,則它就能做到穩(wěn)定排序

1.3 桶排序?qū)?shù)據(jù)的特殊要求

桶排序看起來很快,但是要達(dá)到O(n)的時(shí)間復(fù)雜度,它對(duì)待排序的數(shù)據(jù)是有要求的

  1. 首先,待排序的數(shù)據(jù)需要能很容易的劃分成m個(gè)桶,并且桶與桶之間要有天然的大小關(guān)系。
  2. 其次,數(shù)據(jù)在各個(gè)桶之間的分布要是比較均勻的。如果數(shù)據(jù)經(jīng)過劃分之后,有些桶里面的數(shù)據(jù)非常多,有些非常少,那桶內(nèi)排序的時(shí)間復(fù)雜度就不是常量級(jí)的。極端情況下,如果數(shù)據(jù)全部在一個(gè)桶里面的話,算法的復(fù)雜度就退化成了O(nlogn)

1.4 桶排序的算法實(shí)現(xiàn)

桶排序的實(shí)現(xiàn)思路

  1. 根據(jù)數(shù)據(jù)范圍和預(yù)估的桶的數(shù)據(jù)容量計(jì)算桶的個(gè)數(shù),申請(qǐng)桶空間
  2. 將待排序的數(shù)據(jù)劃分到各個(gè)桶中
  3. 對(duì)每個(gè)桶進(jìn)行排序
  4. 合并排序之后的桶中的數(shù)據(jù)

完整代碼如下

public static void sort(int[] array, int bucketSize) {
    if (array == null || array.length < 2) {
        return;
    }
    //計(jì)算用多少個(gè)桶來裝數(shù)據(jù)
    int min = array[0];
    int max = array[0];
    for (int i = 1; i < array.length; i++) {
        if (array[i] < min) {
            min = array[i];
        } else if (array[i] > max) {
            max = array[i];
        }
    }
    System.out.println("min:" + min);
    System.out.println("max:" + max);
    int bucketCount = (max - min) / bucketSize + 1;
    System.out.println("bucketCount:" + bucketCount);
    //申請(qǐng)桶空間
    int[][] buckets = new int[bucketCount][bucketSize];
    int[] indexArray = new int[bucketCount];
    //將數(shù)據(jù)裝入桶里面
    for (int i = 0; i < array.length; i++) {
        int bucketIndex = (array[i] - min) / bucketSize;
        if (indexArray[bucketIndex] == buckets[bucketIndex].length) {// buckets[bucketIndex]滿了,需要擴(kuò)容
            ensureCapacity(buckets, bucketIndex);
        }
        buckets[bucketIndex][indexArray[bucketIndex]] = array[i];
        indexArray[bucketIndex]++;
    }
    //對(duì)每個(gè)桶進(jìn)行排序
    int k = 0;
    for (int i = 0; i < bucketCount; i++) {
        sort(buckets[i], 0, indexArray[i] - 1);
        //合并桶中的數(shù)據(jù)
        for (int j = 0; j < indexArray[i]; j++) {
            array[k++] = buckets[i][j];
        }
    }
}

private static void sort(int[] a, int left, int right) {
    if (left < right) {
        int low = left;
        int hight = right;
        int pivot = a[low];
        //找到分區(qū)點(diǎn)的位置
        while (low < hight) {//有元素之間的位置交換,所以不是穩(wěn)定排序
            while (low < hight && a[hight] >= pivot) {
                hight--;
            }
            a[low] = a[hight];
            while (low < hight && a[low] <= pivot) {
                low++;
            }
            a[hight] = a[low];
        }
        a[low] = pivot;
        //對(duì)左右兩個(gè)分區(qū)進(jìn)行排序
        if (left + 1 < low) {
            sort(a, left, low - 1);
        }
        if (right - 1 > low) {
            sort(a, low + 1, right);
        }
    }
}

private static void ensureCapacity(int[][] buckets, int bucketIndex) {
    int[] tempArr = buckets[bucketIndex];
    int[] newArr = new int[tempArr.length * 2];
    for (int j = 0; j < tempArr.length; j++) {
        newArr[j] = tempArr[j];
    }
    buckets[bucketIndex] = newArr;
}

1.5 桶排序的實(shí)際應(yīng)用

桶排序比較適合用在外部排序中。比如說有10GB的訂單數(shù)據(jù)需要按照訂單金額進(jìn)行排序,但是能夠使用的內(nèi)容只有1GB,沒有辦法一次把所有數(shù)據(jù)都加載到內(nèi)存中來,這個(gè)時(shí)候就可以使用桶排序

具體怎么做呢?

  1. 先掃描一遍記錄,查看訂單金額的數(shù)據(jù)范圍。假設(shè)訂單的金額范圍是1-10萬元,我們可以把數(shù)據(jù)劃分到100個(gè)桶里面,第一個(gè)桶存儲(chǔ)1元-1000元之間的訂單,第二個(gè)桶存儲(chǔ)1001-2000之間的訂單,依次內(nèi)推。
  2. 然后我們?cè)俅伪闅v訂單記錄,開始加載我們第一個(gè)桶需要的數(shù)據(jù)進(jìn)行排序,排好序之后寫入到編號(hào)為001的桶中。然后在加載第二個(gè)桶的數(shù)據(jù)排序,依次類推。
  3. 待所有桶中的數(shù)據(jù)都排序好了之后,依次讀取這排序好的100個(gè)文件中的訂單數(shù)據(jù),寫入到一個(gè)文件中,這樣文件中存儲(chǔ)的就是金額從小到大排序的訂單數(shù)據(jù)了

如果某個(gè)桶的數(shù)據(jù)規(guī)模過大,依然無法用1GB的內(nèi)存排序如何處理?

再次對(duì)這個(gè)桶中的數(shù)據(jù)進(jìn)行拆分處理。比如訂單在1-1000元的記錄特別多,我們可以繼續(xù)將它劃分為1-100,101-200,……901-1000。然后以同樣的方式去排序

什么是外部排序

外部排序指的是大文件的排序,即待排序的記錄存儲(chǔ)在外存儲(chǔ)器上,待排序的文件無法一次裝入內(nèi)存,需要在內(nèi)存和外部存儲(chǔ)器之間進(jìn)行多次數(shù)據(jù)交換,以達(dá)到排序整個(gè)文件的目的。

1.6 簡單示例

使用桶排序給交易記錄按照價(jià)格來進(jìn)行排序,我們把加一記錄簡化成只有價(jià)格和編號(hào)id的方式

交易記錄

public static class Record {
        private int money;
        private String id;
        ...
    }

桶排序算法

public static void sort(Record[] array, int bucketSize) {
    if (array == null || array.length < 2) {
        return;
    }
    //計(jì)算用多少個(gè)桶來裝數(shù)據(jù)
    int min = array[0].money;
    int max = array[0].money;
    for (int i = 1; i < array.length; i++) {
        if (array[i].money < min) {
            min = array[i].money;
        } else if (array[i].money > max) {
            max = array[i].money;
        }
    }
    System.out.println("min:" + min);
    System.out.println("max:" + max);
    int bucketCount = (max - min) / bucketSize + 1;
    System.out.println("bucketCount:" + bucketCount);
    //申請(qǐng)桶空間
    Record[][] buckets = new Record[bucketCount][bucketSize];
    int[] indexArray = new int[bucketCount];
    //將數(shù)據(jù)裝入桶里面
    for (int i = 0; i < array.length; i++) {
        int bucketIndex = (array[i].money - min) / bucketSize;
        if (indexArray[bucketIndex] == buckets[bucketIndex].length) {// buckets[bucketIndex]滿了,需要擴(kuò)容
            ensureCapacity(buckets, bucketIndex);
        }
        buckets[bucketIndex][indexArray[bucketIndex]] = array[i];
        indexArray[bucketIndex]++;
    }
    //對(duì)每個(gè)桶進(jìn)行排序
    int k = 0;
    for (int i = 0; i < bucketCount; i++) {
//            sort(buckets[i], 0, indexArray[i] - 1);//快排,不穩(wěn)定
        sort2(buckets[i], indexArray[i]);//冒泡,穩(wěn)定排序
        //合并桶中的數(shù)據(jù)
        for (int j = 0; j < indexArray[i]; j++) {
            array[k++] = buckets[i][j];
        }
    }
}

/**
 * 冒泡
 *
 * @param array
 */
private static void sort2(Record[] array, int size) {
    if (array == null || array.length == 1) {
        return;
    }
    for (int i = 0; i < size; i++) {
        boolean isExchanged = false;
        for (int j = 0; j < size - i - 1; j++) {//這里的i表示經(jīng)過了幾次冒泡排序了,經(jīng)過一次有在最后面多了一位已經(jīng)排好序的元素,所以下一次要比較的范圍也較少1
            if (array[j].money > array[j + 1].money) {//只有在后面的元素大于前面的元素的時(shí)候才交互,可以保證排序的穩(wěn)定性
                Record temp = array[j + 1];
                array[j + 1] = array[j];
                array[j] = temp;
                isExchanged = true;
            }
        }
        if (!isExchanged) {//當(dāng)某一趟冒泡排序中沒有交換發(fā)送的時(shí)候,說明序列已經(jīng)有序了
            break;
        }
    }
}

這里我們注意使用穩(wěn)定排序來做桶內(nèi)排序,保證排序的穩(wěn)定性

測(cè)試用例

@Test
public void test() {
    int size = 10;
    BucketSortRecord.Record[] array = new BucketSortRecord.Record[size];
    for (int i = 0; i < size; i++) {
        BucketSortRecord.Record person = new BucketSortRecord.Record();
        person.setMoney(10 + new Random().nextInt(size));
        person.setId("record_" + i);
        array[i] = person;
    }
    print(array, "   org:");
    BucketSortRecord.sort(array, 2);
    print(array, "sorted:");
}

測(cè)試結(jié)果

   org:{money=13, name='record_0'},{money=14, name='record_1'},{money=14, name='record_2'},{money=12, name='record_3'},{money=14, name='record_4'},
sorted:{money=12, name='record_3'},{money=13, name='record_0'},{money=14, name='record_1'},{money=14, name='record_2'},{money=14, name='record_4'},

我們可以看到排序結(jié)果是穩(wěn)定的

2. 計(jì)數(shù)排序

2.1 什么是計(jì)數(shù)排序

計(jì)數(shù)排序可以看做一種特殊的桶排序,每個(gè)桶里面的數(shù)據(jù)都是相同的,也就不用進(jìn)行同類排序了。當(dāng)我們要對(duì)n個(gè)數(shù)據(jù)進(jìn)行排序的時(shí)候,我們先計(jì)算一下它的數(shù)據(jù)區(qū)間,比如最小值是1,最大值是K,則數(shù)據(jù)區(qū)間就是看,然后將這些數(shù)據(jù)拆分到這k個(gè)桶里面,由于每個(gè)桶里面的數(shù)據(jù)都是相同的,所以我們不用進(jìn)行桶內(nèi)排序,拆分完成之后,我們?cè)俅伪闅v每個(gè)桶,合并數(shù)據(jù)就得到了要排序的有序序列


計(jì)數(shù)排序過程示意圖

2.2 計(jì)算排序的性能分析

計(jì)算排序在桶排序的基礎(chǔ)上省去了桶內(nèi)排序,所以它的時(shí)間復(fù)雜度就是O(n)

它的空間復(fù)雜度O(n)

它是穩(wěn)定排序

2.3 計(jì)數(shù)排序?qū)?shù)據(jù)的特殊要求

計(jì)數(shù)排序只能用在數(shù)據(jù)范圍不大的場(chǎng)景中,如果數(shù)據(jù)范圍K很大,就不適合使用計(jì)數(shù)排序了。因?yàn)樗枰暾?qǐng)與范圍同樣大小的空間來進(jìn)行計(jì)數(shù),范圍太大,內(nèi)存就可能不夠了。

2.4 計(jì)數(shù)排序的算法實(shí)現(xiàn)

計(jì)數(shù)排序算法實(shí)現(xiàn)思路

  1. 計(jì)算數(shù)據(jù)之間的區(qū)間,申請(qǐng)計(jì)數(shù)數(shù)組
  2. 遍歷待排序數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),存入計(jì)數(shù)數(shù)組的對(duì)應(yīng)位置
  3. 計(jì)算計(jì)數(shù)數(shù)組中元素在將來排好序的序列中的位置
  4. 遍歷待排序數(shù)組,結(jié)合計(jì)數(shù)數(shù)組,將待排序數(shù)據(jù)存入到存放有序序列的數(shù)組的對(duì)應(yīng)位置

算法實(shí)現(xiàn)

public static void sort(int[] array) {
    /**
     * 計(jì)數(shù)排序的的步驟
     * 1. 計(jì)算數(shù)據(jù)之間的區(qū)間,申請(qǐng)計(jì)數(shù)數(shù)組
     * 2. 遍歷待排序數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),存入計(jì)數(shù)數(shù)組的對(duì)應(yīng)位置
     * 3. 計(jì)算計(jì)算數(shù)組中元素在將來排好序的序列中的位置
     * 4. 遍歷待排序數(shù)組,結(jié)合計(jì)數(shù)數(shù)組,將待排序數(shù)據(jù)存入到存放有序序列的數(shù)組的對(duì)應(yīng)位置
     */
    if (array == null || array.length < 2) {
        return;
    }
    //1. 計(jì)算數(shù)據(jù)分別的區(qū)間,申請(qǐng)計(jì)數(shù)數(shù)組
    int min = array[0];
    int max = array[0];
    for (int i = 1; i < array.length; i++) {
        if (array[i] < min) {
            min = array[i];
        } else if (array[i] > max) {
            max = array[i];
        }
    }
    System.out.println("min:" + min);
    System.out.println("max:" + max);
    int interval = max - min;
    System.out.println("interval:" + interval);
    int[] c = new int[interval + 1];
    //2. 遍歷待排序數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),存入計(jì)數(shù)數(shù)組的對(duì)應(yīng)位置
    for (int i = 0; i < array.length; i++) {
        c[array[i] - min]++;
    }
    //3. 計(jì)算計(jì)算數(shù)組中元素在將來排好序的序列中的位置
    for (int i = 1; i < c.length; i++) {
        c[i] = c[i - 1] + c[i];
    }
    //4. 遍歷待排序數(shù)組,結(jié)合計(jì)數(shù)數(shù)組,將待排序數(shù)據(jù)存入到存放有序序列的數(shù)組的對(duì)應(yīng)位置
    int[] temp = new int[array.length];
    for (int i = array.length - 1; i >= 0; i--) {//倒序保證穩(wěn)定性
        int index = c[array[i] - min] - 1;
        temp[index] = array[i];
        c[array[i] - min]--;
    }
    for (int i = array.length - 1; i >= 0; i--) {
        array[i] = temp[i];
    }
}

2.5 計(jì)數(shù)排序的實(shí)際應(yīng)用

計(jì)數(shù)排序可以應(yīng)用在考試成績的排名上,比如高考成績的快速排名。

假如高考總分是900分,最小分時(shí)0分,總共有50萬名考生,我們就可以將這些學(xué)生劃分到901個(gè)桶里面,由于桶里面的分?jǐn)?shù)相同,所以不同再進(jìn)行排序,我們只要一次掃描每個(gè)桶,將桶內(nèi)的考生依次輸出到一個(gè)數(shù)組中,就能實(shí)現(xiàn)對(duì)50萬名考生的成績的排序了。

2.6 簡單實(shí)例

我們簡單的實(shí)現(xiàn)一些對(duì)考生成績的排序,這里我們將考生信息簡化成只有總成績和名字兩個(gè)部分

考生信息

public static class Person {
    private int age;
    private String name;

    ...
}

計(jì)數(shù)排序算法

public static void sort(Person[] array) {
    /**
     * 計(jì)數(shù)排序的的步驟
     * 1. 計(jì)算數(shù)據(jù)分別的區(qū)間,申請(qǐng)計(jì)數(shù)數(shù)組
     * 2. 遍歷待排序數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),存入計(jì)數(shù)數(shù)組的對(duì)應(yīng)位置
     * 3. 計(jì)算計(jì)算數(shù)組中元素在將來排好序的序列中的位置
     * 4. 遍歷待排序數(shù)組,結(jié)合計(jì)數(shù)數(shù)組,將待排序數(shù)據(jù)存入到存放有序序列的數(shù)組的對(duì)應(yīng)位置
     */
    if (array == null || array.length < 2) {
        return;
    }
    //1. 計(jì)算數(shù)據(jù)分別的區(qū)間,申請(qǐng)計(jì)數(shù)數(shù)組
    int min = array[0].age;
    int max = array[0].age;
    for (int i = 1; i < array.length; i++) {
        if (array[i].age < min) {
            min = array[i].age;
        } else if (array[i].age > max) {
            max = array[i].age;
        }
    }
    System.out.println("min:" + min);
    System.out.println("max:" + max);
    int interval = max - min;
    System.out.println("interval:" + interval);
    int[] c = new int[interval + 1];
    //2. 遍歷待排序數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),存入計(jì)數(shù)數(shù)組的對(duì)應(yīng)位置
    for (int i = 0; i < array.length; i++) {
        c[array[i].age - min]++;
    }
    //3. 計(jì)算計(jì)算數(shù)組中元素在將來排好序的序列中的位置
    for (int i = 1; i < c.length; i++) {
        c[i] = c[i - 1] + c[i];
    }
    //4. 遍歷待排序數(shù)組,結(jié)合計(jì)數(shù)數(shù)組,將待排序數(shù)據(jù)存入到存放有序序列的數(shù)組的對(duì)應(yīng)位置
    Person[] temp = new Person[array.length];
    for (int i = array.length - 1; i >= 0; i--) {
        int index = c[array[i].age - min] - 1;
        temp[index] = array[i];
        c[array[i].age - min]--;
    }
    for (int i = array.length - 1; i >= 0; i--) {
        array[i] = temp[i];
    }
}

測(cè)試代碼

@Test
public void test() {
    int size = 5;
    CountingSortPerson.Person[] array = new CountingSortPerson.Person[size];
    for (int i = 0; i < size; i++) {
        CountingSortPerson.Person person = new CountingSortPerson.Person();
        person.setAge(10 + new Random().nextInt(5));
        person.setName("name_" + i);
        array[i] = person;
    }
    print(array, "   org:");
    CountingSortPerson.sort(array);
    print(array, "sorted:");
}

測(cè)試結(jié)果

   org:{age=10, name='name_0'},{age=13, name='name_1'},{age=12, name='name_2'},{age=11, name='name_3'},{age=11, name='name_4'},
sorted:{age=10, name='name_0'},{age=11, name='name_3'},{age=11, name='name_4'},{age=12, name='name_2'},{age=13, name='name_1'},

3. 基數(shù)排序

3.1 什么是基數(shù)排序

基數(shù)排序是一種多關(guān)鍵字的排序算法,其中每個(gè)關(guān)鍵字可以使用線性排序算法來完成排序,通過依次對(duì)每個(gè)關(guān)鍵字進(jìn)行排序之后,就得到了要的有序序列。這里要求每個(gè)關(guān)鍵字使用的線性排序要能保證穩(wěn)定性。

基數(shù)排序過程示意圖

3.2 基數(shù)排序的性能分析

基數(shù)排序使用其他線性排序來完成關(guān)鍵字的排序,所以它的時(shí)間復(fù)雜度也是O(n),空間復(fù)雜度O(n),它是穩(wěn)定排序

3.3 基數(shù)排序?qū)?shù)據(jù)的特殊要求

基數(shù)排序?qū)?shù)據(jù)的要求:

  1. 待排序的數(shù)據(jù)必須能夠分割成多個(gè)關(guān)鍵字來比較,且關(guān)鍵字之間有遞進(jìn)關(guān)系,比如a的高位比b的高位大,則a必定大于b。
  2. 關(guān)鍵字的范圍不能太大,要可以使用線性排序算法來排序。

3.4 基數(shù)排序的算法實(shí)現(xiàn)

這里直接編寫一個(gè)對(duì)手機(jī)號(hào)碼進(jìn)行排序的算法

算法實(shí)現(xiàn)思路

  1. 拆分關(guān)鍵字
  2. 分別對(duì)每個(gè)關(guān)鍵字進(jìn)行線性排序

代碼實(shí)現(xiàn)

public static void sort(int[] array) {
    // 從個(gè)位開始,對(duì)數(shù)組arr按"指數(shù)"進(jìn)行排序
    for (int exp = 1; array[0] / exp > 0; exp *= 10) {
        countingSort(array, exp);
    }
}

private static void countingSort(int[] array, int exp) {
    if (array == null || array.length < 2) {
        return;
    }
    //1. 計(jì)算數(shù)據(jù)分別的區(qū)間,申請(qǐng)計(jì)數(shù)數(shù)組
    int[] c = new int[10];
    //2. 遍歷待排序數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),存入計(jì)數(shù)數(shù)組的對(duì)應(yīng)位置
    for (int i = 0; i < array.length; i++) {
        c[(array[i] / exp) % 10]++;
    }
    //3. 計(jì)算計(jì)算數(shù)組中元素在將來排好序的序列中的位置
    for (int i = 1; i < c.length; i++) {
        c[i] = c[i - 1] + c[i];
    }
    //4. 遍歷待排序數(shù)組,結(jié)合計(jì)數(shù)數(shù)組,將待排序數(shù)據(jù)存入到存放有序序列的數(shù)組的對(duì)應(yīng)位置
    int[] temp = new int[array.length];
    for (int i = array.length - 1; i >= 0; i--) {//倒序保證穩(wěn)定性
        int cindex = (array[i] / exp) % 10;
        temp[c[cindex] - 1] = array[i];
        c[cindex]--;
    }
    for (int i = array.length - 1; i >= 0; i--) {
        array[i] = temp[i];
    }
}

測(cè)試用例

@Test
public void test1() {
    int size = 10;
    int[] array = new int[size];
    int[] array2 = new int[size];
    for (int i = 0; i < size; i++) {
        int num = 1;
        for (int j = 0; j < 5; j++) {
            num = num * 10 + new Random().nextInt(10);
        }
        array[i] = num;
        array2[i] = num;
    }
    print(array, "   org:");
    print(array2, "   org:");
    RadixSort.sort(array);
    MergeSort.sort(array2);
    print(array, "sorted:");
    print(array2, "sorted:");
}

測(cè)試結(jié)果

   org:186402,159502,111311,107840,111943,191059,181161,147774,143482,199457,
   org:186402,159502,111311,107840,111943,191059,181161,147774,143482,199457,
sorted:107840,111311,111943,143482,147774,159502,181161,186402,191059,199457,
sorted:107840,111311,111943,143482,147774,159502,181161,186402,191059,199457,

這里我們采用歸并排序來做一個(gè)結(jié)果對(duì)比,驗(yàn)證排序的正確性

3.5 基數(shù)排序的實(shí)際應(yīng)用

基數(shù)排序還可以用在單詞的排序中等場(chǎng)景

源碼

完整源碼和測(cè)試用例,請(qǐng)查看github之排序

  1. 桶排序:BucketSort.java、BucketSortTest.java、BucketSortRecord.java、BucketSortRecordTest.java
  2. 計(jì)數(shù)排序:CountingSort.java、CountingSortTest.java、CountingSortPerson.javaCountingSortPersonTest.java
  3. 基數(shù)排序:RadixSort.java、RadixSortTest.java

說明

算法示意圖來源:算法動(dòng)畫演示網(wǎng)站

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容