TD03-队列


一、队列基本概念

队列是一种操作受限的线性表
先进先出(First In First Out)
对头(Front):允许删除的一端,又称队首
队尾(Rear):允许插入的一端

二、队列的顺序存储

队列的顺序存储是指分配一块连续的存储单元存放队列中的元素

1.顺序存储类型描述

//队列顺序存储类型描述
#define MaxSize 10
typedef struct {
	Elemtype data[MaxSize];
	int front, rear;
}SqQueue;

问题:通过初始化,可以由Q.rear = Q.front = 0判断队列是否为空,但是不能由作为Q.rear==MaxSize判断队列满的条件!!!因为会有假溢出,面对这样的情况,引出了循环队列

2.循环队列

由顺序队列的缺点,将顺序队列臆造为一个环状空间,把存储队列元素从逻辑上视为一个环,称为循环队列。主要利用除法取余运算
初始时:Q.rear = Q.front = 0
队首指针进1:Q.front = (Q.front + 1) % MaxSize;
队尾指针进1:Q.rear = (Q.rear + 1) % MaxSize;
队列长度:(Q.rear - Q.front + MaxSize) % MaxSize

问题:队空条件、队满条件都是Q.rear = Q.front,无法区分队空队满!!! 面对这样的问题,有了三种处理方式

3.判断队空队满的三种方式

1、牺牲一个单元来区分队空队满。入队时少用一个队列单元(比较常用
队满:(Q.rear + 1) % MaxSize = = Q.front
队空:Q.rear = = Q.front
队列中元素个数:(Q.rear - Q.front + MaxSize) % MaxSize

2、定义类型时加入一个表示元素个数的变量,如int size;
初始化时:rear=front=0; size=0;
插入成功:size++;
删除成功:size–;
队满条件:size= =MaxSize;
队空条件:size= =0;

3、定义类型时加入一个表示队满队空状态的成员,如int tag;
初始化时:rear=front=0; tag=0;
插入成功:tag=1;
删除成功:tag=0;
队满条件:tag=1;
队空条件:tag=0;
(解释:只有删除操作导致队空;只有插入操作导致队满)

4.其他基本操作

1、初始化

//初始化
void InitQueue(SqQueue& Q) {
	Q.rear = Q.front = 0;			//初始化队首、队尾指针
}

2、判队空

//判队空
bool isEmpty(SqQueue Q) {
	if (Q.rear == Q.front)			//队空条件
		return true;
	else
		return false;
}

3、入队

//入队
bool EnQueue(SqQueue& Q, Elemtype x) {
	if ((Q.rear + 1) % MaxSize == Q.front)		//队满
		return false;
	Q.data[Q.rear] = x;
	Q.rear = (Q.rear + 1) % MaxSize;			//尾指针加一取模
	return true;
}

4、出队

//出队
bool DeQueue(SqQueue& Q, Elemtype& x) {
	if (Q.rear == Q.front)						//队空
		return false;
	x = Q.data[Q.front];
	Q.front = (Q.front + 1) % MaxSize;			//队头指针加一取模
	return true;
}

5、取队头元素

//取队头元素
bool GetHead(SqQueue Q, Elemtype& x) {
	if (Q.rear == Q.front)
		return false;
	x = Q.data[Q.front];
	return true;
}

6、求循环队列长度

//求循环队列长度
int QueueLength(SqQueue Q) {
	return(Q.rear - Q.front + MaxSize) % MaxSize;
}

三、队列的链式存储

队列的链式表示称为链队列,它实际上是一个同时带有队头指针和队尾指针的单链表
出队:取出队头元素
入队:插入到队尾

1.链式存储类型描述

//队列的链式存储
//记录队长:可以设置变量,从队头开始遍历,统计长度,需要的结点数O(n);若经常需要可以在定义类型时加入length变量进行元素记录
typedef struct LinkNode {			//链式队列结点
	Elemtype data;
	struct LinkNode* next;
}LinkNode;
typedef struct {					//链式队列
	LinkNode* front, * rear;		//设置队尾指针:插入操作时就不需要从前往后查找
}LinkQueue;

2.其他基本操作

1、初始化队列

//初始化队列(带头结点)
void InitQueue(LinkQueue& Q) {		//申请一个头结点并让头指针和尾指针同时指向头结点
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	Q.front->next = NULL;
}
//初始化队列(不带头结点)
void InitQueue2(LinkQueue& Q) {
	Q.front = NULL;
	Q.rear = NULL;
}

2、判空

//判空(带头结点)
bool IsEmpty(LinkQueue Q) {
	if (Q.front == Q.rear)			//也可以用Q.front->next = NULL;作为判断
		return true;
	else
		return false;
}

//判空(不带头结点)
bool IsEmpty2(LinkQueue& Q) {
	if (Q.front == NULL)
		return true;
	else
		return false;
}

3、入队

//入队(不带头结点)----因为不带头结点,所以第一个元素入队时需要特殊化
void EnQueue(LinkQueue& Q, Elemtype x) {
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	if (Q.front == NULL) {		//空队列中插入第一个元素单独处理,修改队头队尾指针
		Q.front = s;
		Q.rear = s;
	}
	else {
		Q.rear->next = s;			//非空队列插入元素修改rear尾指针
		Q.rear = s;
	}
}

4、出队

//出队(带头结点)
bool DeQueue(LinkQueue& Q, Elemtype& x) {
	if (Q.front == Q.rear)			//判空
		return false;
	LinkNode* p = Q.front->next;	//指针指向出队结点
	x = p->data;					//返回值
	Q.front->next = p->next;		//移动front指针,如果只有一个元素,那命这里Q.front->next = p->next = NULL
	if (Q.rear == p)				//处理:若只有一个元素,删除后Q.rear = Q.front;空队列设置
		Q.rear = Q.front;
	free(p);
	return true;
}

//出队(不带头结点)
bool DeQueue(LinkQueue& Q, Elemtype& x) {
	if (Q.front == NULL)			//判空
		return false;
	LinkNode* p = Q.front;			//指针指向出队结点
	x = p->data;					//返回值
	Q.front = p->next;				//移动front指针
	if (Q.rear == p) {				//处理:若只有一个元素,删除后空队列设置
		Q.front = NULL;
		Q.rear = NULL;
	}
	free(p);
	return false;
}

四、顺序存储与链式存储对比

1、顺序存储需要预分配空间,会出现队满;链式存储一般不会队满
2、单链表:适用于数据元素变动较大,而且不存在队列满且产生溢出的问题;适用于程序中多个队列,最好使用链式队列

五、纠错

1、循环队列存储在数组[0…n]中,入队时操作
A:rear=rear+1
B:rear=(rear+1)mod(n-1)
C:rear=(rear+1)mod(n)
D:rear=(rear+1)mod(n+1)
下标范围 0~n,数组容量n+1

2、用链式存储方式的队列进行删除操作时需要
A:仅修改头指针
B:头指针尾指针可能都要修改
头指针尾指针可能都要修改(例:队列中只有一个元素时,队尾指针还要移动:rear=front)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值