一天一算法 - 基数排序

介绍

  1. 比较型排序和非比较型排序

首先,比较型排序和非比较型排序有何不同呢?很简单,如果在排序过程中,需要比较数组中的元素大小,然后将元素放置在最终位置,这称之为比较型排序。举个简单的例子来说,对于选择排序,排序的思想就是从第一个位置开始,找到数组中最小的元素放进去,那么怎么找到最小的元素呢?这个时候就需要设置一个 min 变量,在数组中依次比较,不断地替换 min(如果元素的值小于 min ) 直到数组最后的一个元素。

一个比较型排序的比较次数直接影响算法的性能,比如选择排序的比较次数就与 (N^2) 成正比。

非比较型排序不需要经过比较就可以将一个数组变成有序的,从理论上来说,它应该快于任何比较型算法,可事实上却不是这样!但是值得注意的是,比较型排序算法的时间复杂度是不可能会突破 O(NlogN) 的,但是非比较型算法比如基数排序在某些情况下却可以突破下界,达到 O(N)

  1. 稳定排序和不稳定排序

稳定与不稳定该怎么鉴定呢?数组中有任意两个元素 a[i]a[j], 而且 a[i]a[j] 满足条件 a[i] == a[j] && i > j,如果在排序后,i > j 仍然成立,那么这种排序就是稳定排序,否则是不稳定排序。

基数排序是一种稳定排序算法。


算法思想

将所有待比较的数值统一为相同位数,长度不够的在高位补0,然后从低位开始依次进行排序,这样等排到最高位的时候,整个数组自然就是有序的了。

前面我们说了,基数排序是一种非比较型排序,那么我们依赖怎样的手段对数据进行排序呢?

不论个位,十位还是百位,其数值都在 [0, 9] 这个区间内,所以我们首先声明一个数组 backet[10],然后再将 bucket[0] ... bucket[9] 声明为数组,这样的话,我们就可以对个位进行排序,因为个位为 0 的都被放在 bucket[0] 这个数组中,个位为 1 的都被放在 bucket[1] 这个数组里...

当进行完个位的排序时,按照顺序将 bucket[] 元素重新推入原数组中,然后将 bucket 数组清空,以便进行十位的排序。

如果看了以上文字你还是浑浑噩噩的,那么就来举个简单的例子,比如我们对以下数组进行排序。

[1, 21, 89, 110, 56]

首先,我们声明一个数组。

var bucket = [];
for(var i = 0; i < 10; i++) {
    bucket[i] = [];     
}

[1, 21, 89, 110, 56] 的个位分别是 [1, 1, 9, 0, 6], 很显然,对个位排序后,bucket[0] = [110], bucket[1] = [1, 21], bucket[6] = [56], bucket[9] = [89], 将这些数依次推入原数组,这个时候数组为 [110, 1, 21, 56, 89]

[110, 1, 21, 56, 89] 的十位分别为 [1, 0, 2, 5, 8],对十位进行排序后,bucket[0] = [1], bucket[1] = [110], bucket[2] = [21], bucket[5] = [56], bucket[8] = [89], 将这些数依次推入原数组,这个时候数组为 [1, 110, 21, 56, 89]

[1, 110, 21, 56, 89] 的百位分别是 [0, 1, 0, 0, 0],对百位进行排序后,bucket[0] = [1, 21, 56, 89], bucket[1] = [110],将这些数依次推入原数组,这个时候数组为 [1,21,56,89,110]

可见,这个时候数组就变得有序了,而且和比较型排序不同的是,我们并没有与数组中的其它元素进行比较,只是根据自己各个位数的值让其放进不同的数组中。


实现 (JavaScript)

/*
 * @Author: hwaphon
 * @Date:   2017-03-10 13:07:02
 * @Last Modified by:   hwaphon
 * @Last Modified time: 2017-03-10 13:34:52
 */

function radixSort(array) {

    if (array.length <= 1) {
        return array;
    }

    var length = array.length,
        i,
        j,
        str,
        k,
        t,
        loop,
        bucket = [],
        max = array[0];

    for (i = 1; i < length; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }

    loop = (max + '').length;

    for (i = 0; i < 10; i++) {
        bucket[i] = [];
    }

    for (i = 0; i < loop; i++) {
        for (j = 0; j < length; j++) {
            str = array[j] + '';

            if (str.length - 1 >= i) {
                k = parseInt(str[str.length - i - 1]);
                bucket[k].push(array[j]);
            } else {
                bucket[0].push(array[j]);
            }
        }

        array.splice(0, length);

        for (j = 0; j < 10; j++) {
            t = bucket[j].length;
            for (k = 0; k < t; k++) {
                array.push(bucket[j][k]);
            }

            bucket[j] = [];
        }
    }

    return array;
}

总结

刚才我们介绍的基数排序是从低位开始进行排序的,这种排序称之为最低位优先排序(LSD), 还有一种最高位优先排序(MSD)。LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。

我在我电脑上对比了基数排序与快速排序的效率,无论我选择怎样的数据,总是快速排序更快一点,如果看到我博客的人知道原因或者知道基数排序适用情况请告与我知晓,感激不尽。

还有一点,因为快速排序是原地排序,而基数排序还需要额外的内存消耗,所以在选择排序算法时一定要考虑这一点!

拓展阅读:

  1. 《稳定排序和不稳定排序》

  2. 《常见的排序算法 - 基数排序》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 常见排序的java实现 常见排序java实现 插入排序(二分插入排序) 希尔排序 快速排序(三数中值快排) 冒泡排...
    51ac3305fd46阅读 383评论 0 1
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,173评论 0 52
  • 原博客 1.选择排序(Selection Sort): 选择最小元素,移动到首位置。 (1)算法描述和实现: 首先...
    Gitfan阅读 539评论 0 0
  • 用最肤浅最直接的话来讲这本书,就是一个中年男人,为了自己所谓的艺术梦,抛弃自己的妻儿,为了自己的欲望,抢了自己救命...
    Yu菲君阅读 393评论 0 0
  • 现在是深夜,我想睡觉,但我失眠了 我二十岁,最美丽的年纪,我也想过花儿一般得生活,不想扛这么多 我二十岁,最青春的...
    栗小姐的阅读 281评论 0 3