定义
队列这两个词就很好的说明了它的特点,就是先进先出,不然排对也没有什么意义了。
特点:
- 受限操作:限定只能在队列的前端进行删除操作,只能在队列的后端进行插入操作。
- 进行插入操作的一端称为队尾,进行删除操作的一端称为队头。
- 增加元素的操作称为入队列 ,意思是把元素添加到队尾的位置。
- 删除元素的操作称为出队列 ,意思是把元素从队头位置移除。
队列也是一个逻辑结构,跟栈一样,我们可以使用数组或链表来实现。
用两个栈实现一个队列
思路:
- 把数据push到其中一个stack1中
- 首先把stack1的所有元素移动到stack2中,因为是栈的结构,只能操作队尾的元素,即使用pop,然后push到stack2中
- 这个时候stack2中的元素的顺序与stack1相反,即stack1中的队首元素现在在stack2中的队尾,然后pop出来,删除的就是最新进入的那个元素
- pop删除之后,再把stack2中的元素转移到stack1中
export class MyQueue {
private stack1: number[] = []
private stack2: number[] = []
add(n: number) {
this.stack1.push(n)
}
delete(): number | null {
let res
const stack1 = this.stack1
const stack2 = this.stack2
// 将stack1所有元素移动到stack2中
while (stack1.length) {
const n = stack1.pop()
if (n != null) {
stack2.push(n)
}
}
// stack2 pop 执行删除操作
res = stack2.pop()
// 将stack2所有元素还给stack1
while (stack2.length) {
const n = stack2.pop()
if (n != null) {
stack1.push(n)
}
}
return res || null
}
get length(): number {
return this.stack1.length
}
}
队列溢出
队列溢出分为真溢出和假溢出两种:
- 真溢出:指的是由于存储空间不够而产生的溢出叫真溢出,解决方式:扩容的方式解决。
- 假溢出:队列中尚余有足够的空间,但元素却不能入队。一般是由于队列的存储结构或操作方式的选择不当所致。
此时是队列达到上限的情况,此时删除一个元素,会成为:
此时查询队列会显示队列已满的情况,但明显队列中还有空余位置。**解决方式:**1. 删除元素后将所有元素向前移动一位。
循环队列
解决假溢出的途径是采用循环队列。循环队列的好处是我们可以利用队列之前用过的空间,在一个普通队列中,如果一个队列满了,就不能插入新的元素,即使队列前面仍然有空的空间。使用循环队列后,我们可以使用这些空间去存储新的值。
下面是从0开始构建一个循环队列
export default class MyCircleQueue {
list: any[]
front: number
rear: number
max: number
constructor(k: number) {
// 用来保存数组长度为k的数据结构
this.list = Array(k)
// 队首指针
this.front = 0
// 队尾指针
this.rear = 0
// 队列的长度
this.max = k
}
// 增加一个元素
enQueue(num: number): boolean {
if (this.isFull()) {
return false
} else {
this.list[this.rear] = num
// 当队尾指针指到最后一个的时候,就指向开头位置
this.rear = (this.rear + 1) % this.max
return true
}
}
// 删除一个元素
deQueue(): any {
let v = this.list[this.front]
this.list[this.front] = null
this.front = (this.front + 1) % this.max
return v
}
// 判断队列是否空了:当头指针和尾指针同时指向同一个元素,且这个元素为空
isEmpty() {
return this.front === this.rear && !this.list[this.front]
}
// 判断队列是否满了:当头指针和尾指针同时指向同一个元素,且这个元素有值
isFull() {
return this.front === this.rear && !!this.list[this.front]
}
// 获取队首元素
getFront() {
return this.list[this.front]
}
// 获取队尾元素
getRear() {
let rear = this.rear - 1
return this.list[rear < 0 ? this.max - 1 : rear]
}
}