数据结构与算法之队列结构

半腔热情 提交于 2019-12-05 05:14:53

队列结构

  • 受限的线性结构
    • 之前我们总结了:栈结构
    • 并且已经知道这种受限的数据结构对于解决某些特定的问题,会有特别的效果
    • 这面文章,介绍了另外一个受限的数据结构:队列
  • 队列的结构:
    • 满足先进先出的一种结构
    • 受限之处:只允许在表的前端进行删除操作,表的后端进行插入操作
    • 抽象比喻:栈就是树立的杯子而队列就是横着的管道
  • 队列的应用:
    • 打印队列:这些文档会按照次序放入,优先的放入,优先的被取出
    • 线程队列:在开发中,为了让任务可以并行处理,通常会开启多个线程,但是我们不能让大量的线程同时运行处理(占用过多资源)。这个时候,如果有需要开启线程处理任务的话,就会使用线程队列,线程队列会依照次序来启动线程,并且处理任务

队列类的创建和常见操作

  • 队列的实现和栈一样,有两种方案
    • 基于数组实现
    • 基于链表实现
 // 封装队列
    function Queue() {
      //属性
      this.items = []

      //方法
      // 1.将元素加入到队列中
      Queue.prototype.enqueue = function (element) {  
        this.items.push(element)
      }
      // 2.从队列中删除前端元素
      Queue.prototype.dequeue = function () {  
        return this.items.shift()
      }
      // 3.查看前端元素
      Queue.prototype.front = function () {
        return this.items[0]
      }
      // 4.判断队列是否为空
      Queue.prototype.isEmpty = function () {
        return this.items.length == 0
      }
      // 5.获取队列中元素的个数
      Queue.prototype.size = function () {
        return this.items.length
      }
      // 6.toString方法
      Queue.prototype.toString = function () {
        //20  10  12 8  7
        let resultString = ''
        for (let i = 0; i < this.items.length; i++) {
          resultString += this.items[i] + ''
        }
        return resultString
      }
    }

    //使用队列
    var queue = new Queue()

    // 验证使用
    queue.enqueue('abc')
    queue.enqueue('cba')
    queue.enqueue('nba')
    queue.enqueue('mba')
    alert(queue)
    queue.dequeue()
    alert(queue)
    //....其他方法

击鼓传花算法面试题

击鼓传花规则

  • 几个朋友一起玩一个游戏,围城一圈开始数数数到某个数字的人自动淘汰
  • 最后剩下的这个人会获得胜利,请问最后剩下的是原来哪个位置上的人
  • 封装一个基于队列的函数:
    • 参数:所有参与人的姓名,基于的数字
    • 结果:最终剩下的一个人的姓名
  • 思路:将这几个人依此加入队列,然后将一个一个取出,每个取出的时候,就将其放入尾部,取出时,如果符合要求,就剔除

代码实现

//面试题,击鼓传花(使用了上面封装的队列类)
    function passGame(namelist, num) {
      //1.创建一个队列结构
      var queue = new Queue
      //2.所有人依此加入队列
      for (let i = 0; i < namelist.length; i++) {
        queue.enqueue(namelist[i])
      }
      //3.开始数数字
      while (queue.size() > 1) {
        //不是num的时候,重新加入到末尾,是num的时候,将其从队列中删除
        //3.1 num数字之前的人,依此放到末尾去
        for (let i = 0; i < num - 1; i++) {
          //先删除前端元素,再添加到尾部
          queue.enqueue(queue.dequeue())
        }
        //3.2 num对应的这个人,直接从队列中删除掉 
        //因为num对应的前面的人都放到后面去了,所以现在前端就是num对应的那个人
        queue.dequeue()
      }
        //获取最终剩下的那个人
        //获取最终剩下的那个人再原来的数组中是第一个位置

        var endName = queue.front()
        return (namelist.indexOf(endName)+1)+':'+endName
    }
     
    //测试击鼓传花
    names =['lili','lucy','tom','lilei','hy']
    console.log(passGame(names, 3))

优先级队列

  • 优先级队列:再插入一个元素的时候会考虑该数据的优先级,而不是直接插入
  • 和其他数据优先级进行比较
  • 比较完成后,可以得出这个元素再队列中正确的位置
  • 其他处理方式,和基本队列的处理方式一样
  • 优先级队列主要考虑的问题:
    • 每个元素不再只是一个数据,而且还包含数据的优先级
    • 再添加方式中,根据优先级放入正确的位置
  • 优先级队列的应用:
    • 登机顺序:头等舱和商务舱的优先级顺序

优先级队列的实现

  • 实现优先级队列相对队列主要有两仿麦呢的考虑:

    • 1.封装元素和优先级放在一起(可以封装一个新的构造函数)
    • 2.添加元素时,将新的插入元素的优先级和队列中已经存在的元素优先级进行比较,以获得自己正确的位置
  • 1.初步结构封装:

        //封装优先级队列
        function PrioritQueue(){
          //在封装一个类
          //类似java中的内部类,外部传入的两个数,但是内部对这两个数时有封装的
          function QueueElement(element,priorit){
            this.element = element
            this.priorit = priorit
          }
          //封装属性
          this.items = []
    
          //实现插入方法
          PrioritQueue.prototype.enqueue=function(element,priorit){
            //1.先创建QueueElement对象
            var queueElement = new QueueElement(element,priorit)
    
          }
        }
  • 2.优先级队列数据结构实现:

     //封装优先级队列
        function PrioritQueue() {
          //在封装一个类
          //类似java中的内部类,外部传入的两个数,但是内部对这两个数时有封装的
          function QueueElement(element, priorit) {
            this.element = element
            this.priorit = priorit
          }
          //封装属性
          this.items = []
    
          //实现插入方法
          PrioritQueue.prototype.enqueue = function (element, priorit) {
            //先创建QueueElement对象
            var queueElement = new QueueElement(element, priorit)
    
            //判断队列是否为空
            if (this.items.length == 0) {
              //如果为空,则能直接插入
              this.items.push(queueElement)
            } else {
              let added = false
              for (let i = 0; i < this.items.length; i++) {
                if (queueElement.priorit < this.items[i].priorit) {
                  this.items.splice(i, 0, queueElement)
                  added = true
                  break
                }
              }
              if (!added) {
                this.items.push(queueElement)
              }
            }
          }
          //(插以外,其他的操作与普通队列相同)
          // 2.从队列中删除前端元素
          PrioritQueue.prototype.dequeue = function () {
            return this.items.shift()
          }
          // 3.查看前端元素
          PrioritQueue.prototype.front = function () {
            return this.items[0]
          }
          // 4.判断队列是否为空
          PrioritQueue.prototype.isEmpty = function () {
            return this.items.length == 0
          }
          // 5.获取队列中元素的个数
          PrioritQueue.prototype.size = function () {
            return this.items.length
          }
          // 6.toString方法
          PrioritQueue.prototype.toString = function () {
            //20  10  12 8  7
            let resultString = ''
            for (let i = 0; i < this.items.length; i++) {
              resultString += this.items[i].element + '-' +this.items[i].priorit+ ' '
            }
            return resultString
          }
        }
        // 测试代码
        var pq = new PrioritQueue()
    
        //enqueue方法
        pq.enqueue('abc',111)
        pq.enqueue('cba',200)
        pq.enqueue('nba',50)
        pq.enqueue('nba',66)
        console.log(pq)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!