JavaScript数据结构之队列结构(基于数组实现)


一、队列是什么?

队列是一种受限的线性表,特点为先进先出(FIFO:first in first out)。
受限之处在于它只允许在表的前端(front)进行删除操作,在表的后端(rear)进行插入操作
例如:在食堂排队的学生就是一个队列,队列的前端最优先打到菜,然后离开队列,即在队列前端删除元素,学生也只能在队列的末尾加入队列进行排队,即在队列后端进行插入。

二、队列常见的应用

打印队列:计算机打印多个文件的时候,需要排队打印;

线程队列:当开启多线程时,当新开启的线程所需的资源不足时就先放入线程队列,等待CPU处理;

三、队列的实现

队列的实现和栈一样,有两种方案:

基于数组实现;

基于链表实现;

本篇代码使用数组实现。

四、队列的常见操作

enqueue(element):向队列尾部添加一个(或多个)新的项;
dequeue():移除队列的第一(即排在队列最前面的)项,并返回被移除的元素;
front():返回队列中的第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息与Stack类的peek方法非常类似);
isEmpty():如果队列中不包含任何元素,返回true,否则返回false;
size():返回队列包含的元素个数,与数组的length属性类似;
toString():将队列中的内容,转成字符串形式;

五、使用步骤

1.创建队列Queue类:

function Queue() {
            // 以数组形式存储队列数据
            this.items = [];

            // 在Queue类添加方法,可以使多对象复用
            // 在队列后端插入元素
            Queue.prototype.enqueue = function (element) {
                this.items.push(element);
            }
            // 判断是否为空
            Queue.prototype.isEmpty = function () {
                return this.items.length == 0;
            }

            // 在队列前端删除元素
            Queue.prototype.dequeue = function () {
                return this.items.shift();
            }

            // 查看队列前端的元素
            Queue.prototype.front = function () {
                return this.items[0];
            }

            // 获取队列中元素个数
            Queue.prototype.size = function () {
                return this.items.length;
            }

            // 以字符串形式输出元素
            Queue.prototype.toString = function () {
                // 加上空字符串隐式转换成字符串
                let result = '';
                for (let i of this.items) {
                    // 加上' '可以在元素中以空格隔开
                    result += i + ' ';
                }
                return result;
            }

            // 以上代码也可以写成ES6箭头函数形式如:
            // Queue.prototype.enqueue = (element) => {
            //     this.item.push(element);
            // }
        }

2.使用队列:

 // 使用队列
        let q = new Queue();

        // 将数据插入队列中
        q.enqueue(10);
        q.enqueue(20);
        q.enqueue(30);
        q.enqueue(40);

        // 队列前端的元素删除(10)
        console.log(q.dequeue());

        // 查看队列前端的元素(20)
        console.log(q.front());

        // 查看栈是否为空(false,目前栈还有3个元素)
        console.log(q.isEmpty());

        // 查看队列元素个数(3)
        console.log(q.size());

        // 转化成以空格隔开的字符串形式(20 30 40)
        console.log(q.toString());

3.控制台

在这里插入图片描述

六、使用队列结构解决问题

使用队列实现小游戏
击鼓传花:一群学生手拉手按照顺序围成一圈并从第一个人开始向下一个人传递一束花,班长站在旁边打鼓(班长不在这群学生中),当鼓声停止时,鲜花落在哪个学生手中,哪位学生就被淘汰, 以此类推,直到只剩最后一位学生时,求这位学生在之前圈中的排序是第几位?
修改一下鼓声为具体的某个值,如数到数值:5就代表圈中第五位学生遭到淘汰。
需求:传入一组数据和设定的数字num,循环遍历数组内元素,遍历到的元素为指定数字num时将该元素删除,直至数组剩下一个元素。

//使用队列实现小游戏:
     //击鼓传花:一群学生手拉手按照顺序围成一圈并从第一个人开始向下一个人传递一束花,班长站在旁边打鼓(班长不在这群学生中),当鼓声停止时,鲜花落在哪个学生手中,哪位学生就被淘汰,
     //以此类推,直到只剩最后一位学生时,求这位学生在之前圈中的排序是第几位?
     //修改一下鼓声为具体的某个值,如数到数值:5就代表圈中第五位学生遭到淘汰。
     //需求:传入一组数据和设定的数字num,循环遍历数组内元素,遍历到的元素为指定数字num时将该元素删除,直至数组剩下一个元素

     //es6的箭头函数,传入list代表除班长外的所有学生,num表示数到第几个数
     let game = (list, num) => {
         // 使用队列
         let q = new Queue()
         // 将所有人存进队列中
         for (let item of list) {
             q.enqueue(item)
         }
         //开始数数
         // 遍历到只剩最后一个人
         while (q.size() > 1) {
             // 因为队列只能前端删除元素,不能根据索引删除元素,故将数到num之前的元素先删除的同时加入到队列的后端
             // i从0开始,所以num要减1,因为学生个数是从1开始
             for (let i = 0; i < num - 1; i++) {
                 q.enqueue(q.dequeue())
             }
             // 将num之前的元素删除之后,队列的前端现在是数到num的需要被删除的那个数
             //将他删除
             q.dequeue()
         }
         // 查看是否只有一位学生
         console.log(q.size())
         // 查看位于前端的最后一位学生
         console.log(q.front())
         // 返回位于前端的最后一位学生的初始排序
         return list.indexOf(q.front())
     }

     let nameList = ['刘德华', '张学友', '郭富城', '周星驰', '黎明'];
     // 测试
     console.log("最后一位学生的初始排序为" + game(nameList, 3));

