一一先进先出的线性表
一.概念与定义
队列(queen)是一个先进先出的数据结构,又称为先进先出(FIFO—first in first out)的线性表。联想一下链表,在单链表中,只能对表尾进行插入,对表头进行结点的删除,这样强限制性的链表,就是所说的队列。也就是说,队列是限定在表的一端进行插入,表的另一端进行删除的数据结构。
就像去买票排队,每一列队伍都有一个队尾和队首,先来的先买票,后来的后买,买好的就从队首出去,新来买票的就需要从队尾继续排队。
通常,称进数据的一端为队尾,出数据的一端为队首,数据元素进队列的过程称为入队,出队列的过程称为出队。
队列是一个线性的数据结构,并且这个数据结构只允许在一端进行插入,另一端进行删除,禁止直接访问除这两端以外的一切数据,且队列是一个先进先出的数据结构。
二.实现与基本操作
队列存储结构的实现有以下两种方式:
①顺序队列:在顺序表的基础上实现的队列结构。
②链队列:在链表的基础上实现的队列结构。
两者的区别就是顺序表和链表的区别,即在实际的物理空间中,数据集中存储的队列是顺序队列,分散存储的队列是链队列。
1)STL queen
主要操作 | 注解 |
---|---|
queue <Type> q | 定义一个名为q的队列,type为数据类型 |
q.push (item) | 把item放进队列q里 |
q.front() | 返回队首元素,但不删除 |
q.back() | 返回队尾元素,但不删除 |
q.pop() | 删除队首元素 |
q.size() | 返回元素个数 |
q.empty() | 判断队列是否为空 |
例题:机器翻译(洛谷P1540)
假设内存中有 M 个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过 M−1,软件会将新单词存入一个未使用的内存单元;若内存中已存入 M 个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。
假设一篇英语文章的长度为 N 个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。
输入格式
共 2 行。每行中两个数之间用一个空格隔开。
第一行为两个正整数 M,N,代表内存容量和文章的长度。
第二行为 N 个非负整数,按照文章的顺序,每个数(大小不超过 1000)代表一个英文单词。文章中两个单词是同一个单词,当且仅当它们对应的非负整数相同。
输出格式
一个整数,为软件需要查词典的次数。
输入输出样例
输入
3 7 1 2 1 5 4 4 1
输出
5
样例解释
整个查字典过程如下:每行表示一个单词的翻译,冒号前为本次翻译后的内存状况:
1
:查找单词 1 并调入内存。1 2
:查找单词 2 并调入内存。1 2
:在内存中找到单词 1。1 2 5
:查找单词 5 并调入内存。2 5 4
:查找单词 4 并调入内存替代单词 1。2 5 4
:在内存中找到单词 4。5 4 1
:查找单词 1 并调入内存替代单词 2。
共计查了 5 次词典。
思路q
开了一个队列 q 模拟内存情况,数组 inq 来判断每个单词是否在内存中,每次需要去外存查找就ans++。具体细节见注释。
#include<iostream>
#include<queue>
using namespace std;
queue<int> q;//队列模拟内存情况
int m,n,ans;
bool inq[1010];//判断单词是否在内存中
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
if(inq[x])continue;//能够在内存中查找就跳过
else
{
//如果内存满了,最早进入内存的那个单词出列
if(q.size()>=m)
{
inq[q.front()]=false;
q.pop();
}
//把外存的结果加入内存以便下次查找
q.push(x);
inq[x]=true;
ans++;
}
}
cout<<ans;
return 0;
}
2)手写队列
依然以机器翻译为例
#include<bits/stdc++.h>
#define N 1003 //队列大小
int Hash[N]={0}; //用Hash检查内存中有没有单词
struct myqueue{
int data[N]; //分配静态空间
/* 如果动态分配,这样写: int *data; */
int head, rear; //队头、队尾
bool init(){ //初始化
/*如果动态分配,这样写:
Q.data = (int *)malloc(N * sizeof(int)) ;
if(!Q.data) return false; */
head = rear = 0;
return true;
}
int size(){ return (rear - head + N) % N;} //返回队列长度
bool empty(){ //判断队列是否为空
if(size()==0) return true;
else return false;
}
bool push(int e){ //队尾插入新元素。新的rear指向下一个空的位置
if((rear + 1) % N == head ) return false; //队列满
data[rear] = e;
rear = (rear + 1) % N;
return true;
}
bool pop(int &e){ //删除队头元素,并返回它
if(head == rear) return false; //队列空
e = data[head];
head = (head + 1) % N;
return true;
}
int front(){ return data[head]; } //返回队首,但是不删除
}Q;
int main(){
Q.init(); //初始化队列
int m,n; scanf("%d%d",&m,&n);
int cnt = 0;
while(n--){
int en; scanf("%d",&en); //输入一个英文单词
if(!Hash[en]){ //如果内存中没有这个单词
++cnt;
Q.push(en); //单词进队列,放到队列尾部
Hash[en]=1;
while(Q.size()>m){ //内存满了
int tmp; Q.pop(tmp); //删除队头
Hash[tmp] = 0; //从内存中去掉单词
}
}
}
printf("%d\n",cnt);
return 0;
}