排序算法-基数排序

138 阅读2分钟

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

基数排序

介绍

基数排序 它是 计数排序 算法的进阶,当然它也是基于 的思想,来进行的排序算法。

基数排序 是通过每次 对比 相同位数的值,来进行分组。

分组后的数据需要放到下标为 0~9 不同的桶中,因为数据需要 先入先出,后入后出 的特性,所以这里使用 队列 这种数据结构的特性来进行保存。关于队列的讲解,这篇 数据结构-队列 有详细介绍。

直到最后位数所在值超过了 数据里面 最大的值即结束。

  • 动图演示

radixSort.gif

详解

  • 获取最大值

    善于用js的 ES6 语法很快

        const max = Math.max(...arr)
    
  • 定义一个桶的数组,里面是10个桶(队列)

    这里有个知识点,可以用 数组的 Array.from 来进行创建,它的 MDN 中有关于在 Array.from 中使用箭头函数 ,它的详细介绍,可以看下。

    • 用法如下

      Array.from({ length: 5 }, (item, index) => {
        console.log('item: ', item)
        console.log('index: ', index)
      })
      

      image.png

    • 创建的代码

          const buckets = Array.from({ length: 10 }, () => new Queue())
      
  • 创建位数,循环比较

    创建一个从 个位数 开始的值,每次循环后将位数 digit * 10 的操作,直到 这个值 大于 最大值结束。

      let digit = 1
      
      while (digit <= max){}
    
  • 队列

    关于队列的知识,可以查看 数据结构-队列 的讲解

    基数排序 中,也主要获取到数据项里每个值的 位数 后,进行 入队出队 操作,出队操作时,会判断 队列是否为空 的操作,依次出队,直到队列为空。

完整代码

    class Queue {
      constructor() {
        this.arr = []
      }

      enqueue(element) {
        this.arr.push(element)
      }

      dequeue() {
        return this.arr.shift()
      }

      front() {
        if (this.isEmpty()) return null
        return this.arr[0]
      }

      isEmpty() {
        return this.arr.length === 0
      }

      size() {
        return this.arr.length
      }

      find(index) {
        return this.arr[index]
      }

      clear() {
        this.arr = []
      }
    }

    /**
     * num 代表 当前数字, digit 代表位数 1,10,100
     * @param {number} num
     * @param {number} digit
     * @returns 当前数字 的 位数 对应的值
     */
    const getNum = (num, digit) => {
      // 如果 最小值 小于等于 num,说明 num 有这个位数,否则为 0
      return digit <= num ? Math.floor((num / digit) % 10) : 0
    }

    const radix_sort = (arr) => {
      // 获取最大的值
      const max = Math.max(...arr)

      // 定义一个桶数组,里面是10个队列
      const buckets = Array.from({ length: 10 }, () => new Queue())

      // 创建一个位数,循环比较
      let digit = 1
      while (digit <= max) {
        // 循环遍历数组里的值 入队
        arr.forEach((item) => {
          // 获取下标后,进行入队
          buckets[getNum(item, digit)].enqueue(item)
        })

        // 上面操作后, arr 已经没用了,进行置空操作
        arr = []

        // 出队
        buckets.forEach((item) => {
          // 如果该队列中 有值,则分别依次出队
          while (!item.isEmpty()) {
            arr.push(item.dequeue())
          }
        })

        digit = digit * 10
      }

      return arr
    }

总结

基数排序 是 非比较排序,是一种稳定的排序方式。

而且用到了 队列 的相关知识,是 计数排序 的进阶版。

缺点同计数排序一样。但是效率是比 计数排序 高。