控制台:
在这里插入图片描述

七、优先级队列

优先级队列普通队列区别:
普通队列:只能在队列后端插入,从队列前端开始执行
优先级队列:插入元素时需要考虑优先级,根据优先级来进行排序。如:在医院急救科可能会出现很多病人同时求医,但考虑有些病人病情危重优先治疗,病情轻微就略微靠后的情况。这就是优先级队列在生活中的体现。

1.创建优先级队列

 // 创建优先级队列,传入element元素和priority优先级(注意:本篇代码以数字越小优先级越高为例)
        function priorityQueue(element, priority) {
            this.items = [];
            // 在priorityQueue类中再创建一个类QueueElement,代表每一个元素的内容和优先级(可以理解为类中类)
            function QueueElement(element, priority) {
                this.element = element
                this.priority = priority
            }
            //   插入元素
            priorityQueue.prototype.enqueue = (element, priority) => {
                // 创建QueueElement对象,表示每个需要操作的元素,将内容和优先级传入
                var queueElement = new QueueElement(element, priority);
                // 判断队列是否为空,为空不需要判断优先级,直接插入
                if (this.items.length == 0) {
                    this.items.push(queueElement)
                } else {
                    // 由于下方的循环有可能出现循环完后,元素还没有插入,即元素的优先级比当前队列中的所有元素的优先级都高,需要做一个判断
                    // 故定义一个变量来判断循环完后是否已插入
                    var flag = false
                    // 不为空,判断与队列中的所有元素进行优先级比较
                    for (var i = 0; i < this.items.length; i++) {
                        // 如果要插入的元素优先级比队列的第i个元素的优先级低,那么使用数组的splice方法,在i元素前插入该元素
                        // splice(i,0,queueElement)第一个参数表示在i位置前插入元素,第二个参数表示从i位置开始删除几个元素,当前是0即表示不删除元素
                        // 第三个参数表示插入的元素
                        if (queueElement.priority < this.items.priority) {
                            this.items.splice(i, 0, queueElement);
                            // 已插入让flag为true
                            flag = true;
                            // 元素已经插入不需要继续循环
                            break
                        }
                    }
                    // 当flag为false表示上方循环结束后,元素依然没插入,该元素的优先级最大,在末尾直接插入
                    if (!flag) {
                        this.items.push(queueElement)
                    }
                }
            }
            // 判断是否为空
            priorityQueue.prototype.isEmpty = function () {
                return this.items.length == 0;
            }

            // 在队列前端删除元素
            priorityQueue.prototype.dequeue = function () {
                return this.items.shift();
            }

            // 查看队列前端的元素
            priorityQueue.prototype.front = function () {
                return this.items[0];
            }

            // 获取队列中元素个数
            priorityQueue.prototype.size = function () {
                return this.items.length;
            }

            // 以字符串形式输出元素
            priorityQueue.prototype.toString = function () {
                // 加上空字符串隐式转换成字符串
                let result = '';
                for (let i of this.items) {
                    // 加上' '可以在元素中以空格隔开
                    result += i.element + i.priority + ' ';
                }
                return result;
            }
        }

2.使用优先级队列

 // 测试代码
        var pq = new priorityQueue();
        // 插入元素
        pq.enqueue('张学友', 100);
        pq.enqueue('刘德华', 200);
        pq.enqueue('周星驰', 300);
        pq.enqueue('周杰伦', 400);
        // 判断为空(false)
        console.log(pq.isEmpty())
        // 删除前端元素('张学友',100)
        console.log(pq.dequeue())
        // 查看前端元素('刘德华',200)
        console.log(pq.front())
        // 查看队列元素个数(3)
        console.log(pq.size())
        // 字符串输出
        console.log(pq.toString())

3.控制台

在这里插入图片描述


总结

由于个人自身水平有限,本篇文章仅代表个人理解,如有错误,欢迎指正!与君共勉!

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值