学习JavaScript数据结构与算法(三)——队列

队列是遵循FIFO(First In First Out,先进先出,也称为先来先服务)原则的一组有序的项。
队列在尾部添加新元素,并从顶部移除元素。
最新添加的元素必须排在队列的末尾。
在现实中,最常见的队列的例子就是排队,排在第一位的人先接受服务。

一、创建队列

function Queue () {

    var items = [];

    /*
    enqueue(element(s))
    向队列尾部添加一个或多个新的项
     */
    this.enqueue = function(element){
        items.push(element);
    };

    /*
    dequeue()
    移除队列的第一(即排在队列最前面的)项,并返回被移除的元素
     */
    this.dequeue = function(){
        return items.shift();
    };

    /*
    front()
    返回队列中第一个元素(最先被添加,也将是最先被移除的元素)
    队列不做任何变动,不移除元素,只返回元素信息
     */
    this.front = function(){
        return items[0];
    };

    /*
    isEmpty()
    如果队列中不包含任何元素,返回true,否则返回false
     */
    this.isEmpty = function(){
        return items.length == 0;
    };

    /*
    clear()
    移除队列中的所有元素
     */
    this.clear = function(){
        items = [];
    };

    /*
    size()
    返回队列的元素个数
    和数组的length属性类似
     */
    this.size = function(){
        return items.length;
    };

    /*
    print()
    辅助方法,将队列中的元素输出到控制台
     */
    this.print = function(){
        console.log(items.toString());
    };

}

二、使用Queue类

var queue = new Queue();
console.log(queue.isEmpty());  //输出true

//添加一些元素
queue.enqueue("John");
queue.enqueue("Jack");
queue.enqueue("Ben");

queue.print();  //输出John,Jack,Ben
console.log(queue.size());  //输出3
console.log(queue.isEmpty());  //输出false
queue.dequeue();
queue.print();  //输出Jack,Ben
queue.dequeue();
queue.print();  //输出Ben

输出结果如下:

使用Queue类

三、优先队列

元素的添加和移除是基于优先级的。
举个例子,医院的(急诊科)候诊室,医生会优先处理病情比较严重的患者。

function PriorityQueue () {

    var items = [];

    /*
    创建一个特殊的元素
    这个元素包含了要添加到队列的元素(任意类型)及其在队列中的优先级
     */
    function QueueElement(element, priority){
        this.element = element;
        this.priority = priority;
    }

    /*
    添加元素
     */
    this.enqueue = function(element, priority){
        var queueElement = new QueueElement(element, priority);

        //如果队列为空,直接将元素入列
        if (this.isEmpty()) {
            items.push(queueElement);
        }
        //否则比较该元素与其他元素的优先级
        else {
            var added = false;
            for (var i = 0; i < items.length; i++) {
                /*
                当找到一个比要添加的元素的priority值更大(优先级更低)的项时,
                就把新元素插入到它之前
                (对于其他优先级相同,但是先添加到队列的元素,
                同样遵循先进先出的原则)
                 */
                if (queueElement.priority < items[i].priority) {
                    items.splice(i, 0, queueElement);
                    added = true;
                    break;
                }
            }
            /*
            如果要添加元素的priority值大于任何已有的元素,
            把它添加到队列的末尾就行了
             */
            if (!added) {
                items.push(queueElement);
            }
        }
    };

    /*其他方法与默认的Queue实现相同*/

    this.dequeue = function(){
        return items.shift();
    };


    this.front = function(){
        return items[0];
    };

    this.isEmpty = function(){
        return items.length == 0;
    };


    this.clear = function(){
        items = [];
    };

    this.size = function(){
        return items.length;
    };

    //与默认的稍有不同
    this.print = function () {
        var temp = [];
        for(var i = 0; i < items.length; i++){
            temp.push(items[i].element);
        }
        console.log(temp.toString());
    };

}

【注】处理添加元素的方法与默认的不一样外,还有print()方法也略有不同。
在默认的队列中,定义的items数组只存储了element,但是在优先队列中的items里,除了element,还有priority(优先级),这时候为了在控制台上只输出显示队列中的元素,就需要一个临时数组temp来存储element,具体实现看上面的代码。

测试代码如下:

var priorityQueue = new PriorityQueue();

priorityQueue.enqueue("John", 2);
priorityQueue.print();

priorityQueue.enqueue("Jack", 1);
priorityQueue.print();

priorityQueue.enqueue("Ben", 1);
priorityQueue.print();

第一个添加的元素是优先级为2的John,因为此前队列为空,所以它是队列中唯一的元素。
然后,添加优先级为1的Jack,由于Jack的优先级高于John,Jack就成了队列的第一个元素。
接下来,添加优先级为1的Ben,Ben的优先级高于John,所以在John前面;Ben的优先级和Jack相同,但Ben在Jack之后添加,所以Ben在Jack后面。

优先队列

四、循环队列——击鼓传花

在这个游戏中,孩子们围成一个圆圈,把花尽快传递给旁边的人,某一时刻传花停止,这个时候花在谁手里,谁就退出圆圈结束游戏,重复这个过程,直到只剩一个孩子(胜者)。

function hotPotato(nameList, num) {

    //将得到的名单全都加入队列
    var queue = new Queue();
    for (var i = 0; i < nameList.length; i++) {
        queue.enqueue(nameList[i]);
    }

    var eliminated = ''; //淘汰
    while (queue.size() > 1) {
        /*
        给定一个数字,迭代队列。
        从队列开头移除一项,再将其添加到队列末尾。
        如果你把花传给了旁边的人,你被淘汰的威胁立刻就解除了。
         */
        for (var i = 0; i < num; i++) {
            queue.enqueue(queue.dequeue());
        }
        //一旦传递次数达到给定的数字,拿着花的那个人就被淘汰了
        eliminated = queue.dequeue();
        console.log(eliminated + '在击鼓传花游戏中被淘汰。');
    }
    return queue.dequeue();
}

var names = ['John', 'Jack', 'Camila', 'Ingrid', 'Carl'];
var winner = hotPotato(names, 7);
console.log('胜利者:' + winner);

输出如下:

击鼓传花

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值