自制简易循环队列

循环队列的搭建

队列的定义

  • 一种可以实现"先进先出"的存储结构
  • 类似排队过程

队列的分类

  • 链式队列
  • 静态队列

理解循环队列需要回答7个问题

  1. 静态队列为什么必须是循环队列?
  2. 循环队列需要几个参数来确定?
  3. 循环队列各个参数的含义?
  4. 循环队列 入队 算法
  5. 循环队列 出队 算法
  6. 如何判断循环队列是否为空?
  7. 如何判断循环队列是否已满?

循环队列的实现

循环队列个人理解

  • 在这里插入图片描述
  1. 上图很好的展示了循环队列的基本结构,可以看到循环队列空间是有限的,就像排队的时候也不能把队伍无限排吧?
  2. 由于需要"先进先出",所以需要一个地方进,一个地方出,所以需要两个参数来表示循环队列
  3. 而循环的含义是:所有的入队、出队都在同一个数组中实现,设计一个轮回,让出入的指针都围着数组转圈,需要模运算来实现

实现过程

1. 定义循环队列结构

\\ 需要两个参数front(前), rear(后)来表示循环队列,而 *pBase 用来创建所需的数组空间,采用pBase[front]/pBase[rear] 的方式来访问元素,
其中front指向“最前面的元素”,rear指向“最尾部元素的后面一个值(方便操作)”,
typedef struct Queue{
	int *pBase;
	int front;
	int rear;
}QUEUE, * PQUEUE;

\\ len 保存数组长度
const int len = 6;

int main(void)
{
	PQUEUE q;
	return 0;
}

2. 初始化循环队列

void init(PQUEUE pQ);

int main(void)
{
	PQUEUE q;
	init(q);
	
	return 0;
}

void init(PQUEUE pQ)
{
	\\申请数组空间
	pQ->pBase = (int *)malloc(sizeof(int) * len);
	\\初始时,两个参数都指向数组第一个值即0
	pQ->front = 0;
	pQ->rear = 0;
	return;
}

3. 入队算法

  • 由于循环队列是静态队列,无法增长空间,在入队之前需要判断数组是否已满,满了就无法入队啦,那么该如何判断循环队列满了呢?
    通常会采用牺牲一个数组元素的方式来判断,利用模运算,如下图,f指向第一个元素,r指向最后一个元素的后一个元素,当r走到第5个元素的时候时,循环队列里有 {0-4} 5个元素,牺牲掉r所在的那个元素,如果不牺牲这个元素的话,让 r 无休止往后走的话,那一切都乱了,当 r 走到 f “前面”,根本无法判断哪些元素是循环队列里面的,所以关键就是令 r 无法"超过" f
  • 实现方法就是当 (r+1)% 6 == f 时,判断循环队列已满
  • 在这里插入图片描述
bool full(PQUEUE pQ);
bool en_queue(PQUEUE pQ, int val);

int main(void)
{
	PQUEUE q;
	init(q);
	en_queue(q,1);
	
	return 0;
}

bool full(PQUEUE pQ)
{
	\\如上所述的判断满算法
	if ( (pQ->rear+1)%len == pQ->front )
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool en_queue(PQUEUE pQ, int val)
{
	if ( full(pQ) )
	{
		return false;
	}
	else
	{
		\\将入队元素放入 rear 的位置
		pQ->pBase[pQ->rear] = val;
		\\将 rear “向前移” ,模运算实现
		pQ->rear = (pQ->rear+1)%len;
		return true;
	}
}

4. 出队算法

  • 出队算法较简单,先判断循环队列是否为空,不为空的话之间将 front “向前移” 即可,利用模运算实现
bool empty(PQUEUE pQ);
bool out_queue(PQUEUE pQ, int * pVal);

int main(void)
{
	PQUEUE q;
	int val;
	init(q);
	en_queue(q,1);

	out_queue(q,&val);
	
	return 0;
}

bool empty(PQUEUE pQ)
{
	if ( pQ->front == pQ->rear )
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool out_queue(PQUEUE pQ, int * pVal)
{
	if ( empty(pQ) )
	{
		return false;
	}
	else
	{
		\\将 front 处保存的值传给 pVal 将其保存
		*pVal = pQ->pBase[pQ->front];
		\\将 front "向前移"
		pQ->front = (pQ->front+1)%len;
		return true;
	}
}

5. 遍历算法、清队算法

  • 实现起来比较简单,直接贴代码
void traverse(PQUEUE pQ);
void clear(PQUEUE pQ); 

int main(void)
{
	PQUEUE q;
	int val;
	init(q);
	en_queue(q,1);
	en_queue(q,2);
	en_queue(q,3);
	en_queue(q,4);
	en_queue(q,5);
	traverse(q);
	if ( out_queue(q,&val) )
	{
		printf("出队成功!出队元素是 %d \n", val);
	}
	else
	{
		printf("队列为空!出队失败!\n");
	}
	traverse(q);
	clear(q);
	if ( out_queue(q,&val) )
	{
		printf("出队成功!出队元素是 %d \n", val);
	}
	else
	{
		printf("队列为空!出队失败!\n");
	}
	
	return 0;
}

void traverse(PQUEUE pQ)
{
	int p = pQ->front;
	
	while ( p!=pQ->rear )
	{
		printf("%d ", pQ->pBase[p]);
		p = (p+1)%len;
	}
	printf("\n");
}

void clear(PQUEUE pQ)
{
	pQ->front = 0;
	pQ->rear = 0;
	return;
}

总结

循环队列最关键需要理解为何需要循环,算法都很简单,但是需要注意判断满的算法为什么要这样写?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值