队列与基数排序

63 阅读3分钟

什么是队列

  • 队列是一种列表,不同的是队列只能再队尾插入元素(push),再队首取出元素(shift)。是一种先入先出的数据结构。

队列与基数排序

  • 对于0~99的数字从小到大排序,基数排序将数据集扫描两次:
    • 第一次将数据按照个位数进行排序
    • 第二次将数据按照十位数进行排序
  • 每个数字根据对应位上的数值分在不同队列里。
  • 基数排序不是最快的排序算法,但是对于整数排序且数值范围不是特别大情况来说,它的时间复杂度是O(nk) ,其中n是排序元素的数量,k是数字的最大位数。而快速排序的时间复杂度是O(nlogn)。
  • 但是展示了队列的基本操作。
// 创建10个队列
let q = Array.from({length: 10}, () => []);
// 生成0~99的10个随机数
let nums = Array.from({length: 10}, (v, i) => Math.floor(Math.floor(Math.random() * 100)));

// 分别对个位数和十位数进行排序
function dis(nums, q, digit) {
    for (let i = 0; i < 10; i++) {
        // digit === 1 则对个位数排序,digit === 10 则对十位数排序
        if (digit === 1) {
            // 获取个位数作为索引,并将数字插入对应索引的数组中
            q[nums[i] % 10].push(nums[i]);
        } else {
            // 获取十位数作为索引,并将数字插入对应索引的数组中
            q[Math.floor(nums[i] / 10)].push(nums[i]);
        }
    }
}

// 获取排序后的数组
function collect(nums, q) {
    let index = 0;
    // 最简单的办法使用flat铺平,这里为了模拟队列的先入先出。
    // nums = q.flat();
    q.forEach((v, i) => {
        // 遍历每个队列的存储矩阵,将矩阵中的数字插入原数组中
        while (v.length > 0) {
            // 从队首取出
            nums[index++] = v.shift();
        }
    });
}

console.log('排序前:', nums.join(','));
// 对个位数进行排序
dis(nums, q, 1);
collect(nums, q);
console.log('个位数排序后:', nums.join(','));
// 对十位数进行排序
dis(nums, q, 10);
collect(nums, q);
console.log('十位数排序后:', nums.join(','))
  • 使用push模拟队尾插入元素,使用shift模拟队首取出元素。
  • 假设排列以下数字:
    • 91,45,21,0,67,3,12,93
  • 第一次扫描,对个位数排序,分到如下队列中:
    • 0: [0]
    • 1: [91,21]
    • 2: [12]
    • 3: [3,93]
    • 4: []
    • 5: [45]
    • 6: []
    • 7: [67]
    • 8: []
    • 9: []
  • 第一次后的排序结果如下:
    • 0,91,21,12,3,93,45,67
  • 第二次扫描,对十位数排序,分到如下队列中:
    • 0: [0,3]
    • 1: [12]
    • 2: [21]
    • 3: []
    • 4: [45]
    • 5: []
    • 6: [67]
    • 7: []
    • 8: []
    • 9: [91,93]
  • 第二次后的排序结果如下:
    • 0,3,12,21,45,67,91
  • 因为最大只有两位数,所以只需要排序两次,最后的排序结果就是:
    • 0,3,12,21,45,67,91

取出元素为什么不用pop而用shift

  • 维持队列的先入先出机制,这样才能保留上一次排序后的结果,再上一次的排序结果下进行再次排序和取值。
恐有疏漏,如有发现,敬请指正,十分感谢!