队列
队列是只允许在一段进行插入操作,另一端进行删除操作的线性表
队列是一种先进先出的线性表,简称FIFO,允许插入的一端是队尾,允许删除的一段是队首。队列在程序运行设计中用的十分频繁,,比如键盘进行的各种字母数字的输入输出。
循环队列
1.队列顺序储存的不足
假设一个队列有n个元素,我们就需要一个大于n的数组,插入操作很好理解,就是在队尾的下一个位置储存一个数据,但如果是删除数据呢?显然我们有两种方式。
一种就是将队首删除,然后每个元素向前移动一位,但是这样的时间复杂度是O(n)。
可是想想,为什么出队一定要移动所有元素呢?如果我们不去限制队首的位置,也就是说我们不必规定队列的元素必须限制在数组前n个单元内,我们就能用O(1)的时间复杂度来删除一个元素,为了避免当只有一个元素时,队头和队尾重合使处理变得麻烦,所以引入两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个地址,这样当front和rear重合时,此时队列为空。
例如:如果有一个长度为5的数组a[5],一个队列储存在a[0]~a[4],front指向0,rear指向5,如果我们想删除元素,只需要使front+1指向1即可,但是随之而来的又是一个问题,如果此时我们想插入一个元素呢?如果a[5]储存插入的元素,那么rear指向哪呢,此时就会发生一个数组越界的错误,但是明明a[0]是空的,我们把这种现象叫做假溢出。此时我们就需要循环队列了
2.循环队列的定义
试想:如果我们做公交车的时候,后面没有座位了,但是前面还有几个座位,那么你是不坐了呢还是坐到前面去呢?显然是坐到前面去,循环队列用的也是这个思想
继续上面的问题如果我们想继续插入a[5]的话我们只需要让rear指向0,即可完成一个循环
但是问题又双来了,当rear=front时,他们又可能是重合,也有可能是相差一圈 ,那么怎么判断队列是空是满呢?
如果队列最大尺寸是s,那么队列满的条件就是(rear+1)%s==front
在上面的例子中front== 1, rear==0,满足上面的式子,所以队列已经满了
循环队列代码如下
typedef int qelemtype;
typedef struct
{
qelemtype data[maxsize];
int front;//头指针
int rear;//尾指针,指向队尾元素的下一个位置
}sqqueue;
//循环队列q初始化
Status initqueue(sqqueue* q)
{
q->front = 0;
q->rear = 0;
return 1;
}
//循环队列求队列长度代码
int queuelength(sqqueue q)
{
return (q.rear - q.front + maxsize) % maxsize;
}
//循环队列入列操作
Stauts inqueue(sqqueue* q, qelemtype e)
{
if ((q->rear + 1) % maxsize == q->front;)//判断队列是否已经满了
return 0;
q->data[q->rear] = e;
q->rear = (q->rear + 1) % maxsize;//*rear指针向后移一位
return 1;
}
//循环队列的出队操作
Status dequeue(sqqueue* q, qelemtype* e)
{
if (q->front == q->rear)//判断队列是否为空
return 0;
*e = q.->data[q->front];
q->front = (q->front + 1) % maxsize;
return 1;
}
队列的数组模拟
int q[maxn], tail = 0, head = 1;
void push(int x)
{
q[++tail] = x;
}
void pop()
{
head++;
}
int gethead()
{
return q[head];
}
int gettail()
{
return q[tail];
}
单调队列
顾名思义,单调队列就是数据单调递增或者递减的队列
模板题:洛谷p1886
//这里以取最大值为例,取最小值留给读者自行考虑
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1005;
struct data
{
int val, pos;
}a[maxn];
int n, k;
int q[maxn];
int tail = 0;
int head = 1;
void push(int x)
{
while (a[x].val >= a[q[tail]].val && head >= tail)
head--;
while (a[x].pos - a[q[tail]].pos >= k && head >= tail)tail++;
q[++head] = x;
}
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> a[i].val;
a[i].pos = i;
}
q[++tail] = 1;
if (k == 1)
printf("%d", a[q[tail]].val);
for (int i = 2; i <= n; i++)
{
push(i);
if (i > k)cout << a[q[tail]].val;
}
return 0;
}