【数据结构与算法】队列

【数据结构——栈】个人总结摘要(C++版)

一、队列的基本概念

1.队列的定义

  队列(Queue),和一样也是一种操作受限的线性表,其只允许在一端进行插入,另一端进行删除.
  类似于排队,先入队的也是最先出队的,所以队列的特点是先进先出.
队列示意图

2.队列的顺序存储结构

  队列类似于线性表,也有对应的两种存储方式,即顺序存储和链式存储。
  队列的顺序实现是分配一块连续的存储单元存放队列中的元素,并使用两个标记指向队首和队尾(front和rear),不同的定义会有不同的入队出队操作。

2.1 顺序队列

  本文中对于顺序队列初始化定义则是:队尾rear指向数组下标为0的位置,front指向rear的上一个位置,即-1。

(1) 队列的初始化
	SeqQueue::SeqQueue()
	{
		rear=0;
		front=-1;
	}	//队尾rear指向数组下标为0的位置,front指向rear的上一个位置,即-1。

(2)入队操作

队列的初始化
  入队,将要入队的6个数据入队,然后rear++指向下一个位置。对于顺序队列来说,其存储空间是有限的,所以初始化时队列的长度是需要赋值的。

void SeqQueue::inQueue(int a[],int n)	//本段代码队列中的数据通过数组来传参的,n是数组长度即队列的最大存储个数
{
	if(rear==n-1) throw"oversize";		//队尾指针指向最后一个元素,其数组下标是n-1,相等时即队满,然后抛出错误
	for(int i=0;i<n;i++)
	{
		data[rear]=a[i];
		rear++;		//此处注意,最后一个入队后,rear++,若入队6个元素,则rear指向6,后文有图;
	}
}
(3) 取队首元素
int SeqQueue::GetHead()		//取队首元素,因front初始化为-1,所以队首位置是front+1
{
	if(rear==front+1) throw"empty"; 
	return data[front+1];
}
(4) 出队

队满状态
  如上图,此时的队列状态为rear值为6,front值为-1,之后进行出队操作,在队首进行,演示动画如下:
出队操作

int SeqQueue::outQueue( )
{
	if(rear==front+1) throw"empty";		//front始终指向rear的上一个位置,故队空时rear==front+1;
	int x;
	front++;
	x=data[front];
	return x;
}
(5) 主函数及头文件的声明
#include <iostream>
using namespace std;
#define QueueSize 20

class SeqQueue
{
private:
	int data[QueueSize];
	int front,rear;
public:
	SeqQueue();
	~SeqQueue(){};
	void inQueue(int a[],int n);
	int GetHead();
	int outQueue();
};
//其余代码段放入此处即可运行
int main()
{
	SeqQueue l;
	int n,a[10];
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	try				//使用throw抛出错误时,使用try{}...catch(char *str){}调用函数
	{
		l.inQueue(a,n);		//入队
		cout<<l.GetHead()<<endl;	//取队列队首元素
		cout<<l.outQueue()<<endl;	//出队后输出队首元素
	}
	catch(char *str){cout<<str<<endl;}
	return 0;
}

2.2 循环队列

  在顺序队列中,随着队列的插入和删除,整个队列向数组的高端移过去,当元素被插入到数组中下标的最大的位置之后,数组空间就用尽了,尽管此时的数组低端还有空闲空间,这种现象叫作假溢出,如下图:
假溢出
  解决假溢出的办法就是将存储对列的数组看成是头尾相接的循环结构,这样的操作可以通过取模操作实现。
  

注意:通过取模操作时,会牺牲一个单元来区分队满和队空,输入入队个数时,会比队列长度少一个。

(1) 构造函数

  初始化一个空的循环队列只需将队头front和队尾rear同时指向数组的高端,即rear=front=QueueSize-1

template<class DataType>
CirQueue<DataType>::CirQueue( )
{
	front=rear=QueueSize-1;
}
(2) 析构函数

  循环队列是静态存储分配,在循环队列变量退出作用域时自动释放内存单元,因此,循环队列无需销毁,析构函数为空即可。

