排序算法(十):基数排序

基数排序也可以称为多关键字排序,同计数排序类似,也是一种非比较性质的排序算法。将待排序集合中的每个元素拆分为多个总容量空间较小的对象,对每个对象执行桶排序后,则完成排序过程。

基数排序在桶排序的基础上做了优化,桶排序需要选择适当的映射规则,来完成集合中元素到多个桶的映射,也可以称之为值域划分。但是当集合中元素跨度很大时,映射规则的设计比较困难,若规则设计的宽泛一些,则桶的个数较少,随便避免了许多空桶的情况,但是可能会存在元素分布不均,桶排序则演变为普通的比较性质排序;若规则设计的较为精确,则桶的个数较多,可能会存在大部分桶都是空桶的情况,存在较大空间浪费。

桶排序之所以存在上述问题,原因在于算法中对待排序元素的属性选择所致。排序过程选择使用了元素本身的 “大小” 属性,所以算法处理的元素集合就是这个 “大小” 空间。例如,若待排序元素为整型,而整型数字在 “大小” 方面可以是无限大或者无限小的;若待排序元素为字符串,而字符串在 “长度” 方面是无限大的。而桶排序又是一种对元素总容量敏感的排序算法,所以存在使用限制。

基数排序过程中也使用了桶排序操作,不过对于桶排序面向的对象进行了优化。例如,若元素是整数类型,则选择元素的每位数字作为排序对象,因为每个数字的容量空间大小只是 10;同理若元素是字符串,则选择元素的每位字符,因为每个字符的容量空间大小为 26。所以在基数排序过程中,给其中的桶排序操作选择了容量空间有限的排序对象。

基数排序中的桶排序操作具有一点特殊性,即每个桶的宽度,或者称为值域跨度为一,所以将待排序集合中所有元素移动到各个桶上之后,不需要再对每个桶进行排序。

算法过程

  1. 根据待排序元素的类型申请桶空间,并从待排序集合中计算出元素的最大位数;
  2. 从右向左,根据元素当前位数的值,将所有元素移动到对应的桶中;
  3. 将所有桶中元素移动回原始集合中;
  4. 重复步骤 2, 3,直到遍历完所有位数。

演示示例

待排序集合为:[1086, 187, 30, 76, 0, 1359, 36, 777, 9, 2]

step 1:

因为此处选择的待排序集合元素类型为十进制整数,所以基数为 10,申请的桶个数为:10,其中元素的最大位数为 4。

step 2:

遍历待排序集合,当位数 index 值为 1 时,根据元素个位数字,将待排序集合中所有元素移动到对应的桶中:

桶下标 桶中元素
0 30, 0
1
2 2
3
4
5
6 1086, 76, 36
7 187, 777
8
9 1359, 9

step 3:

将桶中所有元素移动回原始序列后,序列为:[30, 0, 2, 1086, 76, 36, 187, 777, 1359, 9]

重复执行 step 2 和 step 3:

cycle 1:

当位数 index 值为 2 时,根据元素十位数字,将集合中所有元素移动到对应的桶中:

桶下标 桶中元素
0 0, 2, 9
1
2
3 30, 36
4
5 1359
6
7 76, 777
8 1086, 187
9

将桶中所有元素移动回原始序列后,序列为:[0, 2, 9, 30, 36, 1359, 76, 777, 1086, 187]

cycle 2:

当位数 index 值为 3 时,根据元素百位数字,将集合中所有元素移动到对应的桶中:

桶下标 桶中元素
0 0, 2, 9, 30, 36, 76, 1086
1 187
2
3 1359
4
5
6
7 777
8
9

将桶中所有元素移动回原始序列后,序列为:[0, 2, 9, 30, 36, 76, 1086, 187, 1359, 777]

cycle 3:

当位数 index 值为 4 时,根据元素千位数字,将集合中所有元素移动到对应的桶中:

桶下标 桶中元素
0 0, 2, 9, 30, 36, 76, 187, 777
1 1086, 1359
2
3
4
5
6
7
8
9

将桶中所有元素移动回原始序列后,序列为:[0, 2, 9, 30, 36, 76, 187, 777, 1086, 1359]

算法示例

def radixSort(arr, radix=10):  # elements in the array are all non-negative integers
    k = math.ceil(math.log(max(arr) + 1, radix))  # calculate the digit length
    radixArr = [[] for i in range(radix)]  # apply the space
    for i in range(k):          # sort each digit
        for j in arr:       # add every element in the array to radixArr
            radixArr[j // (radix ** i) % radix].append(j)
        arr.clear()
        for a in radixArr: # add every element in radixArr to the array
            arr.extend(a)
            a.clear()

代码中第一层循环对最大元素每一位进行桶排序,也就是迭代比较的次数,嵌套包括两个循环,第一个循环为将序列中所有元素移动到对应的桶中,第二个循环为将桶中所有元素移动回序列中。若元素最大位数为 K,则算法的复杂为 O(K*(N+N))

算法分析

由算法过程可知,基数排序的时间复杂度为 O(KN),其中 K 为元素最大位数,也就是迭代比较的次数。算法过程中不存在元素之间的跨位置交换,属于稳定排序方式。算法过程中需要申请的空间大小为 N+R,其中 R 表示待排序元素的基数,例如示例中的十进制整数排序,则 R=10;若待排序元素为字符串,则 R=26,因为基数的容量空间总是有限的,所以算法的时间复杂度为 O(N)

其实基数排序中不一定按照每一位进行排序,也可能元素中的几位构成了一个组合,按照组合为单位进行排序。同时排序算法也不一定是桶排序方式,可以是别的排序算法,也可以给不同位使用不同的排序算法。总之基数排序提供了一个针对复杂元素类型的排序思路,可以针对元素中不同部分,选择不同的排序方式。

github 链接:基数排序

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

推荐阅读更多精彩内容

  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    闲云清烟阅读 757评论 0 6
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,253评论 0 2
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,730评论 0 15
  • 六月初,7.8.9这三天是鲤鱼跃龙门的时候,高考这龙门让多少学生,家长为之拼搏,十年寒窗,出人头地的思想深深的印刻...
    踱白阅读 148评论 0 0
  • 如何阅读一本书-第8章阅读感受 检视阅读后得到的信息 四个收获 通过找到共同的字义,读者和作者间达成共识。 沟通的...
    奋翼阅读 913评论 0 50