JavaScript数据结构和算法----队列

前言

  队列和栈很像,只是用了不同的原则。队列是遵循先进先出(FIFO)原则的一组有序的的项,队列在尾部添加新元素,从顶部移除元素。最新添加的元素必须必须排队在队列的,末尾。可以想象食堂排队买饭的样子。

一、创建队列

  1、创建一种数据结构来保存队列里面的数据,这里选择数组
  2、声明一些栈的方法
  enqueue(element(s)) : 添加一个或一些元素到队列的末尾
  dequeue() : 移除队列第一个的元素(就是排队在最前面的),同时返回被移除的元素。
  front() : 返回队列第一个的元素(最先被添加的),仅仅是返回,不做任何修改。
  isEmpty() : 如果队列里面没有任何元素就返回true,否者为false。
  clear() : 清除队列里面的元素。
  size() : 返回队列里面的个数。

function Queue(){
    
    var items = [];

    this.enqueue= function(element){
        items.push(element);
    }

    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(){
        console.log(items.toString());
    } 
}

var queue = new Queue();
console.log(queue.isEmpty());
queue.enqueue('leaf');
queue.enqueue('jack')
console.log(queue.size());
console.log(queue.dequeue());
console.log(queue.isEmpty());
console.log(queue.size());

  

二、循环队列 --击鼓传花游戏

var nameList = ['leaf', 'jack', 'jef', 'rose', 'red', 'mandy', 'hardy', 'mark' ];
function cyclicGame(nameList){
    
    var queue = new Queue(),
        len = nameList.length;

    for(var i=0 ; i<len; i++){
        queue.enqueue(nameList[i]);
    }

    var weedOutName = '';
    while(queue.size()>1){
        for(var i=0; i<Math.floor(Math.random()*len); i++){
            queue.enqueue(queue.dequeue());//把第一个删除了添加后面
        }
        weedOutName = queue.dequeue();
        console.log(weedOutName + '第'+ (len-queue.size()) +'轮被淘汰了!');
    }

    return console.log(queue.dequeue() + '是最后的胜利者!');//最后一个元素,胜利者

}

cyclicGame(nameList);

  

三、事件队列管理

  JS的执行环境是单线程的,一次只能完成一个任务,其任务的调度方式就是排队,这就在医院挂号一样,前面的那个人没有搞定,你就只能站在后面排队等着。在事件队列中加一个延时,这样的问题便可以得到缓解,下面用代码模拟这个情景。

var Queue = {
    //保存队列信息
    items : [],
    //添加到队列
    enqueue : function(executeQueue){
        //添加到队列,如果不是函数或者数字的不处理
        if(!/function|number/.test(typeof executeQueue)){
            return;
        }

        Queue.items.push(executeQueue);
        //返回自身的引用
        return Queue;
    },
    //执行队列
    executeQueue : function(){
        //删除队列第一个元素并返回它
        var dequeue = Queue.items.shift();
        
        //如果队列为空的,直接返回
        if(!dequeue){
            return;
        }

        //如果是函数,直接执行,然后继续执行executeQueue
        if(typeof dequeue === "function"){
            dequeue();
            Queue.executeQueue();
            return;
        }

        //如果是数字,该数字作为延迟的时间, 延迟executeQueue
        setTimeout(function(){
            Queue.executeQueue();
            //console.log(dequeue);
        }, dequeue);
    }
};

//测试
Queue
//添加事件
.enqueue(function(){
    console.log('3秒之后执行第1个');
})
.enqueue(3000) 
.enqueue(function(){
    console.log('3秒之后执行第2个');
  })
.enqueue(3000)
.enqueue(function(){
    console.log('3秒之后执行第3个');
  })
//执行事件
.executeQueue();

  

四、看一个栗子--实现layMan的功能

实现:

lazyMan('leaf').eat('苹果').sleep(2).eat('雪梨').sleep(3).eat('香蕉')

采用事件队列的思想,根据队列的先后循序执行;

function LazyMan(name) {
        if(this.constructor !== LazyMan) {
          return new LazyMan(name)
        }
        //保存队列
        this.tasks = [];   
        var self = this;
        var fn =(function(n){
            var name = n;
            return function(){
                console.log("Hi! This is " + name + "!");
                self.next();
            }
        })(name);
        this.tasks.push(fn);

        //执行队列里面第一个事件
        setTimeout(function(){
            self.next();
        }, 0); 
    }

    /* 事件调度函数 */
    LazyMan.prototype.next = function() { 
        var fn = this.tasks.shift();
        fn && fn();
    }

    LazyMan.prototype.eat = function(name) {
        var self = this;
        var fn =(function(name){
            return function(){
                console.log("Eat " + name + "~");
                self.next()
            }
        })(name);
        this.tasks.push(fn);
        return this; // 实现链式调用
    }
    LazyMan.prototype.sleep = function(time) {
        var self = this;
        var fn = (function(time){
            return function() {
                setTimeout(function(){
                    console.log("Wake up after " + time + "s!");
                    self.next();
                }, time * 1000);
            }
        })(time);
        this.tasks.push(fn);
       return this;
    }
    LazyMan.prototype.sleepFirst = function(time) {
        var self = this;
        var fn = (function(time) {
            return function() {
                setTimeout(function() {
                    console.log("Wake up after " + time + "s!");
                    self.next();
                }, time * 1000);
            }
        })(time);
        this.tasks.unshift(fn);
        return this;
    }
    /* 封装 */
    function lazyMan(name){
        return new LazyMan(name);
    }

   //调用
    lazyMan('leaf').eat('苹果').sleep(2).eat('雪梨').sleep(3).eat('香蕉')

  

  

 

posted @ 2017-07-23 19:50  leaf+  阅读(291)  评论(0编辑  收藏  举报