【数据结构】五分钟自测主干知识(五)

本文介绍了队列的基本概念,包括FIFO原则和队列操作,重点讨论了顺序队列(使用数组实现,如循环队列)和链式队列的初始化、销毁、长度获取、入队和出队操作。同时对比了两种实现方式的优劣。
摘要由CSDN通过智能技术生成

书继上回:这节课我们来谈谈另一个典型代表:队列。

栈的插入和删除操作只能在线性表的一端进行,并且元素遵循“后进先出”的原则

而队列的插入和删除操作分布在两端,插入的一端是队尾,删除的一端是队首,并且元素遵循“先进先出”的原则。

与一般线性表相比,栈和队列的插入和删除操作受到了更多的约束和限制,故称作限定性线性表结构

(前言提示,本节与上一节内容结构及其相似,代码实现部分不作过多文字阐述)


3.4队列的基本概念

队列(Queue)也是一种线性结构,是一种限定只能在表的一端进行插入,另一端进行删除的线性表。在队列中,插入元素的一端称为“队尾”(Rear),删除元素的一端称为“队首”(Front)。

先进队列的元素先出队列,因此队列又称FIFO(First In First Out)表。

我们可以将其类比为“需要排队的表”

定义:

ADT Queue{
数据对象:D=\left \{ a_i|a_i\in ElemSet,i=1,2,\dots,n,n\geq 0\right \}
数据关系:R=\left \{ \left \langle a_{i-1},a_i \right \rangle |a_{i-1},a_i\in D,i=2,\dots,n\right \}
基本操作:


InitQueue(&Q)
操作结果:创建一个空的队列Q。


DestroyQueue(&Q)
操作结果:销毁队列Q。
参数说明:队列Q已存在。


ClearQueue(&Q)
操作结果:将队列Q清空。
参数说明:队列Q已存在。


QueueEmpty(Q)
操作结果:若队列Q为空则返回TRUE;否则返回FALSE。
参数说明:队列Q已存在。


QueueLength(Q)
操作结果:返回队列Q中的元素数,亦即队列的长度。
参数说明:队列Q已存在。


GetHead(Q,&e)
操作结果:将e赋值为队列Q的队首元素。
参数说明:队列Q已存在且非空。


EnQueue(&Q,e)
操作结果:将e插入队列Q成为新的队尾元素。
参数说明:队列Q已存在。

DeQueue(&Q,&e)
操作结果:若队列非空,删除队列Q的队首元素,并将其值赋给e。
参数说明:队列Q已存在。


QueueTraverse(Q)
操作结果:从队首到队尾依次输出Q中各个数据元素。
参数说明:队列Q已存在。


}end ADT Queue


3.5队列的表示与实现

队列的实现有顺序链式两种。

顺序队列

顺序队列一般设置两个静态指针 front(头指针)和rear(尾指针)来分别表示队首元素和队尾元素在队列中的位置。

注意这个“指针”也不是内存地址,而是一个 int 类型的值,它表示的是数组存储单元的下标。一般约定,初始空队列时front = rear =0;每当在队尾插入一个元素时 rear 加 1 ,每当在队首删除一个元素时 front 加1。这样,front 始终指向队列中的队首元素,而 rear 指针则指向队尾元素的“下一个”位置。


如果数组容量为n,我们向队首插入了超过n个数(当然也会从队尾删除一些元素使实际存储数的量小于n),rear的指向超出了数组的边界,而实际上这时队列空间并没有装满。为了解决这种情况,我们把顺序队列想象成一个首尾相接的循环空间,认为逻辑上rear的下一个位置又从数组空间的0下标开始,可以通过取模((rear+ 1)mod\enskip n=0)来实现。因此习惯上把这样的顺序队列称为循环队列

由于插满的满状态(有n个数)以及空队列的front和rear值都相等,无法区别。

因此我们少用一个队列空间,认为存有n-1个数,队列就满了,此时队列满的标志为:

((rear+ 1)mod\enskip n==front)

而队列空的标志为:

rear==front


循环队列实现如下:

