队列基础知识
概念
先入先出 FIFO
一片连续的存储区域,可以存储任意类型的数据
队列会有两个指针:
- 一个头指针
- 一个尾指针:指向最后一个元素的下一位,一般描述区间都是左闭又开的方式,尾指针上不放元素,这样【tail - head】正好是队列当前存放数据的数量
队列就像是去排队买火车票的场景
支持两种基本操作:
- 入队:尾指针向后移动一位,将数据放进去
- 出队:对于普通队列来说只支持从队首出队,就是头指针向后移动一位。
队列溢出:队列满了。不能再放入数据。
队列假溢出:队列的尾指针走到了队列的最后一位,普通队列会判断队列已经满了,但是实际上队列前方还有可以存放数据的空间。
循环队列:为了解决队列的假溢出。尾指针在向后移动到最后一位时,发现指向了一个不存在的地址,此时会移动到队列的队首。循环队列不算是特殊的队列,只是为了有效利用空间,为了解决假溢出的一种处理方式
几种经典队列实现方式
普通队列
// 结构定义
// 标准实现方式,head和tail一开始都指向下标为0的位置
// 入队时讲数据放入tail指向的位置,并且将tail向后移动一位
class Queue {
constructor(n = 10) {
this.head = 0;
this.tail = 0;
this.arr = [];
this.length = n;
}
// 入队
push (data) {
// 判断队列是否已经满了
if (this.full()) {
console.error('队列满了');
return;
}
this.arr[this.tail] = data;
this.tail += 1;
return;
}
// 出队-头指针向后移动一位即完成了出队
pop () {
if (this.empty()) {
console.error('队列已经没有数据了');
return;
}
this.head += 1;
}
// 判断队列是否是空的
empty () {
return this.head === this.tail;
}
// 普通队列判断队列是否是满的-尾指针指向最后一个元素的下一位
full () {
return this.tail && (this.tail === this.length)
}
// 查看队首元素
front () {
return this.arr[this.head];
}
// 查看队列中元素的数量
size () {
return this.tail - this.head;
}
// 打印队列中所有元素
output () {
for (let i = this.head; i < this.arr.length; i++){
console.log(this.arr[i]);
}
}
}
const q = new Queue(5);
q.push(1);
q.push(2);
q.push(3);
q.output(); // 1 2 3
console.log(q.front()); // 1
console.log(q.size()); // 3
q.pop();
q.output(); // 2 3
console.log(q.size()); // 2
简单粗暴的循环队列
class CircularQueue {
constructor(n) {
this.length = n;
this.head = 0;
this.tail = 0;
this.arr = [];
// 当前队列中元素数量
this.cnt = 0;
}
// 入队
push (data) {
if (this.full()) {
console.error('队列已经满了');
return
}
this.arr[this.tail] = data;
this.tail += 1;
this.cnt += 1;
if (this.tail === this.length) {
this.tail = 0;
}
}
// 出队
pop () {
if (this.empty()) {
console.error('队列中已经空了');
return
}
this.cnt -= 1;
this.head += 1;
if (this.head === this.arr.length) {
this.head = 0
}
}
// 判断队列是否已经空了
empty () {
this.cnt === 0;
}
// 判断队列是否已经满了
full () {
return this.cnt === this.length;
}
// 返回队首元素
front () {
return this.arr[this.head];
}
// 当前队列元素数量
size () {
return this.cnt;
}
// 打印当前所有元素
output () {
let result = '';
for (let i = 0, j = this.head; i < this.cnt; i++){
result += this.arr[j] + ' ';
j += 1;
if (j === this.length) {
j = 0;
}
}
console.log('output', result);
}
}
console.log('----------------------------------------')
console.log('循环队列');
const cq = new CircularQueue(5);
cq.push(1);
cq.push(2);
cq.push(3);
cq.output(); // output 1 2 3
cq.pop();
cq.output(); // output 2 3
cq.push(4);
cq.push(5);
cq.output(); // output 2 3 4 5
cq.push(6);
cq.output(); // output 2 3 4 5 6
console.log('----------------------------------------')