目录
队列的概念
队列的静态实现
总代码
stl的queue
队列算法题
1.队列模板题
2.机器翻译
3.海港
双端队列
队列的概念
和栈一样,队列也是一种访问受限的线性表,它只能在表头位置删除,在表尾位置插入,队列是先进先出(FIFO)栈是后进先出(LIFO)
队列的静态实现
我们用一个比较大的数组来表示队列,h表示队头的前一个元素,t表示队尾元素
队列的创建
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int q[N], h, t; 
队列的插入
void push(int x)
{
	q[++t] = x;
} 
和顺序表的尾插差不多,时间复杂度是O(1)
队列的删除
我们的删除直接让头指针向前移动一位就行了
void pop()
{
	h++;
} 
查询队头元素
h指向的是队头的前一个元素的下标,所以h+1是队头的下标
int front()
{
	return q[h + 1];
} 
查询队尾元素
t就是队尾元素的下标
int back()
{
	return q[t];
} 
队列判空
当我们只剩一个元素的时候,h指向这个元素的前面,t指向这个元素,如果删除的话,h++ h就和t相等了,这和我们刚开始没有元素的状态也是一致的,所以h==t就是我们判断队列为空的要点
bool empty()
{
	return h == t;
} 
队列有效元素个数
由于我们h和t是左开右闭的,所以t-h就是中间的元素个数,比如h指向1,t指向3的时候,下标2,3就是我们的元素,3-1=2就是元素个数是一致的
int size()
{
	return t - h;
} 
测试
总代码
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int q[N], h, t;
void push(int x)
{
	q[++t] = x;
}
void pop()
{
	h++;
}
int front()
{
	return q[h + 1];
}
int back()
{
	return q[t];
}
bool empty()
{
	return h == t;
}
int size()
{
	return t - h;
}
int main()
{
	for (int i = 1; i <= 10; i++)
	{
		push(i);
	}
	while (size())
	{
		cout << front() << " " << back() << endl;
		pop();
	}
	return 0;
} 
 
stl的queue
测试代码
#include <iostream>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
int main()
{
	queue <PII> q;
	for (int i = 1; i <= 10; i++)
	{
		q.push({ i,i * 10 });
	}
	while (!q.empty())
	{
		auto t = q.front();
		int first = t.first;
		int second = t.second;
		cout << first << " " << second << endl;
		q.pop();
	}
} 
测试结果

队列算法题
1.队列模板题

#include <iostream>
using namespace std;
const int N = 1e4+10;
int q[N],h,t;
int main()
{
	int n,op,x;
	cin >> n;
	while(n--)
	{
		cin >> op;
		if(op == 1)
		{
			cin >> x;
			q[++t] = x;
		}
		else if(op == 2)
		{
			if(t-h == 0) cout << "ERR_CANNOT_POP" << endl;
			else h++;
		}
		else if(op == 3)
		{
			if(t-h == 0) cout << "ERR_CANNOT_QUERY" << endl;
			else cout << q[h+1] << endl;
		}
		else
		{
			cout << t-h << endl;
		}
	}
} 
2.机器翻译

我们可以用队列来模拟这个内存存储的单元格,此外我们还需要一个bool数组来判断某个单词在不在内存中
下面是我们的实现的代码
#include <iostream>
#include <queue>
using namespace std;
const int N = 1010;
bool st[N];
int cnt;
queue <int> q;
int main()
{
	int n,m;
	cin >> m >> n;
	while(n--)
	{
		int x; cin >> x;
		if(st[x]);
		else{
			q.push(x);
			st[x] = true;
			cnt++;
			if(q.size() > m)
			{
				st[q.front()] = false;
				q.pop();
			}
		}
		
		
	}
	cout << cnt << endl;
} 
 
3.海港

这道题我们用队列来模拟,我们用一个数组来记录每个国家的人数,当每个国家从0变1时,种类加1,从1变0时,种类减1
先把每个船的信息入队列,用pair类型,<时间,国家>来入队列,每次入队列判断种类是否加1
每个船的信息入完了之后,要判断队列合不合法,如果队头的时刻和队尾的时刻差值超过24小时,我们就要把第一个时刻的信息出队列,出队列的时候再次判断要不要让种类减1
每次一个信息弄完就打印一下种类
#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5+10;
typedef pair<int,int> PII;
int t,k;
int cnt[N];//记录每个国家的人数,从0到1时种类加1,从1到0时种类减1,其他不变 
int kinds;//记录国家种类 
queue <PII> q;
int main()
{
    int n;
	cin >> n;
	while(n--)
	{
		cin >> t >> k;
		while(k--)
		{
			int x;
			cin >> x;
			q.push({t,x});
			if(cnt[x]++ == 0)
			{
				kinds++;
			}
		}
	    //让队列合法
		while(q.size() && (q.back().first - q.front().first >= 86400)) 
		{
			int tmp;
			tmp = q.front().second;
			if(cnt[tmp]-- == 1)
			{
				kinds--;
			}
			q.pop();
		}
			cout << kinds << endl;
	}	
	
	return 0;
 }  
双端队列
什么是双端队列?
双端队列也是一种特殊的线性表,它允许在表的两端插入和删除元素
我们就不实现它的模拟实现了
我们直接用stl现成的双端队列deque测试一下
头插头删
#include <iostream>
#include <deque>
using namespace std;
struct node {
	int x, y, z;
};
deque <node> q;
int main()
{
	//头插和头删
	for (int i = 1; i <= 5; i++)
	{
		q.push_front({ i,i * 5,i * 10 });
	}
	while (q.size())
	{
		auto t = q.front();
		q.pop_front();
		cout << t.x << " " << t.y << " " << t.z << endl;
	}
} 

同理尾插和尾删
#include <iostream>
#include <deque>
using namespace std;
struct node {
	int x, y, z;
};
deque <node> q;
int main()
{
	//尾插和尾删
	for (int i = 1; i <= 5; i++)
	{
		q.push_back({ i,i * 5,i * 10 });
	}
	while (q.size())
	{
		auto t = q.back();
		q.pop_back();
		cout << t.x << " " << t.y << " " << t.z << endl;
	}
} 




















