队列(单端)

                                 一一先进先出的线性表

一.概念与定义


队列(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. 1 2:查找单词 2 并调入内存。
  3. 1 2:在内存中找到单词 1。
  4. 1 2 5:查找单词 5 并调入内存。
  5. 2 5 4:查找单词 4 并调入内存替代单词 1。
  6. 2 5 4:在内存中找到单词 4。
  7. 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值