[路飞]前端算法——数据结构篇(二、队列): 初识队列

382 阅读4分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

总结: 队列是一种常用的数据结构,是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

前言

前端算法系列是我对算法学习的一个记录, 主要从常见算法数据结构算法思维常用技巧几个方面剖析学习算法知识, 通过LeetCode平台实现刻意练习, 通过掘金和B站的输出来实践费曼学习法, 我会在后续不断更新优质内容并同步更新到掘金、B站和Github, 以记录学习算法的完整过程, 欢迎大家多多交流点赞收藏, 让我们共同进步, daydayup👊

目录地址:目录篇

相关代码地址: Github

相关视频地址: 哔哩哔哩-百日算法系列

一、什么是队列

队列可能是我们日常生活中见到最多的一种数据结构, 例如我们每天进地铁时需要排队过安检、中午吃饭时需要排队打饭等, 都是队列在生活中的体现, 作为一种 线性表结构 我们通常将队列做对比, 相比与栈的先入后出, 队列则秉持先入先出的原则.

我们把从队尾插入数据的过程叫 入队

我们把从队首删除数据的过程叫 出队

388236c6f099177093544d853d505b9f.jpeg

二、队列的特性

对比栈的特性, 队列有如下特下:

  • 两端操作
  • 先入先出原则

无它, 记住先入先出就好.

三、队列的应用

关于队列的应用, 我们最熟悉的莫过于浏览器中的消息队列, 个人理解其实队列最大的作用就在于限流和缓冲, 它使得我们可以将一些现在来不及处理的事情按照顺序的存储起来, 在我们解决了当下的事情之后, 在未来按计划处理剩余的事情.

  • 线程池的任务队列

image.png

当一个进程之后涉及到频繁的线程创建和销毁时, 因为线程的创建代价很大, 为了让我们的线程不被频繁的创建和删除,所以我们提出线程池的概念, 而线程池中的线程是有数量限制的, 当线程池的任务不能处理大量的并发任务时, 我们可以创建一个队列用来缓冲.

  • CPU的超线程技术
  • 线程池的任务队列
  • 任务调度器
  • 迷宫问题
  • 杨辉三角
  • 斐波那契数列
  • 二叉树的广度优先搜索(BFS)

(求补充...)

其实, 像栈和队列这样简单的数据结构, 越简单应用的范围就越广, 同时也越基础, 很多时候只是作为算法的一小部分来展现.

四、队列的前端实现

关于队列的基础实现通常情况下有两种, 一种是通过数组实现的顺序队列, 还有一种是通过链表实现的链式队列, 两种方法实现的差别主要是数组与链表之间的差别.

此外, 在简单队列的基础上, 我们还有循环队列双端队列单调队列优先队列等应用于不同场景的实现方式, 但这并不是本文的主要内容, 将会在后续队列文章中再做解析.

// 数组实现
function Queue(k) {
  let head = 0
  let tail = 0
  let items = new Array(k)

  // 尾部追加元素
  this.enqueue = function (item) {
    if (this.isFull()) return -1
    items[tail] = item
    tail++
  }

  // 头部删除元素
  this.dequeue = function () {
    if (this.isEmpty()) return
    head++
  }

  // 返回队列头部
  this.head = function () {
    return items[head]
  }

  // 返回队列尾部
  this.tail = function () {
    return items[tail]
  }

  // 队列的大小
  this.size = function () {
    return tail - size
  }

  // 是否空队列
  this.isEmpty = function () {
    return tail === head
  }
  
  // 是否满
  this.isFull = function () {
    return tail === items.length
  }

  // 清空队列
  this.clear = function () {
    items = new Array(k)
  }

  // 打印
  this.print = function () {
    console.log(items)
  }
}

五、队列的算法练习

// leetcode: https://leetcode-cn.com/

LeetCode #621 任务调度器 

LeetCode #622 设计循环队列 

LeetCode #641 设计循环双端队列 

LeetCode #1670 设计前中后队列 

LeetCode #933 最近的请求次数 

LeetCode #面试题1709 第K个数 

LeetCode #859 亲密字符串 

LeetCode #860 柠檬水找零 

LeetCode #969 煎饼排序 

LeetCode #86 分隔链表 

LeetCode #138 带随机指针的链表