IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构与算法学习笔记——队列 -> 正文阅读

[数据结构与算法]数据结构与算法学习笔记——队列

数据结构与算法学习笔记(C语言)

1.定义:队列是一种先进先出(FIFO)的线性表,它只允许从一端插入,而在另一端删除删除元素。

这和我们日常生活中的排队是一样的,排在第一个的人先办事,后来的人排在队尾。

在队列中,允许插入的一段叫队尾(rear),允许删除的一端叫队头(front)。
插入元素到队尾叫入队,删除队头的元素叫出队。

队列的抽象数据类型定义:

ADT Queue {
	数据对象:D = {a1, a2, a3...}
	数据关系:R = {<a1, a2>,<a2, a3>...}
	基本操作:
	InitQueue(*Q) /*初始化队列*/
	DestroyQueue(*Q) /*销毁队列*/
	ClearQueue(*Q) /*清空队列*/
	QueueEmpty(Q) /*若队列为空,返回true,否则返回false*/
	QueueLength(Q) /*返回队列元素的个数*/
	GetHead(Q, *e) /*获取队头元素*/
	EnQueue(*Q, e) /*入队,元素插入队尾*/
	DeQueue(*Q, *e) /*出队,删除队头元素*/
	QueueTraverse(Q) /*遍历队列*/
}ADT Queue

2.队列的链式存储

一个链队列需要两个分别指示队头和队尾的指针唯一确定,为了操作方便,我们也给链队列添加一个头结点
如果没有头节点,那么初始化之后,入队第一个元素的时候,要把头指针指向新添加的节点,出队最后一个元素的时候,又和出队其他节点的操作不一样
链队列
链队列的C语言描述

typedef struct QNode {
	QElemType data;
	struct QNode *next;
}QNode, *QueuePtr;
typedef struct {
	QueuePtr front; /*队头指针*/
	QueuePtr rear; /*队尾指针*/
}LinkQueue;

基本操作的函数原型说明

Status InitQueue(LinkQueue *Q) /*构建一个空队列*/
Status DestroyQueue(LinkQueue *Q) /*销毁队列*/
Status ClearQueue(LinkQueue *Q) /*清空队列*/
bool QueueEmpty(LinkQueue Q) /*返回链队列是否为空*/
int QueueLength(LinkQueue Q) /*返回元素的个数*/
Status GetHead(LinkQueue Q, QElemType *e) /*获取队头元素*/
Status EnQueue(LinkQueue *Q, QElemType e) /*插入元素e为队尾元素*/
Status DeQueue(LinkQueue *Q, QElemType *e) /*队头元素出队*/
void QueueTraverse(LinkQueue Q) /*遍历队列元素并打印*/

1.队列初始化

Status InitQueue(LinkQueue *Q) 
{
	Q->front = (QueuePtr)malloc(sizeof(QNode));
	if (!Q->front) exit(OVERFLOW);
	Q->rear = Q->front;
	Q->front->next = NULL;
	return OK;
} 

2.销毁队列

Status DestroyQueue(LinkQueue *Q)
{
	while(Q->front) {
	/*俩指针一前一后,逐节点释放空间*/
		Q->rear = Q->front->next;
		free(Q->front);
		Q->front = Q->rear;
	}
	return OK;
}

3.清空队列

Status ClearQueue(LinkQueue *Q)
{
	QueuePtr p;
	if (Q->front == Q->rear) return OK;
	/*已经是空队列*/
	p = Q->front;
	/*保存头节点的位置*/
	Q->rear = p->next;
	/*从头节点开始释放队列节点的元素,最后只剩头节点*/
	while (Q->rear) {
		Q->front = Q->rear->next;
		free(Q->rear)
		Q->rear = Q->front;
	}
	Q->front = p;
	/*头指针指回头节点*/
	Q->front->next = NULL;
}

4.判断队列是否为空

bool QueueEmpty(LinkQueue Q)
{
	if (Q.front == Q.rear) return true;
	else return false;
}

5.求队列长度

int QueueLength(LinkQueue Q)
{
	int i = 0;
	/*不用担心改变队尾指针的指向,值传递是实参的拷贝,不会改变传入的队列*/
	Q.rear = Q.front->next;
	while(Q.rear) {
		++i;
		Q.rear = Q.rear->next;
	}
	return 0;
}

6.取队头元素

Status GetHead(LinkQueue Q, QElemType *e)
{
	if (Q.front == Q.rear) return ERROR;
	*e = Q.front->next->data;
	return OK;
}

7.入队

Status EnQueue(LinkQueue *Q, QElemType e)
{
	QueuePtr p;
	p = (QueuePtr)malloc(sizeof(QNode));
	if (!p) exit(OVERFLOW);
	p->data = e;
	p->next = NULL;
	Q->rear->next = p;
	Q->rear = p;
	return OK;
}

