开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
一、队列的定义与操作
1.定义
1.概念
-
队列:只能在线性表一端进行插入操作,在另一端进行访问和删除操作的线性表
-
队尾:将进行插入操作的一端
-
队头:可以进行访问和删除操作的一端
2.顺序:先进先出
2.链队列
1.定义
typedef struct clNode{
int data;
clNode* next;
}*cqNode;
struct chainQueue{
cqNode front;//头结点
cqNode rear;//尾结点
chainQueue():front(NULL),rear(NULL){}
};
2.操作
bool empty(chainQueue cq) {
return cq.front == NULL;
}
void push(chainQueue& cq, int x) {
cqNode tmp = new clNode;//创建新节点
tmp->data = x;
tmp->next = NULL;
if (empty(cq)) {//如果链队列没有元素
cq.front = new clNode;
cq.front->next = tmp;
}
else {
cq.rear->next = tmp;//新加入的结点加入当前链队列队尾的后面
}
cq.rear = tmp;//队尾始终为新加入的结点
}
int front(chainQueue cq) {
if (empty(cq)) {
cout << "队列为空" << endl;
return -1;
}
return cq.front->next->data;//返回队头元素
}
void pop(chainQueue& cq) {
if (empty(cq)) {
cout << "队列为空" << endl;
return;
}
cqNode tmp = cq.front->next;//队头结点
cq.front->next = tmp->next;
delete tmp;
tmp = NULL;
if (cq.front->next == NULL) {//链队列中元素被全部删除
delete cq.front;
cq.front = NULL;
cq.rear = NULL;
}
}
void cq_traverse(chainQueue& cq) {
while (!empty(cq)) {
cout << front(cq) << " ";
pop(cq);
}
}
3.循环队列
1.定义
1.概念:下标最大的元素的下一个元素的下标为0
#define N 100
#define next(x) ((x)==N-1?0:(x)+1)
typedef struct sqNode{
int data[N];
int front;
int rear;
sqNode():front(0),rear(-1){}
}seqQueue;
判断队空的条件next(sq.rear)=sq.front
判断队满的条件next(next(sq.rear))=sq.front因此队中有一个元素为空
2.操作
//判断队空
bool empty(seqQueue sq) {
return next(sq.rear) == sq.front;
}
//判断队满
bool full(seqQueue sq) {
return next(next(sq.rear)) == sq.front;
}
void push(seqQueue& sq, int x) {
if (full(sq))
{
cout << "队满" << endl;
return;
}
sq.rear = next(sq.rear);//队尾后移一位
sq.data[sq.rear] = x;
}
int front(seqQueue sq) {
if (empty(sq)) {
cout << "队空" << endl;
return - 1;
}
return sq.data[sq.front];
}
void pop(seqQueue& sq) {
if (empty(sq)) {
cout << "队空" << endl;
return;
}
sq.front = next(sq.front);//队头后移一位
}
void sq_traverse(seqQueue& sq) {
while (!empty(sq)) {
cout << front(sq) << ' ';
pop(sq);
}
}
二、STL队列
1.queue
1.头文件:#include<queue>
1.定义
queue<int>q1;
queue<char, list<char>>q1;
//用list容器实现的queue
queue<int,vector<int>>q1;//底层容器为vector
2.操作
qu.push(3);//入队
cout << qu.size() << endl;//队列中元素的个数
cout << qu.back() << endl;//返回尾元素
while (!qu.empty()) {//判断队列是否为空
cout << qu.front() << endl;//获取队头元素
qu.pop();//出队
}
2.deque
1.定义
deque<int>dq;//创建空对象
deque<int>dq2(12, 5);//创建一个含有12个元素的deque对象,元素的初始值都为5
int a[] = { 1,3,7 };
deque<int>dq3(a, a + 2);//创建含有4个元素的deque对象
2.操作
dq.push_front(7);//插入队头
dq.pop_back();
三、队列应用
1.二项式
1.实现
-
首先向队列中添加0,即为每一行都最后的0以及下一行的第一个0
-
取队列q的队头元素,假设其值为f1,出队;再取q的队头元素,假设其值为f2,出队
-
将f1+f2入队
-
如果f2不为0,则输出f2,回到第2步,如果f2=0,则一行输出结束,回到第1步
2.代码
void chineseTriangle(int n) {
int f1, f2, flag, w = 4;
queue<int>qu;
qu.push(0), qu.push(1);//初始化
while (n--) {
qu.push(0);//每一行都最后一个0,也是下一行的第一个0
flag = 0;//flag=0表示当前为每一行都第一个数字
do {
f1 = qu.front();
qu.pop();//获取第一个值,并出队
f2 = qu.front();//获取第二个值
if (f2) {
if (!flag) {
flag = 1;
cout << setw(w * n + 1) << f2;//第一个数字的宽度特别处理
}
else
cout << setw(2 * w) << f2;
}
else
cout << endl;//f2=0,一行结束
qu.push(f1 + f2);//f1+f2入队
} while (f2 != 0);
}
}
四、单调队列
1.定义
1.概念:队列的元素按从队头到队尾的顺序为严格单调递增,称为递增队列;如果队列的元素按从队头到队尾的顺序为严格单调递减,则称为递减队列
2.应用
1.利用单调队列求固定长度区间的最大值
1.步骤
-
定义一个双端队列dq,队列中存放的是数组a的下标。一次考虑a的每一个元素,对于元素a[i],可分为三步
-
去尾操作。如果dq不空,且a[i]≥dq的队尾元素值,则将dq的队尾出队,并继续上述操作,直到a[i]<dq的队尾元素值或dq为空。a[i]入队。这一操作保证队列中的元素递减
-
掐头操作。如果dq队头元素与a[i]的距离不小于m,则将dq的队头出队,这一操作保证队头元素在以a[i]为右端点的滑动窗口内
-
dq队头元素即为当前滑动窗口中的最大值,输出该最大值
void rangeMax(vector<int>ve,int m){
deque<int> dq;
for(int i=0;i<ve.size();i++){
while(!dq.empty()&&ve[dq.back()]<ve[i])//队尾
dq.pop_back();
dq.push_back(i);//下标入队
if(i>=m-1){
if(!dq.empty()&&i-dq.front()>=m)//掐头
dq.pop_front();
cout<<ve[dq.front()]<<' ';//输出队头
}
}
}