参考:
百度百科:基数排序
基数排序(radix sort)
工作原理
针对 基数 进行排序,找出待排序列表的最大值,判断它的位数,比如 123
的位数为 3
,先对个位数进行排序,遍历待排序列表,将个位数相同的值放在一起,即放在编号 0-9
的 桶 中,排序完成后,按顺序连接 0-9
桶中的值;再对十位数的值进行排序,同样放入 0-9
的 桶 中;依此类推,遍历所有位数
基数排序又称为 桶子法(bucket sort)
算法思想
有两种不同的排序方式
最低位优先(
LSD,least significant digit first
)。先从低位数开始,遍历到最高位,每次遍历后都将所有桶中数据连接在一起,最后一次合并所有桶中的数字就是排序结果- 问题:用
Python
实现时考虑如何创建0-9
共10
个桶,如何将数据放入这些桶中 - 思路:创建一个下标列表,长度为
10
,初始化为0
,表示每个桶的数据个数,同时创建一个辅助列表,保存排序结果
- 问题:用
最高位优先(
MSD,most significant digit first
)。先从最高位数开始,遍历到最低位。和LSD
不同的是,每次遍历后不再连接所有桶中的数据,而是针对单独桶中的数据进行低位排序,最后再合并所有桶中的数据- 问题:如何针对桶中数据进行排序
- 思路:采用递归方法,输入待排序数据和位数
Python 算法实现
# -*- coding: utf-8 -*-
"""
基数排序实现
"""
import random
__author__ = 'zj'
def create_data(leng, min, max):
"""
创建待排序序列
:param leng: 序列长度
:param min: 最小值
:param max: 最大值
:return: 列表
"""
li = range(min, max)
return random.sample(li, leng)
def radix_sort(li):
"""
基数排序实现 lsd(least significant digit first) 从小到大排序
:param li: 待排序列表
:return: 已排序列表
"""
m = max(li) # 获取最大值
digits = len(str(m)) # 获取位数
target = 0
while target < digits:
idxs = [x * 0 for x in xrange(10)]
te = []
for item in li:
radix = item / 10 ** target % 10
idxs[radix] += 1
te.insert(sum(idxs[:radix + 1]) - 1, item)
target += 1
li = te
return li
def radix_sort_v2(li, d=None):
"""
基数排序实现 msd(most significant digit first)
:param li: 待排序列表
:param d:基数,默认为 None
:return: 已排序列表
"""
if len(li) == 1:
return li
if d is None:
m = max(li) # 获取最大值
d = len(str(m)) # 获取位数
if d <= 0:
return li
idxs = [x * 0 for x in xrange(10)]
te = []
for item in li:
radix = item / 10 ** (d - 1) % 10
idxs[radix] += 1
te.insert(sum(idxs[:radix + 1]) - 1, item)
res = []
for i in xrange(len(idxs)):
if idxs[i] != 0:
sub = te[sum(idxs[:i]): sum(idxs[:i + 1])]
# print sub
res.extend(radix_sort_v2(sub, d - 1))
return res
if __name__ == '__main__':
da = create_data(20, 0, 160)
print da
res = radix_sort(da)
print res
性能分析
稳定性
基数排序是稳定排序算法
不论是 LSD
还是 MSD
,每次遍历不涉及数据交换,所以相同大小的数据的相对位置不会发生改变
时间复杂度
其时间复杂度为 O(d(r+n))
,其中 r
为所采取的基数,而 n
为堆数(关键字的个数),d
代表长度
空间复杂度
空间复杂度为 O(rd+n)