前言
写dp写晕了。。。赶紧来个队列休息一下。
队列是模仿现实生活当中的“排队”的。当然,电脑当中的队列可是比现实生活当中的规矩多了:没人插队,先排队进来的永远先出队。示意图如下:
计算机当中是怎么实现的呢?
一般定义一个head指针,一个tail指针,head指向队列的头,tail指向队列的尾,每次插入一个元素,那么就把tail指针往后一个,每次弹出一个元素,就会把head指针往后移一位。如图
“删除”在计算机当中很多时候不意味着真的将其删除了,只是将指针指向别处,导致你无法访问该元素,同时将该地址标记为“可复写”。所以该数据还是存在于这个队列当中的,处于等待复写的状态。
但是这样会引来一个问题:假设我们的队列只有两个空间,当tail指向第三个空间时就代表队列满了,那么此时弹出张三,其实空间又增加了一个,但是从tail的判断上却发现已经满了,而不能入队。
这个问题的解决方案:可以多定义两个变量:一个指针end指向该点,一个msize表示当前的元素数量。当tail和head指针达到end的时候,让他们直接回到整个分配的空间首地址去(注意head不是队列的首地址,只是队列第一个元素的地址),而msize则专门用来判断是否真的队列已经满溢了。
注意,此时可能会出现以下情况:
此时tail在head的前面,所以在扩容时候不能使用realloc函数,否则序列可能会出现错乱。
这样就完成了一个循环队列。
队列在BFS广度优先搜索 (breadth-first search)用处非常广泛。是一个重要的数据结构。
注意事项
队列也应当有自动扩容的功能,而不需要让人动手去扩容。比较重要的函数有:
- push():从队尾加入一个新元素
- pop():从队首弹出一个元素
- front():取出第一个元素的值
老样子,还是实现最简单的队列,存储int型。
代码
#include<iostream>
#include<vector>
#include<queue>
#include<deque>
using namespace std;
class Queue {
private:
int* mdata, * head, * tail, * end, msize, mcapacity;
int expand() {
int extra_size = mcapacity;
int* p = nullptr;
while (extra_size) {
p = new int[mcapacity + extra_size]();
if (p) break;
extra_size >>= 1;
}