diff --git a/数据结构/code/LoopQueue.cpp b/数据结构/code/LoopQueue.cpp new file mode 100644 index 0000000..02dc1d6 --- /dev/null +++ b/数据结构/code/LoopQueue.cpp @@ -0,0 +1,56 @@ +/* + * @Description: 循环队列操作 + * @Version: Beta1.0 + * @Author: 【B站&公众号】Rong姐姐好可爱 + * @Date: 2019-09-27 14:17:28 + * @LastEditors: 【B站&公众号】Rong姐姐好可爱 + * @LastEditTime: 2021-03-18 23:52:10 + */ + + + +// 队列最大存储元素个数 +#define MaxSize 50 + +// 结构体定义 +typedef struct { + // 存放队列元素 + ElemType data[MaxSize]; + // 队头指针和队尾指针 + int front,rear; +} SqQueue; + + + + +// 入队算法 +// 尾插法:Q.data[Q.rear]=x;Q.rear=(Q.rear+1)%Maxsize;Q.tag=1 +// 队空条件:Q.front== Q.rear且Q.tag==0 +int EnLoopQueue(SqQueue &Q, ElemType x){ + if(Q.front==Q.rear&&Q.tag==1){ + return 0; + } + Q.data[Q.rear]=x; + Q.rear=(Q.rear+1)%MaxSize; + Q.tag=1; + return 1; +} + + + +// 出队算法 +// 头结点删除:x=Q.data[Q.front];Q.front=(Q.front +1)%Maxsize;Q.tag=0 +// 队满条件:Q.front == Q.rear且Q.tag=1 +// 注意:当删除之后链表为空时,还需增加一步,将尾指针指向头结点 +int DeLoopQueue(SqQueue &Q, ElemType &x){ + if (Q.front==Q.rear&&Q.tag==0){ + return 0; + } + x=Q.data[Q.front]; + Q.front=(Q.front+1)%MaxSize; + Q.tag=0; + return 1; +} + + + diff --git a/数据结构/栈和队列/.DS_Store b/数据结构/栈和队列/.DS_Store index e455563..7d26eda 100644 Binary files a/数据结构/栈和队列/.DS_Store and b/数据结构/栈和队列/.DS_Store differ diff --git a/数据结构/栈和队列/5.队列的顺序存储结构.md b/数据结构/栈和队列/5.队列的顺序存储结构.md index 8df170f..5a81d91 100644 --- a/数据结构/栈和队列/5.队列的顺序存储结构.md +++ b/数据结构/栈和队列/5.队列的顺序存储结构.md @@ -4,7 +4,7 @@ * @Author: 【B站&公众号】Rong姐姐好可爱 * @Date: 2020-03-1 07:23:48 * @LastEditors: 【B站&公众号】Rong姐姐好可爱 - * @LastEditTime: 2021-03-17 23:23:09 + * @LastEditTime: 2021-03-18 23:51:35 --> @@ -121,13 +121,90 @@ typedef struct { - 队列长度: `(Q.rear+MaxSize-Q.front)%MaxSize` -是不是理解起来有点抽象,其实我最开始学到这里的时候,也不明白为什么要用`除法取余运算(%)`来实现。后来我看看了手机上的时钟指针,一圈两圈三圈的转,好像就开始悟了... +> 是不是理解起来有点抽象,其实我最开始学到这里的时候,也不明白为什么要用`除法取余运算(%)`来实现。后来我看看了手机上的时钟指针,一圈两圈三圈的转,好像就开始悟了...其实这种取余操作在计算机知识体系中还是非常常见的,例如:组成原理中将会学到的补码,据说idea就是来源于时钟.. **和时钟一样,顺时钟进行时间变换,在出队、入队时,队首、队尾指针都是按顺时针方向进1** +![](/数据结构/栈和队列/images/循环队列入队.png) +如上图,循环队列从最开始初始化为空队列时:`Q.front==Q.rear==0`,经过元素a入队,队尾指针顺时针前移`Q.rear+1`,到元素a、b、c、d陆续入队,就好像时钟转完了一圈,循环队列已满,此时发现:`Q.front==Q.rear==0`在队满时候依然成立,所以结合前面提到的初始化对空条件:`Q.front==Q.rear==0`,用`Q.front==Q.rear`来区分`队空`和`队满`是非常不合适的。 + + + + +#### 如何区别队空还是队满 + +> 为了很好的区别循环队列的`队空`还是`队满`的情况,一般有三种处理方式. +##### 牺牲一个单元来区分队空和队满 + +这种方式**要求在入队时少用一个队列单元**,是一种比较普遍的做法。约定: + +**队头指针在队尾指针在队尾指针的下一个位置作为队满标志【重要】** + +- 队满条件:`(Q.rear+1)%MaxSize==Q.front` +- 队空条件:`Q.front==Q.rear` +- 队列中元素个数:`(Q.rear+MaxSize-Q.front)%MaxSize` + + +##### 类型中增设表示元素个数的数据成员 + +这种就很直接了,直接和MaxSize去比较,就可以有: + +- 队空条件: `Q.count=0` +- 队满条件: `Q.count=MaxSize` + + +值的注意的是:在这个前提下,不论是`队空`还是`队满`,对会存在`Q.front=Q.rear`,这个可以通过前面方案解决。 + +##### 类型中增设tag数据成员标记 + +通过添加tag标记的方式,区分`队空`还是`队满` + +- `tag==0`的情况下,如果因为删除导致`Q.front==Q.rear`,则队空; +- `tag==1`的情况下,如果因为插入导致`Q.front==Q.rear`,则队满; + +可能你会对上面的这两种情况有迷惑,说实话我第一次看的时候,也挺迷惑的,这里我按照我的理解来解释一下: + +> 在循环队列中增加tag数据成员标记,tag的主要作用: +> - 在有元素入队的时候,设置tag=1 +> - 在有元素出队的时候,设置tag=0 + + +对应的算法实现: +```C++ +// 入队算法 +// 尾插法:Q.data[Q.rear]=x;Q.rear=(Q.rear+1)%Maxsize;Q.tag=1 +// 队空条件:Q.front== Q.rear且Q.tag==0 +int EnLoopQueue(SqQueue &Q, ElemType x){ + if(Q.front==Q.rear&&Q.tag==1){ + return 0; + } + Q.data[Q.rear]=x; + Q.rear=(Q.rear+1)%MaxSize; + Q.tag=1; + return 1; +} + + + +// 出队算法 +// 头结点删除:x=Q.data[Q.front];Q.front=(Q.front +1)%Maxsize;Q.tag=0 +// 队满条件:Q.front == Q.rear且Q.tag=1 +// 注意:当删除之后链表为空时,还需增加一步,将尾指针指向头结点 +int DeLoopQueue(SqQueue &Q, ElemType &x){ + if (Q.front==Q.rear&&Q.tag==0){ + return 0; + } + x=Q.data[Q.front]; + Q.front=(Q.front+1)%MaxSize; + Q.tag=0; + return 1; + } + +``` +##### ### 代码实现 @@ -137,8 +214,15 @@ typedef struct { ```C++ - -void InitQueque(&Q){ +/* + * @Description: 循环队列初始化,队列为空 + * @Version: Beta1.0 + * @Author: 【B站&公众号】Rong姐姐好可爱 + * @Date: 2019-09-27 14:17:28 + * @LastEditors: 【B站&公众号】Rong姐姐好可爱 + * @LastEditTime: 2021-03-18 22:15:06 + */ +void InitLoopQueque(&Q){ Q.front=Q.rear=0; } ``` @@ -146,11 +230,21 @@ void InitQueque(&Q){ #### 队列是否为空 ```C++ - -bool isEmpaty(Q){ +/* + * @Description: 判断循环队列是否为空 + * @Version: Beta1.0 + * @Author: 【B站&公众号】Rong姐姐好可爱 + * @Date: 2019-09-27 14:17:28 + * @LastEditors: 【B站&公众号】Rong姐姐好可爱 + * @LastEditTime: 2021-03-18 22:15:06 + */ +bool isEmpatyLoopQueue(Q){ + // 注意循环队列对空条件:Q.rear=Q.front if(Q.rear=Q.front){ - return false; + // 队空 + return true; }else{ + // 非空 return false; } } @@ -158,12 +252,95 @@ bool isEmpaty(Q){ ``` -#### 入队 +#### 入队操作 ```C++ +/* + * @Description: 循环队列元素入队 + * @Version: Beta1.0 + * @Author: 【B站&公众号】Rong姐姐好可爱 + * @Date: 2019-09-27 14:17:28 + * @LastEditors: 【B站&公众号】Rong姐姐好可爱 + * @LastEditTime: 2021-03-18 22:15:06 + */ +bool EnLoopQueue(SqQueue &Q, ElemType x){ + // 判断循环队列是否已满 注意判断条件:(Q.rear+1)%MaxSize===Q.front + if((Q.rear+1)%MaxSize===Q.front){ + // 循环队列满 + return false; + } + // 队列未满,可进行入队操作【队尾进行】 + + // 队尾指针指向的数据域进行赋值 + Q.data[Q.rear]=x; -bool EnSqQueue(SqQueue) + //队尾指针后移+1【类似时钟的顺时针方向】 + Q.rear=((Q.rear+1)%MaxSize); + + // 入队成功,返回true + return true; +} ``` -#### 出队 \ No newline at end of file +#### 出队操作 + + +```C++ + +/* + * @Description: 循环队列元素出队 + * @Version: Beta1.0 + * @Author: 【B站&公众号】Rong姐姐好可爱 + * @Date: 2019-09-27 14:17:28 + * @LastEditors: 【B站&公众号】Rong姐姐好可爱 + * @LastEditTime: 2021-03-18 20:32:18 + */ +bool DeLoopQueue(SqQueue &Q, ElemType &x){ + + // 判断循环队列是否为空队列 + if(Q.rear==Q.front){ + + // 队列为空,无法进行出队操作,返回false + return false; + } + + // 循环队列非空,元素可出队【队首操作】 + + // 将循环队列队首指针指向的元素的数据域赋值给变量x + x=Q.data[Q.front]; + + // 移动队首指针,顺时针后移+1 + Q.front=(Q.front+1)%MaxSize; + + // 出队成功,返回true + return true; +} + +``` + +#### 获取队头元素 + +```C++ +/* + * @Description: 获取循环队列队头元素 + * @Version: Beta1.0 + * @Author: 【B站&公众号】Rong姐姐好可爱 + * @Date: 2019-09-27 14:17:28 + * @LastEditors: 【B站&公众号】Rong姐姐好可爱 + * @LastEditTime: 2021-03-18 20:15:33 + */ +bool GetLoopQueueHead(SqQueue &Q, ElemType &x){ + // 判断循环队列是否为空队列 + if(Q.front==Q.rear){ + // 队列为空,没有队头元素,返回false + return false; + }else{ + // 获取队头指针指向元素的数据域,赋值给x + x=Q.data[Q.front]; + + // 获取队头元素成功,返回true + return true; + } +} +``` \ No newline at end of file diff --git a/数据结构/栈和队列/images/循环队列入队.png b/数据结构/栈和队列/images/循环队列入队.png new file mode 100644 index 0000000..f6790ba Binary files /dev/null and b/数据结构/栈和队列/images/循环队列入队.png differ