环形队列
所为环形即队尾存入到一定位置后,跳回前面的位置,
对头放出一定数据后也跳回到前面的位置
实现方法很容易,对规定的队列最大长度取余数即可,
麻烦点是区分当 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 | ||||
---|---|---|---|---|
0 | 1 | 2 | 3 | 4 |
出队4个
tail | head | |||
---|---|---|---|---|
*0 | *1 | *2 | *3 | 4 |
入队5,6
tail | head | |||
---|---|---|---|---|
5 | 6 | *2 | *3 | 4 |
打印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
禁止出队
想法很简单
- 入满队
- 再入队一个,测试是否发出警告,并禁止入队
- 出队到空
- 再出队一个,测试是否警告,并禁止出队
#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
head | tail | |||
---|---|---|---|---|
0 | 1 | 2 | 3 | *-1 |
或者
tail | head | |||
---|---|---|---|---|
3 | *-1 | 0 | 1 | 2 |
下一步如果再入队一个 full_mark = 0
检测full_mark
,禁止再入队
此时 tail == head
head-tail | ||||
---|---|---|---|---|
0 | 1 | 2 | 3 | 4 |
就相当于在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]