今天,我们要讲的是数据结构与算法中的队列。

队列简介

队列是什么?队列是一种先进先出(FIFO)的数据结构。队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如:

  • 在图的广度优先遍历中,我们需要使用队列来记录每个节点的相邻节点,以便可以在接下来最先访问它们,从而实现广度优先遍历。
  • 在 JavaScript 事件循环(Event Loop)中有一个事件队列(Task Queue),也是先进先出来处理各种异步事件。
  • 在生活中,队列可以映射排队打饭等先来后到的场景。

用 JavaScript 编写队列类

《JavaScript 版数据结构与算法(一)栈》中编写栈类的方法类似,编写队列类也使用了构造器函数。

编写一个队列类,可以跑通如下测试:

var queue = new Queue();
expect(queue.isEmpty()).toBeTruthy();
queue.enqueue('张三');
queue.enqueue('李四');
queue.enqueue('王五');
expect(queue.front()).toBe('张三');
expect(queue.toString()).toBe('张三,李四,王五');
expect(queue.size()).toBe(3);
expect(queue.isEmpty()).toBeFalsy();
queue.dequeue();
queue.dequeue();
expect(queue.toString()).toBe('王五');

队列类比较简单,直接上代码:

function Queue() {
  // 私有变量 items,用于记录数组
  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.size = function () {
    return items.length;
  };
  // 将数组转为字符串并返回
  this.toString = function () {
    return items.toString();
  };
}

// 导出队列类
module.exports = Queue;

请注意数组增删的四个方法,别搞混淆了:

  • push:在尾部添加新元素
  • pop:删除并返回尾部元素
  • unshift:在头部添加新元素
  • shift:删除并返回头部元素

所以,出队的方法用的是 shift。另外,如果考虑时间复杂度,使用数组创建队列并不是一个好方法,因为出队时,所有的元素都会移动位置,造成较差的性能。而使用链表则会更好,因为链表不是连续存储的,增删元素只需要改变相关的指向即可。

优先队列:加队就是这么任性

普通的队列类就是调用原生 Array 对象的方法,比较简单,但是还有一种队列叫优先队列。在优先队列里面,有些人比较霸道,可以加队。不过,如果遇到比他更霸道的人,他也得老实在后面排着。举个例子吧!假设有三个人:张三、李四、王五。王五是个没本事的老实人。张三是个小流氓,经常欺负王五。李四呢?是个官老爷。他们三个排队,小流氓张三先来,官老爷李四第二个来,老实人王五最后来。结果,张三给李四让道,王五还是排在最后。在优先队列里,我们使用优先级(priority)来描述霸道程度。

var priorityQueue = new PriorityQueue();
priorityQueue.enqueue('张三', 2);
priorityQueue.enqueue('李四', 1);
priorityQueue.enqueue('王五', 3);
expect(priorityQueue.toString()).toBe('李四-1,张三-2,王五-3');

上述代码中,名字后面的数字就是优先级。排队结果就如最后一个断言所示:'李四-1,张三-2,王五-3'

为了实现上述测试用例,我们需要改写 enqueue 方法和toString方法:

function PriorityQueue() {
  var items = [];

  // 利用构造器函数创建队列元素
  var QueueElement = function (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++) {
        if (queueElement.priority < items[i].priority) {
          // 李四的情况
          items.splice(i, 0, queueElement);
          added = true;
          break;
        }
      }
      // 王五的情况
      if (!added) {
        items.push(queueElement);
      }
    }
  };

  ...

  this.toString = function () {
    var string = '';
    for (var i = 0; i < items.length; i++) {
      string += items[i].element + '-' + items[i].priority + (items.length - i > 1 ? ',' : '');
    }
    return string;
  };
}

module.exports = PriorityQueue;

因为这三个人正好代表了所有的情况,所以只要将测试用例跑通,逻辑就写完了。为何会如此?其实我当时在写测试用例时,故意将代码覆盖率刷到100%。也就是说,测试用例涵盖了所有的情况。toString 方法则是则是多打印了一个优先级而已,其他方法与普通队列一样,不再赘述。

教程示例代码及目录

示例代码:https://github.com/lewis617/javascript-datastructures-algorithms

目录:http://www.liuyiqi.cn/tags/数据结构与算法/

JavaScript 版数据结构与算法(二)队列的更多相关文章

  1. JavaScript 版数据结构与算法(三)链表

    今天,我们要讲的是数据结构与算法中的链表. 链表简介 链表是什么?链表是一种动态的数据结构,这意味着我们可以任意增删元素,它会按需扩容.为何要使用链表?下面列举一些链表的用途: 因为数组的存储有缺陷: ...

  2. JavaScript 版数据结构与算法(四)集合

    今天,我们要讲的是数据结构与算法中的集合. 集合简介 什么是集合?与栈.队列.链表这些顺序数据结构不同,集合是一种无序且唯一的数据结构.集合有什么用?在 Python 中,我经常使用集合来给数组去重: ...

  3. JavaScript 版数据结构与算法(一)栈

    今天,我们要讲的是数据结构与算法中的栈. 栈的简介 栈是什么?栈是一个后进先出(LIFO)的数据结构.栈有啥作用?栈可以模拟算法或生活中的一些后进先出的场景,比如: 十进制转二进制,你需要将余数倒序输 ...

  4. Java数据结构和算法(二)--队列

    上一篇文章写了栈的相关知识,而本文会讲一下队列 队列是一种特殊的线性表,在尾部插入(入队Enqueue),从头部删除(出队Dequeue),和栈的特性相反,存取数据特点是:FIFO Java中queu ...

  5. JavaScript数据结构与算法(二) 队列的实现

    TypeScript方式源码 class Queue { items = []; public enqueue(element) { this.items.push(element); } publi ...

  6. Android版数据结构与算法(二):基于数组的实现ArrayList源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本片我们分析基础数组的实现--ArrayList,不会分析整个集合的继承体系,这不是本系列文章重点. 源码分析都是基于"安卓版" ...

  7. Python实现的数据结构与算法之队列详解

    本文实例讲述了Python实现的数据结构与算法之队列.分享给大家供大家参考.具体分析如下: 一.概述 队列(Queue)是一种先进先出(FIFO)的线性数据结构,插入操作在队尾(rear)进行,删除操 ...

  8. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  9. JavaScript版EAN码校验算法

      <script type="text/javascript"> $(document).ready(function () { $("#btnCalc&q ...

随机推荐

  1. spring 整合Mybatis 《报错集合,总结更新》

    错误:java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExcepti ...

  2. ROS学习记录(一)————创建简单的机器人模型smartcar

    这是我在古月居上找的(http://www.guyuehome.com/243),但直接运行的话,没办法跑起来,我也是查了好多博客和日志,才实现最后的功能的,所以,记录下来,以备后用吧,也欢迎其他和我 ...

  3. Google推出移动网页开发者认证考试 价格99美元

    如果您是移动网页开发人员,希望了解您的编码实力,Google将推出一个认证流程,让您可以参加考试,如果您通过,可以在您的简历,网站和其他在线上显示电子徽章配置文件.           此外,潜在的雇 ...

  4. bootstrap 基础(二)

    1 栅格系统偏移 栅格系统的偏移只能向右:col-xs-offset-x. <!DOCTYPE html> <html lang="en"> <hea ...

  5. 汇编指令-位置无关码(BL)与绝对位置码(LDR)(2)

    位置无关码,即该段代码无论放在内存的哪个地址,都能正确运行.究其原因,是因为代码里没有使用绝对地址,都是相对地址.  位置相关码,即它的地址与代码处于的位置相关,是绝对地址 BL :带链接分支跳转指令 ...

  6. 交换机的Ethernet Channel

    端口聚合也叫做以太通道(ethernet channel),主要用于交换机之间连接.由于两个交换机之间有多条冗余链路的时候,STP会将其中的几条链路关闭,只保留一条,这样可以避免二层的环 路产生.但是 ...

  7. 201521123084 《Java程序设计》第4周学习总结

    第4周作业-面向对象设计与继承 1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 总结: (1)学会了如何给类和方法进行简单的注释: (2)学 ...

  8. Java单元测试之JUnit篇

    单元测试是编写测试代码,应该准确.快速地保证程序基本模块的正确性. 好的单元测试的标准 JUnit是Java单元测试框架,已经在Eclipse中默认安装. JUnit4 JUnit4通过注解的方式来识 ...

  9. 201521123034《Java程序设计》第六周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  10. 201521123009 《Java程序设计》第10周学习总结

    1. 本周学习总结 2. 书面作业 本次PTA作业题集异常.多线程 Q1:finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中finally中捕获异常需要注意什么? tr ...