/*
2022.05.14
目的:
理解简单的队列相关知识
功能:
静态队列,利用数组完成出队、入队
理论:
1.线性结构的队列,实现“先进先出”的存储结构;
2.分类-链式队列(链表实现)和静态队列(数组实现),链式队列相较于静态队列简单些;
3.链式队列-front 指向第一个元素,rear 永远指向最后一个元素的下一个元素,与栈区分开来;
4.静态队列-数组实现,是在数组原有的一些功能上进行增减;
5.静态队列通常都必须是循环队列;
6.弄清楚循环队列需要弄清以下问题:
a.静态队列为什么必须是循环队列?
因为静态队列是用数组实现的,那么由于数组的局限性,所以在使用的过程中,由于指针的移动,存在对数组空间的浪费;
b.循环队列至少需要几个参数实现?
-front 与 rear 2个参数来确定
c.循环队列各个参数的含义?
-两个参数在不同的场景有不同的含义
-建议初学者先记住,然后慢慢体会
(1).队列初始化
front 与 rear 的值都是零
(2).队列非空
front 代表的队列的第一个元素
rear 代表的队列的最后一个有效元素的后一个元素
(3).队列空
front 与 rear 相等,但是不一定是零
d.循环队列入队伪算法讲解?
入队伪算法演示:
1.将值存入“rear”所代表的位置;
2.rear = rear + 1; //错误写法,当rear = 5时,加1越界; rear = (rear + 1)%数组的长度 //正确写法;
e.循环队列出队伪算法讲解?
出队伪算法演示:
1.保存出队的值;
2.front = (front + 1)%数组的长度;
f.如何判断循环队列是否为空?
front 与 rear 相等,队列为空
g.如何判断循环队列是否已满?
预备知识:
front的值可能比rear大,
front的值可能比rear小,
当然也可能相等
两种方式:
1.多增加一个标识参数;
2.少用一个元素,比如队列一共只能存储n个元素,那么现再存储到n-1个就不存储了。
如果rear与front的值紧挨着,则队列已满,实现的伪代码如下:
if((rear+1)%数组长度 == front)
已满
else
不满
*/
#include <stdio.h>
#include <malloc.h>
typedef struct Queue /* 定义一个新的数据类型 */
{
int* pBase;
int iFront;
int iRear;
}QUEUE;
void InitQueue(QUEUE *pQPara); /* 初始化队列 */
bool EnQueue(QUEUE *pQPara, int val); /* 在某个队列入队 */
void Traverse(QUEUE *pQPara); /* 对队列进行遍历 */
bool FullQueue(QUEUE *pQPara); /* 判断队列是否为空 */
bool DeQueue(QUEUE* pQPara,int* pDeQueueVal); /* 在某个队列进行出队 */
bool EmptyQueue(QUEUE* pQueue); /* 判断队列是否为空 */
int main(void)
{
QUEUE Q; /* 只是定义了一个QUEUE数据类型的变量,并没有对这个变量进行初始化 */
int iTampVal; /* 存储出队值的变量 */
InitQueue(&Q);
EnQueue(&Q,1);
EnQueue(&Q,2);
EnQueue(&Q,3);
EnQueue(&Q,4);
EnQueue(&Q,5);
Traverse(&Q);
if (DeQueue(&Q, &iTampVal))
{
printf("出队成功,出队元素为:%d\n", iTampVal);
}
else
{
printf("出队失败\n");
}
Traverse(&Q);
if (DeQueue(&Q, &iTampVal))
{
printf("出队成功,出队元素为:%d\n", iTampVal);
}
else
{
printf("出队失败\n");
}
Traverse(&Q);
return 0;
}
void InitQueue(QUEUE *pQPara) /* 因为你在初始化的过程中需要改变结构体变量中的值,所以传进来的是结构体变量的地址 */
{
pQPara->pBase = (int* )malloc(sizeof(int)*6); /* 申请一个含有6个整型空间的数组,并且数组的首地址返回给 pBase */
pQPara->iFront = 0; /* 赋值第一个元素的下标 */
pQPara->iRear = 0; /* 同上 */
return;
}
bool FullQueue(QUEUE* pQPara) /* 判断队列是否满 */
{
if ((pQPara->iRear + 1)%6 == pQPara->iFront) /* 判断为满的算法 */
{
return true;
}
else
{
return false;
}
}
bool EnQueue(QUEUE *pQPara, int val) /* 入队操作 */
{
if (FullQueue(pQPara)) /* 如果队列已满 */
{
return false; /* 返回错误 */
}
else
{
pQPara->pBase[pQPara->iRear] = val; /* 入队将值放在 pQPara->iRear*/
pQPara->iRear = (pQPara->iRear + 1)%6; /* 移动到下一个位置,但是由于是循环的所以利用取余的操作解决这一问题 */
return true; /* 返回正确 */
}
}
bool EmptyQueue(QUEUE* pQueue) /* 判断队列是否为空 */
{
if (pQueue->iFront == pQueue->iRear) /* 如果队尾元素下表和队首元素下标相等 */
{
return true;
}
else
{
return false;
}
}
bool DeQueue(QUEUE* pQPara, int* iDeQueueVal) /* 出队操作 */
{
if (EmptyQueue(pQPara)) /* 判断为空则没有元素可以出队 */
{
return false;
}
else
{
*iDeQueueVal = pQPara->pBase[pQPara->iFront]; /* 要出队的值保存下来 */
pQPara->iFront = (pQPara->iFront + 1) % 6; /* 移动到下一个位置,但是由于是循环的所以利用取余的操作解决这一问题 */
return true;
}
}
void Traverse(QUEUE* pQPara) /* 对队列进行遍历 */
{
int iTampVal = pQPara->iFront; /* 将第一个元素的序号赋值给iTampVal */
while (iTampVal != pQPara->iRear) /* 当这两个序号不相等的时候,说明还没有遍历完成 */
{
printf("%d ", pQPara->pBase[iTampVal]);
iTampVal = (iTampVal + 1) % 6; /* 移动到下一个位置,但是由于是循环的所以利用取余的操作解决这一问题 */
}
printf("\n");
}
/*
程序运行结果:
1 2 3 4 5
出队成功,出队元素为:1
2 3 4 5
出队成功,出队元素为:2
3 4 5
*/
理解:
循环队列的原因
循环队列入队伪算法
循环队列出队伪算法
如何判断队列已满