队列的基本概念及其相关操作详解(C++)

队列的概念及相关术语:

队列是一种操作受限制的线性表,只允许在表的一端插入和删除元素。

对头(Front):允许删除的一端,又称队首;

队尾(Rear):允许插入的一段;

空队列:不含任何元素的空表;

向队列插入元素称为入队,删除元素称为出队或者离队。

 

队列的特性:

先进先出。

队列和栈一样不支持随机访问内部元素。

队列的存储结构:

  1. 顺序存储
    • 普通顺序存储
    • 循环队列
  2. 链式存储

队列的基本操作:

  • Initqueue(&Q):初始化队列,构造一个空队列;
  • QueueEmpty(Q):队列判空;
  • Enqueue(&Q,x):入队;
  • Dequeue(&Q):出队;
  • GetHead(Q,x):读取对头元素;

1.1顺序存储--普通顺序队列

队列的存储类型定义:

typedef struct{
	int data[maxsize];
	int front,rear;
}queue;

队列的顺序存储实现是分配一块连续的存储单元存放队列中的元素。并设置两个指针:front和rear分别指向对头元素位置和队友元素位置,具体实现时,front和rear的具体指向有不同的方式:

  1. front指向对头元素,rear指向队尾元素的下一个位置
  2. front指向队友元素的前一个位置,rear指向队尾元素

不同的指向方式对于列表的操作影响不大,只是在一些小细节判断上有些许却别,本文以第一种凡是为例。

1.Initqueue(&Q):初始化队列,构造一个空队列:

void initqueue(queue &q) {
	q.rear = q.front =0;
}

2.QueueEmpty(Q):队列判空:

bool isempty(queue q) {
	if (q.rear == q.front) return true;
	else return false;
}

3.Enqueue(&Q,x):入队:

void enqueue(queue &q,int x) {
	if (isfull(q)) cout << "队列满" << endl;
	else {
		q.data[q.rear] = x;
		q.rear++;
	}
}

4.Dequeue(&Q):出队:

void dequeue(queue &q) {
	if (isempty(q))  cout << "队列空" << endl;
	else
	{
		q.front++;
	}
}

5.GetHead(Q,x):读取对头元素:

void gethead(queue q) {
	if (isempty(q))  cout << "队列空" << endl;
	else {
		cout<< q.data[q.front];
	}
}

整体代码实现:

#include<iostream>
#define maxsize 10
using namespace std;
typedef struct{
	int data[maxsize];
	int front,rear;
}queue;
void initqueue(queue &q) {
	q.rear = q.front =0;
}
bool isempty(queue q) {
	if (q.rear == q.front) return true;
	else return false;
}
bool isfull(queue q) {
	if (q.rear == maxsize) return true;
	else return false;
}
void enqueue(queue &q,int x) {
	if (isfull(q)) cout << "队列满" << endl;
	else {
		q.data[q.rear] = x;
		q.rear++;
	}
}
void dequeue(queue &q) {
	if (isempty(q))  cout << "队列空" << endl;
	else
	{
		q.front++;
	}
}
void gethead(queue q) {
	if (isempty(q))  cout << "队列空" << endl;
	else {
		cout<< q.data[q.front];
	}
}
int main() {
	queue q;
	initqueue(q);
	for(int i = 0; i < 10; i++)
	{
		enqueue(q, i);
	}
	gethead(q);
	cout << endl;
	dequeue(q);
	gethead(q);
	return 0;
}

执行结果:

 注意点:

由于是顺序存储的,在最开始就已经分配了一定大小的内存空间,所以必然要做判满和判空操作,当当前队列已经存满时,就不再往队列里插入元素。这里指的注意的是,判定为空的条件可以是q.front == q.rear。但是判空的条件不能是q.rear == maxsize,假设在某个时候,队列已经插满元素,这个时候去q.rear == maxsize,接下来,以此删除队列中一个元素,此时q.front ==1,此时队列显然不为空。这就造成了“假溢出”。

对于假溢出的概念,简单理解就是当前的队列的q.rear == maxsize但是,当前的队列并不满,有空间没有存入元素(0 -- (q.front-1)),这便造成大量的内存浪费。为解决这个问题,于是乎就有了下面的循环队列的概念。

 1.2顺序存储--循环队列:

循环队列在物理任然是一个连续的内存空间,但是在逻辑上是一个环。

 ***关于循环对的详细逻辑讲解,我会在后续出一个视频讲解,点个关注,第一时间获取讲解***

那么此时,就可以用出发取余运算(%)来实现空间的循环利用并解决普通队列判满的缺陷。

具体实现如下:

  • 初始化:Q.front == Q.rear == 0;
  • 队首指针进1(出队):Q.front = (Q.front+1)%maxsize;
  • 队尾指针进1(入队):Q.rear=(Q.rear+1)%maxsize;
  • 队列长度:(Q.rear+maxsize-Q.front)%maxsize;