(3) 入队操作

  循环队列的入队操作只需将队尾的rear在循环意义下加1,然后将代插元素x插入队尾位置。见如下动图:
入队操作

  入队操作中判断队列是否上溢的条件是:(rear + 1) % QueueSize == front。

template<class DataType>
void CirQueue<DataType>::EnQueue(DataType x)
{
	if((rear+1)%QueueSize==front)
	{
		cout<<"CirQueue is fulled"<<endl;
		return;
	}
	else
	{
		rear=(rear+1)%QueueSize;
		data[rear]=x;
	}
}
(4) 出队操作

  循环队列的出队操作只需将队头元素在循环意义下加1,与上文入队操作原理相同。
  出队操作中判断队列是否为空的条件是rear==front。

template<class DataType>
DataType CirQueue<DataType>::DeQueue()
{
	if(rear==front) cout<<"empty"<<endl;
	else
	{
		int temp;
		front=(front+1)%QueueSize;
		temp=data[front];
		return temp;
	}
}
(5) 取队首元素

  在循环意义下+1后,返回队首元素即可完成操作。

if(rear==front) cout<<"empty"<<endl;
	else
	{
		front=(front+1)%QueueSize;
		return data[front];
	}
(6) 主函数及头文件声明
#include<iostream>
using namespace std;
#define MaxSize 100
int QueueSize;

template<class DataType>
class CirQueue
{
public:
	CirQueue();
	~CirQueue(){};	//析构函数为空即可
	void EnQueue(DataType x);
	DataType DeQueue();
	DataType GetHead();
private:
	DataType data[MaxSize];
	int front, rear;
};
//以上各段代码放入此处即可
int main()
{
	int n;
	cout<<"输入队列长度:";
	cin>>n;
	QueueSize=n;
	CirQueue<int> q;
	cout<<"输入"<<n-1<<"个入队数据";
	for(int i=0;i<n-1;i++)
	{
		int x;
		cin>>x;
		q.EnQueue(x);
	}
	cout<<"DeQueued data was: "<<q.DeQueue()<<endl;
	cout<<"GetHead data is: "<<q.GetHead()<<endl;
	return 0;
}

3.C++库函数——队列的快捷使用

  库函数在使用时需声明头文件,栈的头文件是"#include< queue >",之后在定义队列时,与类模板相似,声明方式为"queue<DataType数据类型>+名称"。
   *调用函数进行队列的操作,具体如下:

//例如要定义的队列为:
queue<int> q;
int x;	//x为要入队的数据

  -q.push(x); //入队函数" XXX.push(x); “,无返回值,可直接调用
  -q.pop(x); //出队函数” XXX.pop(x); “,无返回值,可直接调用
  -q.front(x); //取队首函数” cout<<XXX.front(x); “,有返回值,为当前队首元素,得赋值给一个变量或直接输出
  -q.empty(); //判断队列是否为空的函数” cout<<XXX.empty();",不需要传参,但有返回值,返回值为1,表示该队列为空,为0表示该队列不为空

以下为具体使用示例:

#include<iostream>
#include"queue"			//注意此处
using namespace std;

int main()
{
	queue<int> q;
	int n,i,x;
	cin>>n;				//要入队的数据个数
	for(i=0;i<n;i++)
	{
		cin>>x;
		q.push(x);
	}
	if(q.empty()) cout<<"Queue is empty"<<endl;	//如果队是空,输出提示信息
	else
	{
		cout<<q.front()<<endl;	//输出队首元素
		q.pop();				//进行出队操作
		cout<<q.front()<<endl;	//之后查看队首
	}
	return 0;
}

  小伙伴们,因为我本身也在学习数据结构中,此系列文章也作为笔记记录分享给大家,如有错误希望各位指正,我会继续努力,提高自己水平。
注:
  参考书籍《2022年数据结构考研复习指导》,王道论坛组 编。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悦享未来

你的鼓励必将成为我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值