【数据结构基础笔记】【队列】
代码参考《妙趣横生的算法.C语言实现》
文章目录
- 前言
- 1、队列定义
- 2、创建一个队列
- 3、入队列
- 4、出队列
- 5、销毁一个队列
- 6、循环队列的概念
- 7、循环队列的实现
- 8、实例分析
前言
本章总结:链队列定义,创建,出队入队操作,销毁操作;循环队列的定义以及循环队列的一些基本操作
1、队列定义
队列是一种先进先出的线性表(FIFO),它要求所有的数据从队列的一端进入,从队列的另一端离开。
在队列中,允许插入数据的一端角队尾,允许数据离开的一端叫做队头。
队列是一个线性表,既可以是一个顺序表也可以是一个链表。这里重点介绍用链表实现一个队列。
typedef char ElemType ;
//队列元素类,队列中的每个元素都是QNode类
typedef struct QNode{ElemType data; //队列结点的数据域struct QNode* next; //队列结点的指针域
}QNode, *QueuePtr;typedef struct {QueuePtr front; //队头指针,用来存放队头元素的地址QueuePtr rear; //队尾指针,用来存放队尾元素的地址
}LinkQueue;
//这里定义得队列是一个链队列,队列之间的元素由指针相连,所以只要掌握了队列的队头指针和队尾指针,就可以对队列进行各种
2、创建一个队列
创建一个队列要完成两步:
1、在内存中创建一个头结点,但该头结点不是用来存放数据的,而是为了操作方便人为添加的。
2、将队列的头指针和尾指针都指向这个生成的头结点,此时队列中没有任何队列元素,该队列为空队列。
这样判断队列为空的条件就是头指针front和尾指针rear都同时指向头结点。
//创建一个空队列
void InitQueue(LinkQueue* q)
{q->front = q->rear = (QueuePtr)malloc(sizeof(QNode)); //初始化一个队列指针大小的空间,并将地址传给头指针和尾指针if (!q->front){printf("内存分配失败");exit(0);}q->front->next = NULL; //头结点指针域指向空
}
此时空队列的状态如下:
3、入队列
入队列就是讲一个QNode类型的结点从队列尾部进入队列。
每当一个队列元素插入队列,队列的尾指针都要进行修改。
队头的指针不改变。
//入队列
void EnQueue(LinkQueue* q,ElemType elem)
{QueuePtr p;p = (QueuePtr)malloc(sizeof(QNode)); //创建一个队列元素结点,并将地址传给指针pif (p == NULL){printf("分配内存失败");exit(0);}p->data = elem; //将数据elem放到队列结点data域中p->next = NULL;q->rear->next = p; //从队尾插入元素q->rear = p; //修改队尾指针,注意,此时队尾指针指向空(q->rear->next = p->next =NULL)
}
入队列操作流程:
4、出队列
出队列操作就是将队列中的元素从队列的头部移除。每次从队列中一出数据时,队头指针front不改变,但是头结点的next指针要发生改变。队尾指针rear只有在(队头即队尾)的情况下才会改变,否则也不改变。
//出队列
void DeQueue(LinkQueue* q, ElemType *elem)
{QueuePtr p;//如果队列不为空,删除q的队头元素,用e返回其值if (q->front == q->rear) return; //队列为空,返回p = q->front->next; //p指向队列的第一个元素*elem = p->data; //将队首元素数据传给eq->front->next = p->next; //删除当前头结点if (q->rear == p) q->rear = q->front; //如果此时队列为空,则修改队尾指针free(p); //将原本队头结点销毁
}
效果如下:
1、当队伍中存在超过1个元素
2、当队伍中只有一个元素时
5、销毁一个队列
由于队列建立在内存动态区(堆内存),因此当一个队列不再有用时,应当把它及时销毁掉,以免占用内存空间得不到释放导致内存泄漏。
释放一块内存要做两点:1.释放指向它的指针。2.将该指针指向空
void DestroyQueue(LinkQueue* q)
{while (q->front) //如果队列头指针还存在{q->rear = q->front->next; //q->rear指向q->front的后继结点free(q->front); //释放q->front,此时q->rear应该指向NULLq->front = q->rear;}
}
6、循环队列的概念
用顺序表实现的队列称为循环队列,此队列的空间是可以循环使用的。
循环队列一般来说有固定的容量。
如果不断地有元素入队列,同时又不断地有元素出队列,那么对于一般的链队列,只要队列不为空,头指针front和尾指针rear都不会改变,只有头指针的next指针和尾指针的前一个结点的next指针会发生变化,而且链队列的长度也会随着入出度列元素而不断变化。
循环队列,容量固定,队头指针和队尾指针都可以随着元素的入出队列而发生改变,这样循环队列逻辑上就是一个环形的存储空间,只要队列中有空单元未使用,就可以向队列中存放元素
所以循环队列可以作为缓冲池存储结构来存放数据。
该队列总容量为8B,实际长度为5B。这里规定循环队列头指针front始终指向队头元素,尾指针rear始终指向队尾元素的下一个空间。
这里队头元素:f,队尾元素:b,该队列实际可用空间为7B。
将队首元素f出队列,在队尾加入元素a,形成上面队列。
所以,入队列操作就是想rear指向的空间赋值,rear再指向队尾元素的下一个空间。
出队列就是将队头指针front向上移一个单元。整个循环队列逻辑上就是一个首尾相接的环形缓冲区。
7、循环队列的实现
现实中只有线性的存储单元,不存在环形存储单元。
只需要注意rear不断加1后超过循环队列的地址范围,采用取模运算处理的结果。
因此,无论是入队列的rear+1操作还是出队列的front+1操作,实际都是模加运算,即
(rear+1)%len 和(front+1)%len
/*****************************循环队列******************************************/
//定义一个循环队列
#define MAXQSIZE 100
typedef struct {ElemType* base; //循环队列内存分配基地址int front; //队头int rear; //队尾
}cycleQueue; //循环队列类cycleQueue//初始化一个循环队列
void InitcycleQueue(cycleQueue *q)
{q->base = (ElemType*)malloc(MAXQSIZE*sizeof(ElemType));//开辟MAXQSIZE个单元的顺序表作为循环队列的存储空间if (!q->base){printf("循环队列分配内存失败");exit(0);}q->front = q->rear = 0; //空队列,front和rear都指向0号单元}
//入队列操作
void EncycleQueue(cycleQueue* q, ElemType elem)
{if ((q->rear + 1) % MAXQSIZE == q->front) return; //循环队列已满q->base[q->rear] = elem; //将元素elem入队列,q->base为顺序表的额首地址q->rear = (q->rear + 1) % MAXQSIZE; //队尾指针+1,注意这里的全部都是模加运算
}
//出队列操作
void DecycleQueue(cycleQueue* q, ElemType* elem)
{if (q->front == q->rear) return; //循环队列为空*elem = q->base[q->front]; //取出队头元素q->front = (q->front + 1) % MAXQSIZE; //队头指针+1
}
8、实例分析
实现一个链队列,任意输入一串字符,以@为结束标志,然后将队列中的元素逐一取出,打印出来
#include "stdio.h"
#include "malloc.h"
#include "conio.h"
#include <stdlib.h>
#include <math.h>
typedef char ElemType ;
/*****************************链队列******************************************/
//队列元素类,队列中的每个元素都是QNode类
typedef struct QNode{ElemType data; //队列结点的数据域struct QNode* next; //队列结点的指针域
}QNode, *QueuePtr;typedef struct {QueuePtr front; //队头指针,用来存放队头元素的地址QueuePtr rear; //队尾指针,用来存放队尾元素的地址
}LinkQueue;
//这里定义得队列是一个链队列,队列之间的元素由指针相连,所以只要掌握了队列的队头指针和队尾指针,就可以对队列进行各种操作。、//创建一个空队列
void InitQueue(LinkQueue* q)
{q->front = q->rear = (QueuePtr)malloc(sizeof(QNode)); //初始化一个队列指针大小的空间,并将地址传给头指针和尾指针if (!q->front){printf("内存分配失败");exit(0);}q->front->next = NULL; //头结点指针域指向空
}
//入队列
void EnQueue(LinkQueue* q,ElemType elem)
{QueuePtr p;p = (QueuePtr)malloc(sizeof(QNode)); //创建一个队列元素结点,并将地址传给指针pif (p == NULL){printf("分配内存失败");exit(0);}p->data = elem; //将数据elem放到队列结点data域中p->next = NULL;q->rear->next = p; //从队尾插入元素q->rear = p; //修改队尾指针,注意,此时队尾指针指向空(q->rear->next = p->next =NULL)
}
//出队列
void DeQueue(LinkQueue* q, ElemType *elem)
{QueuePtr p;//如果队列不为空,删除q的队头元素,用e返回其值if (q->front == q->rear) return; //队列为空,返回p = q->front->next; //p指向队列的第一个元素*elem = p->data; //将队首元素数据传给eq->front->next = p->next; //删除当前头结点if (q->rear == p) q->rear = q->front; //如果此时队列为空,则修改队尾指针free(p); //将原本队头结点销毁
}//销毁一个队列
//释放一块内存要做两点:1.释放指向它的指针。2.将该指针指向空
void DestroyQueue(LinkQueue* q)
{while (q->front) //如果队列头指针还存在{q->rear = q->front->next; //q->rear指向q->front的后继结点free(q->front); //释放q->front,此时q->rear应该指向NULLq->front = q->rear;}
}/*****************************循环队列******************************************/
//定义一个循环队列
#define MAXQSIZE 100
typedef struct {ElemType* base; //循环队列内存分配基地址int front; //队头int rear; //队尾
}cycleQueue; //循环队列类cycleQueue//初始化一个循环队列
void InitcycleQueue(cycleQueue *q)
{q->base = (ElemType*)malloc(MAXQSIZE*sizeof(ElemType));//开辟MAXQSIZE个单元的顺序表作为循环队列的存储空间if (!q->base){printf("循环队列分配内存失败");exit(0);}q->front = q->rear = 0; //空队列,front和rear都指向0号单元}
//入队列操作
void EncycleQueue(cycleQueue* q, ElemType elem)
{if ((q->rear + 1) % MAXQSIZE == q->front) return; //循环队列已满q->base[q->rear] = elem; //将元素elem入队列,q->base为顺序表的额首地址q->rear = (q->rear + 1) % MAXQSIZE; //队尾指针+1,注意这里的全部都是模加运算
}
//出队列操作
void DecycleQueue(cycleQueue* q, ElemType* elem)
{if (q->front == q->rear) return; //循环队列为空*elem = q->base[q->front]; //取出队头元素q->front = (q->front + 1) % MAXQSIZE; //队头指针+1
}//测试函数
int main()
{ElemType e;LinkQueue q;InitQueue(&q); //初始化一个队列qprintf("请输入一串字符到队列中\n");scanf("%c",&e);while (e != '@'){EnQueue(&q,e);scanf("%c", &e);}printf("队列为:\n");while (q.front != q.rear){DeQueue(&q, &e);printf("%c",e);}printf("\n");DestroyQueue(&q); //销毁队列q_getche();return 0;
}
效果:
【数据结构基础笔记】【队列】相关推荐
- Python数据结构学习笔记——队列和双端队列
目录 一.队列的定义 二.队列 实现步骤分析 三.队列的Python实现代码 四.队列的应用 六人传土豆游戏 五.双端队列的定义 六.双端队列 实现步骤分析 七.双端队列的Python实现代码 八.双 ...
- 实战PHP数据结构基础之队列
什么是队列 队列是另外一种遵循先进先出原则的线性数据结构.队列有两端可供操作,一端出队,一端入队.这个特点和栈不同,栈只有一端可以用来操作.入队总是在后端,出队在前端. 常见操作 enqueue -& ...
- 【数据结构基础笔记】【栈】
代码参考<妙趣横生的算法.C语言实现> 文章目录 前言 1.栈的定义 2.创建一个栈 3.入栈和出栈操作 4.栈的清空.销毁.计算栈的当前容量 5.实例分析 前言 本章总结:栈的定义.创建 ...
- 【数据结构基础笔记】【链表】
代码参考<妙趣横生的算法.C语言实现> 文章目录 前言 1.链表基础 2.创建一个链表 3.插入结点 4.删除结点 5.销毁链表 6.实例分析 前言 本章总结:链表的定义.创建.销毁,结点 ...
- 蓝桥杯python省赛冲刺篇1——数据结构基础:队列、栈、排序
注意:加了题目链接 目录 注意:加了题目链接 CLZ 的银行普通队列(队列) 题目描述 输入描述 输出描述 输入输出样例 示例1 代码演示 小邋遢的衣橱(栈) 题目描述 输入描述 输出描述 输入输出样 ...
- 【数据结构基础笔记】【树】
代码参考<妙趣横生的算法.C语言实现> 文章目录 前言 1.树的概念 2.二叉树 3.二叉树的遍历 4.创建二叉树 5.实例分析 前言 本章总结:树的概念.二叉树的创建.遍历 1.树的概念 ...
- 【数据结构基础笔记】【顺序表】
代码参考<妙趣横生的算法.C语言实现> 文章目录 前言 1.创建顺序表 2.顺序表插入元素 3.顺序表删除元素 4.顺序表实例分析 1.静态 2.动态 5.顺序表总结 前言 本章总结:从静 ...
- 一周刷爆LeetCode,算法da神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解 笔记
一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解 笔记 教程与代码地址 P1 出圈了!讲课之外我们来聊聊 ...
- 【数据结构基础】线性数据结构——栈和队列的总结及封装(C和java)
前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...
最新文章
- 【MySQL】在centos7 纯IPv6环境下,安装mysql5.7
- MyEclipse 16(汉化版)安装教程
- 极客产品经理学习笔记
- 概率论和数理统计 - 01
- 《软件工程导论》课后习题答案
- CoreData 从入门到精通(三)关联表的创建
- Transformer为啥在NER上表现不好
- git学习笔记(三)
- hadoop系列一:hadoop集群安装
- thinkphp5之配置tp5重写伪静态
- 利用iframe来做无刷新上传
- webrtc-sdp编码信息协商
- web前端-写给大家看的设计书-笔记-颜色运用-色轮使用
- 小宝精灵-智能语音遥控伴侣(套装版)测评-遥控器的语音时代
- SuperMap 地图裁剪
- 拼多多之所以壮大,在于淘宝对利益过度痴迷
- android手游开发三维地图高清版,三维地图实景地图下载手机
- redis安装,redis安装windows服务
- ai前世识别_AI人脸识别前世今生app-AI人脸识别前世今生软件下载v2.0-西西软件下载...
- 启动SpringBoot报错:Field userService in com.sunshin.controller.UserController required a bean of type...