数据结构之队列

特性

他与队列都是一种受限的线性结构,但是我们知道栈结构做大的特性是先进后出,任何的操作都是基于栈顶的操作,而队列,则是先进后出,压栈在栈顶操作,而出栈则是在栈低进行操作;


基于数组实现


class Queue {
    arr: number[];
    constructor() {
        this.arr = [];
    }
    // 队列的操作;
    // 进入队列(从队列的顶部进行操作)
    enqueue(elemnet: number) {
        this.arr.push(elemnet)
    }
    // 删除队列(从队列的底部进行操作)
    dequeue() {
        this.arr.shift()
    }

}
let queue = new Queue();

就从代码复杂度来看,对列的代码与栈结构的复杂度差不多,没有什么太大的差别,但从性能来看,队列的性能远低于栈结构:如果只是单纯的增加的话,没有太大的区别,主要是出栈与出队列。出栈的话,他依旧是从栈顶进行操作,而整个栈结构并没有太大改变,无论里面的程序多呢复杂,运行起来都是相差无几的,但队列就不同了,出队列的话,则是从队列底部出栈,就单纯的论数组来看,每一次出栈,都会导致后面的元素重新排序,代码轻还行,但要是队列的复杂度、耦合度很高的话,使用对列就很麻烦了;

而这,也是队列性能低于栈结构的主要原因

优先级队列


用队列的方式进行排序

class PriorityQueue {
    arr?: { element: string, level: number }[];
    element?: string;
    level?: number;
    constructor() {
        this.arr = []
        this.element = ""
        this.level = 0
    }
    QueueElement(element: string, level: number) {
        this.element = element;
        this.level = level;
        return { element, level }
    }
    isEmpty() {
        return this.arr.length === 0
    }
    // 实现插入的方法
    enqueue(elment: string, level: number) {
        let queueElement = this.QueueElement(elment, level);
        // 情况一:判断队列是否为空;如果为空的话,直接放入
        if (this.isEmpty()) {
            this.arr.push(queueElement)
        } else {
            // 情况二:队列不为空,且用循环对比其等级,判断其插入的等级是否高于原数组的等级
            // 如果高于其中的某一等,就将其插入其元素之前
            // 并且这里做一个标记,用于检测循环中并未发现插入元素等级大于其所有元素,也就是说插入的元素的等级最低
            let addElenemt = false
            this.arr.forEach((item, index) => {
                if (this.level > item.level) {
                    this.arr.splice(index, 0, queueElement);
                    addElenemt = true
                    return
                }
            })
            // 如果元素的等级最低,则直接将其元素插值末尾
            if (!addElenemt) {
                this.arr.push(queueElement)
            }
        }

    }
}

let priorityQueue = new PriorityQueue();
priorityQueue.enqueue("moannian1", 1)
priorityQueue.enqueue("moannian2", 2)
priorityQueue.enqueue("moannian3", 3)

// 此刻的arr:[{element:"moannian3",level:3},{element:"moannian2",level:2}{element:"moannian1",level:1}]

使用两个队列模拟栈结构


解题:我们想要做这一题,首先我们先要了解什么是栈结构:先进后出,后进先出

           然后什么是队列:先进先出,后进后出

思路:双队列结构

这里,我们准备两个队列,一个是主队列,queue1,也就是我们主要存放队列的地方,一个是辅助队列queue2,是存放我们需要push的元素队列;首先我们先往辅助队列之中存储一个元素1;

此刻,我们检测到主队列为空了,将辅助队列赋值给主队列,然后将辅助队列清空,以便存入下一个元素

 对的,我的思路就是这样的,将主队列中的元素为空时,而辅助队列不为空时,然后就将赋值队列中的值赋值给主队列,然后将赋值队列清空;

此时就有人疑惑了,只是恰巧主队列为空罢了,容易互相转换,那万一主队列中有值,且赋值队列中也有值呢;(且一直记住这一点栈的结构特性)

那好,我们此时加入一个元素2(记住,push的元素,永远存储到辅助队列中)

此时我们看见了,主队列并未空,且辅助队列中又有元素2,那么此时我们应该做的,就是想办法做的是:将主队列清空,已达到主队列与辅助队列的转换条件,且主队列中的元素并不能丢失;

我们要做的便是,将主队列元素pop出来,然后作为push的元素压入到辅助队列之中;

此时的主队列就为空了,就达到了主队列为空,辅助队列就与主队列相转换的原则了,此时我们转换一下看一看

 我们暂时先不解释为什么这么做,我们先再按照以上的步骤在push一个元素3,且push的值依旧存储到辅助队列中

 然后如法炮制,将主队列中的元素1和2依次取出,记住主队列也是队列,他的取出顺序也是依赖队列的原则,队列底部的元素先出来,也就是元素2先出来

然后取出元素1

主队列与辅助队列转换

此刻,我们举的例子完全结束,我们来回归一下,注意,回顾过程中,我们只关注主队列,不关注辅助队列,辅助队列,只是一个辅助我们的逻辑作用,不在最终结果讨论范围内;

我们最先push了元素1,然后push了元素2,最后push了元素3

假设:我们按照正常的队列逻辑来走,先进先出的原则:取出的顺序应该是:1、2、3;

但经过了我们一系列操作,结果正的如此吗?

就如我们上图来看:最先出来的一定是3,然后是2,最后是1;

此出队列顺序,正和我们如队列的顺序一致:最后压入3,最先出来3;最先压入的1,却是最后出来的, 正好符合我们的栈结构:先入后出,后入先出原则;

解题思路完毕,思路来自Leetcode;

提供本人所写代码;

 


class MyStack {
    // 这里使用了两个数组来进行转换
    queue1?: number[];
    queue2?: number[];
    constructor() {
        this.queue1 = [];
        this.queue2 = [];
    }

    push(x: number): void {
        // 将push的元素压入辅助队列
        this.queue2.push(x);
        // 当主队列为空时转换,且清空赋值队列
        if (this.empty()) {
            this.queue1 = this.queue2;
            this.queue2 = [];
            return
        } else {
            // 如果主队列不为空时:将主队列中的值依次取出,且作为元素push到辅助队列中
            this.push(this.pop())
        }

    }

    // 出队列
    pop(): number {
        return this.queue1.shift();
    }
    // 这一步,始终指向栈顶元素
    top(): number {
        return this.queue1[0]
    }
    // 判断主队列是否为空
    empty(): boolean {
        return this.queue1.length === 0
    }
}



 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值