静态队列实现

Posted 軒邈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态队列实现相关的知识,希望对你有一定的参考价值。

/*
	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
*/

理解:

循环队列的原因





循环队列入队伪算法

循环队列出队伪算法

如何判断队列已满


原创:参考 郝斌老师系列课程

以上是关于静态队列实现的主要内容,如果未能解决你的问题,请参考以下文章

静态队列实现

郝斌数据结构教学视频下载地址

循环队列的实现及细节

[数据结构]手动实现队列

如何看懂一个程序(郝斌老师)

如何看懂一个程序(郝斌老师)