js基数排序

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

算法描述

  • 取得数组中的最大数,并取得位数;
  • arr为原始数组,从最低位开始取每个位组成radix数组;
  • 对radix进行计数排序(利用计数排序适用于小范围数的特点);

动图演示

代码实现

let array = randomArray(1, 120);

console.log(array);
radixSort(array);
console.log(array);
function radixSort(arr) {
  //定义一个二维数组,表示10个桶,每个桶就是一个一维数组
  //说明
  //1,二维数组包含10个一维数组,
  //2.为了防止在放入数的时候,数据溢出,则每个一维数组(桶)
  //大小定为arr.length
  //3.很明确,基数排序是使用空间换时间的经典算法
  let bucket = new Array(10);
  for (let i = 0; i < bucket.length; i++) {
    bucket[i] = new Array(arr.length);
  }
  //为了记录每个桶中,实际存了多少个数据,我们定义一个
  //一维数组来记录每个桶的每次放入的数据个数
  //可以这里理解
  //比如:bucketElementCounts[0],记录的就是bucket[0]桶的放入数据个数
  let buckeElementCounts = new Array(10).fill(0);
  //1.得到数组中最大的位数
  let max = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] > max) {
      max = arr[i]
    }
  }
  //得到最大是几位数
  let maxLength = (max + '').length;
  for (let i = 0, n = 1; i < maxLength; i++, n = n * 10) {
    //每一轮,对每个元素的各个位数进行排序处理,
    //第一次是个位,第二次是十位,第三次是百位
    for (let j = 0; j < arr.length; j++) {
      //取出每个元素的各位的值
      let digitOfElement = Math.floor(arr[j] / n) % 10;
      bucket[digitOfElement][buckeElementCounts[digitOfElement]] = arr[j];
      buckeElementCounts[digitOfElement]++;
    }
    //按照这个桶的顺序(以为数组的下标依次取出数据,放入原来数组)
    let index = 0;
    //遍历每一桶,并将桶中的数据,放入原数组
    for (let k = 0; k < buckeElementCounts.length; k++) {
    //如果桶中有数据,我们才放入原数组
    if (buckeElementCounts[k] !== 0) {
      //循环该桶即第k个桶,即第k个一维数组,放入
      for (let l = 0; l < buckeElementCounts[k]; l++) {
      //取出元素放入arr
        arr[index] = bucket[k][l];
        //arr下标后移
        index++;
      }
      //每轮处理后,下标要清0
      buckeElementCounts[k] = 0;
     }
    }
  }
}

打印结果

 算法分析

基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。

基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。

原文地址:https://www.cnblogs.com/ming1025/p/13896645.html