判空条件:Q.front == Q.rear

判满条件:(Q.rear+1)%maxsize==Q.front -- 利用牺牲一个单元来区分队列空和满。

1.Initqueue(&Q):初始化队列,构造一个空队列:

void initqueue(queue &q) {
	q.rear = q.front =0;
}

2.QueueEmpty(Q):队列判空:

bool isempty(queue q) {
	if (q.rear == q.front) return true;
	else return false;
}

3.QueueFull(Q):队列判满:

bool isfull(queue q) {
	if ((q.rear +1)%maxsize == q.front) return true;
	else return false;
}

4.Enqueue(&Q,x):入队:

void enqueue(queue& q, int x) {
	if (isfull(q)) cout << "队列满" << endl;
	else {
		q.data[q.rear] = x;
		q.rear=(q.rear+1)%maxsize;
	}
}

5.Dequeue(&Q):出队:

void dequeue(queue& q) {
	if (isempty(q))  cout << "队列空" << endl;
	else
	{
		q.front=(q.front+1)%maxsize;
	}
}

6.GetHead(Q,x):读取对头元素:

void gethead(queue q) {
	if (isempty(q))  cout << "队列空" << endl;
	else {
		cout<< q.data[q.front];
	}
}

7.获取当前表长度:

int getlen(queue q)
{
	return (q.rear + maxsize - q.front) % maxsize;
}

整体代码:

#include<iostream>
#define maxsize 10
using namespace std;
typedef struct {
	int data[maxsize];
	int front, rear;
}queue;
void initqueue(queue& q) {
	q.rear = q.front = 0;
}
bool isempty(queue q) {
	if (q.rear == q.front) return true;
	else return false;
}
bool isfull(queue q) {
	if ((q.rear + 1) % maxsize == q.front) return true;
	else return false;
}
void enqueue(queue& q, int x) {
	if (isfull(q)) cout << "队列满" << endl;
	else {
		q.data[q.rear] = x;
		q.rear=(q.rear+1)%maxsize;
	}
}
void dequeue(queue& q) {
	if (isempty(q))  cout << "队列空" << endl;
	else
	{
		q.front=(q.front+1)%maxsize;
	}
}
void gethead(queue q) {
	if (isempty(q))  cout << "队列空" << endl;
	else {
		cout << q.data[q.front]<<endl;
	}
}
int getlen(queue q)
{
	return (q.rear + maxsize - q.front) % maxsize;
}
int main() {
	queue q;
	initqueue(q);
	for(int i = 0; i < maxsize-1; i++)
	{
		enqueue(q, i);
	}
	gethead(q);
	dequeue(q);
	gethead(q);
	return 0;
}

执行结果:

2.链式存储的队列

 链式存储的队列是一个同时代有对头指针队尾指针单链表

同样的,单链表可以有头节点也可以没有头结点,在我之前的关于单链表的文章里讲述里有无头结点的区别。本文使用的带头结点的单链表,方便操作。

队列的链式存储类型定义:

typedef struct {
	int data;
	struct LinkNode* next;
}LinkNode;

typedef struct {
	LinkNode* front, * rear;
}LinkQueue;

整体代码:

#include<iostream>
using namespace std;
typedef struct LinkNode {
	int data;
	struct LinkNode* next;
};

typedef struct LinkQueue{
	LinkNode* front, * rear;
};
void initlinkqueue(LinkQueue &Q) {
	LinkNode* head;
	head = new LinkNode;
	head->next = NULL;
	Q.front = head;
	Q.rear = head;
}
bool isempty(LinkQueue Q) {
	if (Q.front == Q.rear) return true;
	else return false;
}
void enqueue(LinkQueue& Q, int x) {
	LinkNode* s = new LinkNode;
	s->next = NULL;
	s->data = x;
	Q.rear->next = s;
	Q.rear = s;
}
void dequeue(LinkQueue& Q) {
	LinkNode* s;
	s = Q.front->next;
	Q.front->next = s->next;
	delete[]s;
}
void destoryQueue(LinkQueue& Q) {
	LinkNode* s = new LinkNode;
	if (!isempty(Q)) cout << "空" << endl;
	else {
		while (Q.front->next != NULL)
		{
			s = Q.front->next;
			Q.front = s->next;
			delete[]s;
		}
		delete[]Q.front;
		delete[]Q.rear;
	}
}
int main() {
	LinkQueue* Q;
	Q = new LinkQueue;
	initlinkqueue(*Q);
	for (int i = 0; i < 10; i++)
	{
		enqueue(*Q, i);
	}
	cout << Q->front->next->data << endl;
	dequeue(*Q);
	cout << Q->front->next->data << endl;
	destoryQueue(*Q);
	return 0;
}

执行结果:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值