JS版数据结构第二篇(队列)

栏目: 数据库 · 发布时间: 5年前

内容简介:相信通过上篇博客大家对栈有了一个大概的认识,今天我们开始对队列的学习。我们还是先看一下百度百科上对

本片博客参考到银国徽老师的《Js版数据结构与算法》

队列

队列的定义

相信通过上篇博客大家对栈有了一个大概的认识,今天我们开始对队列的学习。

我们还是先看一下百度百科上对 队列 的定义:

JS版数据结构第二篇(队列)

说白了就是队列是一种受限的线性表,''受限''体现在只能从表的前端(队头)进行删除,只能从表的后端(队尾)进行插入。接下来我还是用一个比喻更形象的说明一下我对队列的理解。

队列的理解

相信大家平时都会路过一些网红店如‘喜茶’,‘一点点’,‘BONUS’(雇人排队的行为不值得提倡:grinning:),每次路过时都是门庭若市,我家楼下的也有一家烤肠店,每到周末都会排起很长的队伍。

JS版数据结构第二篇(队列)

图 1

这个时候排队的大家就形成了一个 队列

图片中最前面的蓝色衣服的大叔就是 队头

在最后面拍照片的我呢就是 队尾

这时候当大叔交完钱拿到自己的烤肠后就可以离开我们的'队列'(称为 出队 ,只能从队头离开)

如果隔壁家的小孩被馋哭了的话他也只能去我的后面开始排队(称为 入队 ,只能从队尾入队)

注意: 大叔是先去排队的,所以他也是先拿到自己的烤肠离开的,小朋友是后来的,所以他也会后拿到自己的烤肠,这也就是我们常说的' 先进先出 '。

对比栈的 后进先出 ,是不是还挺有趣的?

js实现一个简单的顺序队列

首先我们要清楚的是队列分为 顺序队列 和循环队列,上边的例子我们排队买烤肠就是顺序队列,至于循环队列我会在接下来的例题中进行说明,我们先实现一个简单的顺序队列。

JS版数据结构第二篇(队列)

图 2

队列有两个指针,分别为队头指针front和队尾指针rear,

front指向队头元素,rear指向下一个入队元素的存储位置。(如图2)

下方的ArrayQuene函数就实现一个简单功能的顺序队列:

function ArrayQueue(){  
    var arr = [];  
        //入队操作  
    this.push = function(element){  
        arr.push(element);  
        return true;  
    }  
        //出队操作  
    this.pop = function(){  
        return arr.shift();  
    }  
        //获取队首  
    this.getFront = function(){  
        return arr[0];  
    }  
        //获取队尾  
    this.getRear = function(){  
        return arr[arr.length - 1]  
    }  
        //清空队列  
    this.clear = function(){  
        arr = [];  
    }  
        //获取队长  
    this.size = function(){  
        return length;  
    }  
}  复制代码

例题:设计循环队列

循环队列理解

在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。

这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。除了一些简单应用之外,真正实用的队列是循环队列。

在上文中提到过顺序队列中有两个指针,front指向队头元素,rear指针指向下一个入队的元素的存储位置。结合下面这张图我们分析一下循环队列在不同情况下front指针和rear指针的指向。

JS版数据结构第二篇(队列)

 图 3

  • (a)在初始空队时,front和rear指针同时指向队头初始的位置(即0的位置,队列长度为6)
  • (b)a,b,c三个元素入队时,rear指针会随着添加元素的个数移动到相应的位置(三个元素,向前移动1位,此时rear由0移动到3)
  • (c)a出队,front指针也会随着删除元素的个数移动到相应的位置(删除1个元素,向前移动1位,此时front由0移动到1)
  • (d)d,e,f,g入队,rear向前移动4位,由3移动到1,此时队列空间全部占满,rear和front同时指向1
  • (e)g出队(由于g处于队头的位置,所以可以出队),front向前移动1位,由0移动到1

相信大家对循环队列有了一个初步的认识,话不多说,我们直接上例题

例题

原题地址(LeetCode 622题)

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k)
Front
Rear
enQueue(value)
deQueue()
isEmpty()
isFull()

题目不是很难,我们简单的分析一下题目里面需要我们实现的操作:

  • 建立一个长度为k的数组arr,并声明front和rear指针,初始值都设置为0,当插入或删除元素时我们需要手动操作指针的位置。
  • 队首元素直接返回arr[front]即可。
  • 如果rear不指向0时,队尾元素是arr[rear-1],如果rear指向0的时候队尾元素就是arr[k-1]。
  • 插入元素,直接将插入元素赋值给arr[rear],注意要先判断下队列是否是满的状态。
  • 删除元素,将元素arr[front]赋值为空,注意要先判断一下队列是否是空的状态。
  • 检查队列是否为空,当front和rear的指向相同且队首元素也为空时,队列为空。
  • 检查队列是否已满,当front和rear的指向相同且队首元素有值时,队列已满。

代码如下:

class MyCircularQueue{
        // 构造器
        constructor (k) {
            // 建立长度为k的循环队列
            this.arr= Array(k)
            // 声明队首指针front
            this.front = 0
            // 声明队尾指针rear
            this.rear = 0     
        }
        // 获取队首元素
        Front () {
            // 如果队列为空,返回-1 否则直接返回front指向的值
            return this.isEmpty()? -1 : this.arr[this.front]
        }
        // 获取队尾元素
        Rear () {
            // 如果此时rear指针指向0的位置,返回队列最后一位,否则返回下一位
            let rearItem = rear -1 
            return this.arr[rearItem < 0 ? k-1 : rearItem]
        }
        // 插入元素
        enQuene (value) {
            // 先判断队列是否是已满状态
            if(this.isFull()){
                return false
            }else{
                // 插入元素
                this.arr[this.rear] = value
                // 移动rear指针位置,考虑到循环队列指针的变动,用取模的方式
                this.rear = (this.rear+1) % k
                return true
            }
        }
        // 删除元素
        deQuene () {
            // 先判断队列是否为空
            if(this.isEmpty()){
                return false
            }else{
                let deleteItem = this.arr[this.front]
                this.arr[this.front] = ''
                this.front = (this.front+1) % k
                return deleteItem
            }
        }    
        // 判断队列是否为空
        isEmpty () {
            // 头尾指针指向同一个地址并且队首元素为空
            retutn this.rear === this.front && !this.arr[this.front]
        }
        // 判断队列是否已满
        isFull () {
            // 头尾指针指向同一个地址并且队首元素不为空
            return this.rear === this.front && !!this.arr[this.front]
        }
    }复制代码

总结

栈和队列是相对简单的数据结构,相信通过两篇博客大家对这两种数据结构都有了简单的认识,接下来我将介绍相对复杂一些的数据结构。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ggplot2:数据分析与图形艺术

ggplot2:数据分析与图形艺术

哈德利·威克姆 (Hadley Wickham) / 统计之都 / 西安交通大学出版社 / 2013-5-1 / CNY 46.00

中译本序 每当我们看到一个新的软件,第一反应会是:为什么又要发明一个新软件?ggplot2是R世界里相对还比较年轻的一个包,在它之前,官方R已经有自己的基础图形系统(graphics包)和网格图形系统(grid包),并且Deepayan Sarkar也开发了lattice包,看起来R的世界对图形的支持已经足够强大了。那么我们不禁要问,为什么还要发明一套新的系统? 设计理念 打个比......一起来看看 《ggplot2:数据分析与图形艺术》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具