eg_12_5

文章介绍了环形队列的基本概念和实现方式,包括使用取模运算实现队尾入队和队头出队,以及如何通过数量标记法和特殊标签来判断队列是否满或空,并展示了相关代码示例。在满队列时尝试入队和空队列时尝试出队会触发警告并禁止操作。
摘要由CSDN通过智能技术生成

环形队列

所为环形即队尾存入到一定位置后,跳回前面的位置,
对头放出一定数据后也跳回到前面的位置

实现方法很容易,对规定的队列最大长度取余数即可,
麻烦点是区分当 tail == head 时 当前是空,还是满,
这个问题就建立一个前置或者后置处理这个问题,试一试能写多少个方法

基础环形队列实现

队尾入队tail++ ,队头出队 head++
环形队列实现用取余数方法

#include <stdio.h>
#define MAX_LEN 5

int tail = 0, head = 0;
int queue[MAX_LEN] = {-1, -1, -1, -1, -1};

void enqueue(int p) { queue[tail++ % MAX_LEN] = p; }

int dequeue(void) { return queue[head++ % MAX_LEN]; }

int main() {
  for (int i = 0; i < MAX_LEN; i++)
    enqueue(i);

  dequeue();
  dequeue();
  dequeue();
  dequeue();
  enqueue(5);
  enqueue(6);

  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", queue[i]);
	printf("\n");

	printf("%d\t",dequeue());
	printf("%d\t",dequeue());

  return 0;
}

定义一个循环队列,内存连续,全部值初始化为-1
再过程中为了方便可视化,将已被出队的元素加*表示

tail-head
-1-1-1-1-1

入队 0,1,2,3,4 满队列

tail-head
01234

出队4个

tailhead
*0*1*2*34

入队5,6

tailhead
56*2*34

打印3个出队元素, 空队列

head-tail
*5*6*2*3*4

最后打印按序打印队列元素,并再打印两个出队元素

5       6       2       3       4
4       5       6

环形队列的初步实现已经成功了

区分队列已满或者队列已空

满队后禁止入队,如有入队发出警报
空队后禁止出对,如有出队发出警报

最简单的方法,数量标记法

顾名思义,用一个数量标记 number_mark 即可
每入队一个number_mark++
每出队一个 number_mark--
if number_mark == MAX_LEN 禁止入队
if number_mark == 0 禁止出队


想法很简单

  1. 入满队
  2. 再入队一个,测试是否发出警告,并禁止入队
  3. 出队到空
  4. 再出队一个,测试是否警告,并禁止出队
#include <stdio.h>
#define MAX_LEN 5

int tail = 0, head = 0;
int queue_len = 0;
int queue[MAX_LEN] = {-1, -1, -1, -1, -1};

void enqueue(int p) {
  if (queue_len == MAX_LEN) {
    printf("full of queue, cannot enqueue!\n");
    return;
  }
  queue_len++;
  queue[tail++ % MAX_LEN] = p;
}

/*
 * dequeue must return a value
 * while it is empty just return the last value again
 */
int dequeue(void) {
  if (queue_len == 0) {
    printf("empty queue, cannot dequeue!\n");
    return queue[head];
  }
  queue_len--;
  return queue[head++ % MAX_LEN];
}

int main() {

	printf("enqueue till the queue is full\n");
	for (int i = 0; i < MAX_LEN; i++)
    enqueue(i);

  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", queue[i]);
  printf("\n");
	
	printf("try to enqueue while the queue is full\n");
  enqueue(5);

  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", queue[i]);
  printf("\n");

	printf("dequeue till the queue is empty\n");
  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", dequeue());
  printf("\n");

	printf("dequeue while the queue is empty\n");
  printf("%d\t", dequeue());

  return 0;
}

结果

enqueue till the queue is full
0       1       2       3       4
try to enqueue while the queue is full
full of queue, cannot enqueue!
0       1       2       3       4
dequeue till the queue is empty
0       1       2       3       4
dequeue while the queue is empty
empty queue, cannot dequeue!
0

该方法成功

复杂的办法,再即将满前或空前,设置特殊label

如果 tail 主动右移到 head 出,满队列
如果 head 主动右移到 tail 处,空队列

对于满队检测
设置一个full_mark
一般情况下设置为-1,
当tail 在head 的右侧一个位置时,设置为0,
再次入队,full_mark += 1
触发警告,禁止再次入队
另外一点
如果满队,那么一定不是空队
满队时,empty_mark = -2

满队检测和空队检测时完全镜像的,写好一个就会有第二个

千言万语比不上一个图

这里用图标显示一下 full_mark 个人思路

初始情况下队列全空 置 full_mark = -2

head/tail
-1-1-1-1-1

只有在 差一步满队列的情况下置 full_mark = -1

headtail
0123*-1

或者

tailhead
3*-1012

下一步如果再入队一个 full_mark = 0
检测full_mark,禁止再入队
此时 tail == head

head-tail
01234

就相当于在full_mark 加上一个记忆保留的功能
需要 full_mark = full_mark
而为了让 full_mark == -1 情况下再enqueue 一个
就使得 full_mark == 0 很容易联想到 ++ 方法

贴上代码

#include <stdio.h>
#define MAX_LEN 5

int tail = 0, head = 0;
int full_mark = -2, empty_mark = -2;
int queue[MAX_LEN] = {-1, -1, -1, -1, -1};

void enqueue(int p) {
  if (full_mark >= 0) {
    printf("full of queue, cannot enqueue!\n");
    full_mark = 0;
    empty_mark = -2;
    return; // can not enqueue
  }

  if (head - tail == 1 || tail - head == MAX_LEN - 1)
    full_mark = -1;
  else if (head == tail)
    full_mark = full_mark;
  else
    full_mark = -2;
  full_mark++;
  queue[tail] = p;
  tail = (tail + 1) % MAX_LEN;
}

/*
 * dequeue must return a value
 * while it is empty just return the last value again
 */
int dequeue(void) {
  int tmp;

  if (empty_mark >= 0) {
    printf("empty queue, cannot dequeue!\n");
    empty_mark = 0;
    full_mark = -2;
    return queue[head];
  }
  if (tail - head == 1 || head - tail == MAX_LEN - 1)
    empty_mark = -1;
  else if (tail == head)
    empty_mark = empty_mark;
  else
    empty_mark = -2;
  empty_mark++;
  tmp = head;
  head = (head + 1) % MAX_LEN;
  return queue[tmp];
}

int main() {

  printf("enqueue till the queue is full\n");
  for (int i = 0; i < MAX_LEN; i++)
    enqueue(i);

  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", queue[i]);
  printf("\n");

  printf("try to enqueue while the queue is full\n");
  enqueue(5);

  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", queue[i]);
  printf("\n");

  printf("dequeue till the queue is empty\n");
  for (int i = 0; i < MAX_LEN; i++)
    printf("%d\t", dequeue());
  printf("\n");

  printf("dequeue while the queue is empty\n");
  printf("%d\t", dequeue());

  return 0;
}
enqueue till the queue is full
0       1       2       3       4
try to enqueue while the queue is full
full of queue, cannot enqueue!
0       1       2       3       4
dequeue till the queue is empty
0       1       2       3       4
dequeue while the queue is empty
empty queue, cannot dequeue!
0
[Process exited 0]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值