排序算法之基数排序
这里是传送门⇒总结:关于排序算法
平均时间复杂度 | 最优时间复杂度 | 最差时间复杂度 | 空间复杂度 | 稳定性 | |
---|---|---|---|---|---|
基数排序 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(n+r) | 稳定 |
注:d为数组最高位数,r为基数
- 算法描述
- 将每个元素按位数切割,收集元素的各个位数,然后按元素各个位数分配到对应的位置,顺序可以从高位到低位(MSD:最高优先法Most significant digital)或者低位到高位(LSD:最低优先法Least significant digital)
- LSD:适用于位数较少的序列。先按照各个元素的最低位大小进行分配排序,再按照元素次低位大小进行分配排序...直到按照元素最高位分配排序。其中采用了计数排序的思想,只不过count的值不是元素本身,而是元素的各个位数上的值
- MSD:适用于位数较多的序列,采用了桶排序的递归思想:先把元素分到对应区间,再逐渐排好各个区间的。先按照各个元素的最高位大小进行分配排序,再对分配了不只1个元素的“桶”内元素按次高位大小进行子分配排序...循环直到元素最低位
- 这里只考虑非负整数的排序
- JS实现
// 使用公用函数GetHighDigitTemp
// 返回数组元素中的最高位数
function GetHighDigitTemp(array, radix) {
var len = array.length;
var max = array[0];
for (var i = 1; i < len; i++) {
if (array[i] > max) {
max = array[i];
}
}
var digit = 1;
for (; max >= radix; digit++) {
max /= radix;
}
return digit;
}
// 这里是采用LSD的基数排序
// 此处传入的array会被直接改变
function RadixSort_LSD(array, radix) {
var len = array.length;
if (len <= 1) {
return;
}
var digit = GetHighDigitTemp(array, radix);
var count = new Array(radix),
bucket = new Array(len);
for (var i = 0, digitTemp = 1; i < digit; i++, digitTemp *= radix) {
for (var j = 0; j < radix; j++) {
count[j] = 0;
}
for (var j = 0; j < len; j++) {
var temp = Math.floor(array[j] / digitTemp) % radix;
count[temp]++;
}
for (var j = 1; j < radix; j++) {
count[j] += count[j - 1];
}
for (var j = len - 1; j >= 0; j--) {
var temp = Math.floor(array[j] / digitTemp) % radix;
bucket[count[temp] - 1] = array[j];
count[temp]--;
}
for (var j = 0; j < len; j++) {
array[j] = bucket[j];
}
}
}
// 这里是采用MSD的基数排序
// 此处传入的array会被直接改变
function RadixSort_MSD(array, radix, digit) {
var len = array.length;
if (len <= 1 || digit <= 0) {
return;
}
var digitTemp = 1;
var bucket = new Array(radix);
for (var i = 0; i < radix; i++) {
bucket[i] = [];
}
for (var i = 1; i < digit; i++) {
digitTemp *= radix;
}
for (var i = 0; i < len; i++) {
var temp = Math.floor(array[i] / digitTemp) % radix;
bucket[temp].push(array[i]);
}
array.length = 0;
for (var i = 0; i < radix; i++) {
var sBucketILen = bucket[i].length;
if (sBucketILen > 1) {
RadixSort_MSD(bucket[i], radix, digit - 1);
}
for (var j = 0; j < sBucketILen; j++) {
array.push(bucket[i][j]);
}
}
}
// 执行RadixSort_MSD必须先算出digit,digit为数组元素中的最高位数
var digit = GetHighDigitTemp(array,radix);
- 分析
- 设待排序列长度为n,序列中最高位数为d,基数为r,b为每层递归的子桶数量
- 其中使用的公共函数
GetHighDigitTemp
的时间复杂度为O(n) - 对于采用了LSD方式的
RadixSort_LSD
,其时间复杂度T(n) = O(n + d * (2r + 3n)) = O(d(n + r)),其空间复杂度为count数组和bucket数组所占用的内存,S(n) = O(n + r) - 对于采用了MSD方式的
RadixSort_MSD
,其时间复杂度T(n) = O(d * (br + 2n)) = O(d(r + n)),(这里的每一层递归的b不知道怎么算,暂时把它看成常数),其空间复杂度为压栈最深的时候总的bucket数组所占内存,栈最大深度为d,每层递归的bucket所占...然后,这个我算不明白了,希望之后可以解答 - 上述复杂度表格的数据是采用LSD的基数排序的复杂度
- 两种方法分别采用了
计数排序
和桶排序
的思想,而基于这两种思想的排序都是稳定的,因此基数排序是稳定的