8.出队

Status DeQueue(LinkQueue *Q, QElemType *e)
{
	QueuePtr p;
	if (Q->rear == Q->front) return ERROR;
	p = Q->front->next;
	*e = p->data;
	Q->front->next = p->next;
	/*当队列中最后一个元素被删除时,让队尾指针指向头节点*/
	if (p == Q->rear) Q->rear = Q->front;
	free(p);
	return OK;
}

9.打印队列中的元素

void QueueTraverse(LinkQueue Q)
{
	Q.rear = Q.front->next;
	while (Q.rear) {
		printf("%c ", Q.rear->data);
	}
	printf("\n");
}

队列的顺序存储
1.定义:用一组地址连续的存储单元依次存放从队列到队尾的元素,附设两个整形变量作为队头和队尾的标记,记录队头、队尾的下标

队列
队列为空时,Q.rear = Q.front = 0;队列满时,Q.rear = MAXSIZE;
但是,这里明显有一个大问题,因为元素出队,Q.front++,最后Q.front前面的存储单元都用不了了,造成队列“假空”,为了解决这个问题,我们定义循环队列

将申请的连续空间假想成环状的,0存储单元和最后一个存储单元首尾相接
循环队列
注意:指针malloc申请的空间一定是地址连续的存储单元,想象成环状是我们在逻辑上这么想,与之相反的就像地球是圆的,我们可以认为汽车是在平地上行驶(不太恰当,但就这样吧)

从图中,可以看出,当循环队列为空时,Q.front = Q.rear = 0;
当循环队列满的时候,在环状空间逻辑上,Q.front 在Q.rear的下一个存储单元
Q.front = (Q.rear + 1) % MAXSIZE;

循环队列的C语言描述

#define MAXSIZE 100 
/*循环队列的最大存储空间,由循环队列的特征,可以知道分配的存储空间不可扩大*/
typedef struct {
	QElemType *base;
	int front;
	int rear;
}SqQueue;

循环队列各种操作的实现
1.初始化队列

Status InitQueue(SqQueue *Q)
{
	Q->base = (QElemType *)malloc(MAXSIZE * sizeof(QElemType));
	if (!Q->base) exit(OVERFLOE);
	Q->front = Q->rear = 0;
	return OK;
}

2.销毁队列

Status DestroyQueue(SqQueue *Q)
{
	Q->front = Q->rear = 0;
	free(Q->base);
	Q->base = NULL; 
	return OK;
}

3.清空队列

Status ClearQueue(SqQueue *Q)
{
	Q->front = Q->rear = 0;
	return OK;
}

4.判断队列是否为空

bool QueueEmpty(SqQueue Q)
{
	if (Q.front == Q.rear) return true;
	else return false;
}

5.返回队列元素的个数

int QueueLength(SqQueue Q)
{
	/*这个式子不难理解,就是就算元素从屁股后面转到前面了,求余就能消除循环的影响而得到真实长度,
	想像钟表指针之间的时差,相减对12取余就是了*/
	return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

6.取队头元素

Status GetHead(SqQueue Q, QElemType *e)
{
	if (Q.front == Q.rear) return ERROR;
	*e = Q.base[Q.front];
	return OK;
}

7.元素入队

Status EnQueue(SqQueue *Q, QElemType e)
{
	if (Q->front == (Q->rear + 1) % MAXSIZE) return ERROR;
	Q->base[Q->rear] = e;
	Q->rear = (Q->rear + 1) % MAXSIZE;
	/*元素没转过来的时候忽略取余,元素转到前面来后,取余得到就是从0开始的下标*/
	return OK;
}

8.元素出队

Status DeQueue(SqQueue *Q, QElemType *e)
{
	if (Q->front == Q->rear) return ERROR;
	*e = Q->base[Q->front];
	Q->front = (Q->front + 1) % MAXSIZE;
	/*元素没转过来的时候忽略取余,元素转到前面来后,取余得到就是从0开始的下标*/
	return OK;
}

9.遍历队列元素

void QueueTraverse(SqQueue Q)
{
	if (Q.rear == Q.front) return;
	/*循环队列为空,直接返回*/
	else if (Q.rear > Q.front) {
		for (i = Q.front; i < Q.rear; i++) 
			printf("%c ", Q.base[i]);
	}
	else {
	/*如果队尾的下标小于队头的,表示元素从尾部转过来了,有两部分元素需要打印*/
		for (i = Q.front; i < MAXSIZE; i++)
			printf("%c ", Q.base[i]);
		for (i = 0; i < Q.rear; i++)
			printf("%c ", Q.base[i]);
	}
}

队列这部分比较难以理解的可能就是循环队列这一部分了,结合钟表的表盘,理解一下取余对于求真实差值的意义,那么循环队列也不是很难理解,加油!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:42:15  更:2021-08-31 15:42:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:53:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码