#define QUEUE_INIT_SIZE 100
typedef int Elemtype;
typedef struct {
	Elemtype* elem;
	int queuesize;
	int front;
	int rear;
}SqQueue;

1.循环队列的初始化

void InitQueue(SqQueue& Q, int msize = QUEUE_INIT_SIZE) {
	Q.elem = new Elemtype[msize];
	Q.queuesize = msize;
	Q.front = Q.rear = 0;
}

2.循环队列的销毁操作

void DestroyQueue(SqQueue& Q) {
	delete[] Q.elem;
	Q.front = Q.rear = 0;
	Q.queuesize = 0;
}

3.获取循环队列的长度

int Queuelength(SqQueue Q) {
	return (Q.rear + Q.queuesize - Q.front) % Q.queuesize;
}

4.入队列操作

void Enqueue(SqQueue& Q, Elemtype e) {
	if ((Q.rear + 1) % Q.queuesize == Q.front)Increment(Q);
//如果队列满则增加空间
	Q.elem[Q.rear] = e;
	Q.rear = (Q.rear + 1) % Q.queuesize;
}

Increment函数已经是我们的老朋友了,大家可以翻看前面的笔记来思考它的实现

参考代码:(之前的顺序栈内容,可以把SqStack改成SqQueue)

void ErrorMsg(const char* a) {
	printf(a);        //错误处理函数,我们老熟人了,再打上去一次
}
void Increment(SqStack& S) {
	ElemType* a;
	a = new ElemType[S.stacksize + 1];//重新创建一个数组
	if (!a) { ErrorMsg("内存创建失败"); return; }
	for (int i = 0; i < S.stacksize; i++) {
		a[i] = S.elem[i];
	}
	delete[] S.elem;
	S.elem = a;
	S.stacksize++;//容量加一
}

5.出队列操作

bool DeQueue(SqQueue& Q, Elemtype& e) {
	if (Q.front == Q.rear) return false;
	e = Q.elem[Q.front];
	Q.front = (Q.front + 1) % Q.queuesize;
	return true;
}

其实与栈部分相同,链队列其实比顺序队列更佳 


链队列

链式存储方式实现的队列称为链队列。

链队列的实现为:

LinkList是链表,其实现请查看我之前的文字:附链接:【数据结构】五分钟自测主干知识(三)

http://t.csdnimg.cn/OsA27icon-default.png?t=N7T8http://t.csdnimg.cn/OsA27在这里我以后就直接用了,不作过多阐述

typedef LinkList Queueptr;
typedef struct {
	Queueptr front;
	Queueptr rear;
}LinkQueue;

1.链队列的初始化

void InitQueue(LinkQueue& Q) {
	Q.front = Q.rear = new LNode;
	Q.front->next = NULL;
}

2.链队列的销毁

void DestroyQueue(LinkQueue& Q) {
	while (Q.front) {
		Q.rear = Q.front->next;
		delete Q.front;
		Q.front = Q.rear;
	}
}

3.链队列获取队首元素

bool GetHead(LinkQueue Q, ElemType& e) {
	if (Q.front == Q.rear) return false;
	e = Q.front->next->data;
	return true;
}

4.入队列操作

void Enqueue(LinkQueue& Q, ElemType e) {
	LNode*p = new LNode;
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
}

5.出队列操作

bool DeQueue(LinkQueue& Q, ElemType& e) {
	if (Q.front == Q.rear)return false;
	LNode*p = Q.front->next;
	Q.front->next = p->next;
	e = p->data;
	if (Q.rear == p) Q.rear = Q.front;
	delete p;
	return true;
}

出队列操作时,如果删除的结点是队列中唯一的元素结点,那么在删除该结点之后还需要修改rear指针。可以看出,和顺序存储相比,链式存储是实现队列更好的选择! 


下一讲,我们来探讨一个新的概念“串”

我做好了会把链接直接放在这里,供需要自测的读者方便自取~

【数据结构】五分钟自测主干知识(六)

http://t.csdnimg.cn/ZSxmTicon-default.png?t=N7T8http://t.csdnimg.cn/ZSxmT

  • 14
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值