1
0
mirror of https://github.com/142vip/408CSFamily.git synced 2026-04-14 18:30:30 +08:00

loopQueue ending

This commit is contained in:
mmdapl
2021-03-18 23:57:33 +08:00
parent 7506969bd5
commit 11cb7445b6
4 changed files with 243 additions and 10 deletions

View File

@@ -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;
}

Binary file not shown.

View File

@@ -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;
}
```
#### 出队
#### 出队操作
```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;
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB