一、栈和队列的应用之球鈡问题原理
球钟问题
球钟问题是一个通过球的移动来记录时间的装置问题,其原理与栈和队列的操作特性密切相关。
问题描述
它有三个可以容纳若干个球的指示器:分钟指示器,五分钟指示器,小时指示器。
若分钟指示器中有2个球,五分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32。
工作原理
每过一分钟,球钟就会从球队列的队首取出一个球放入分钟指示器,分钟指示器最多可容纳4个球。
当放入第五个球时,在分钟指示器的4个球就会按照他们被放入时的相反顺序加入球队列的队尾。而第五个球就会进入五分钟指示器。
按此类推,五分钟指示器最多可放11个球,小时指示器最多可放11个球。
当小时指示器放入第12个球时,原来的11个球按照他们被放入时的相反顺序加入球队列的队尾,然后第12个球也回到队尾。这时,三个指示器均为空,回到初始状态,从而形成一个循环。因此,该球钟表示时间的范围是从0:00到11:59。
现设初始时球队列的球数为27,球钟的三个指示器初态均为空。问,要经过多久,球队列才能回复到原来的顺序?
二、栈和队列的应用之球鈡问题实现
代码下载链接:git clone https://gitee.com/flying-wolf-loves-learning/data-structure.git
#include <stdio.h>
#include "linkqueue.h" // 包含队列的头文件
#include "sqstack.h" // 包含栈的头文件
int check(linkqueue * lq); // 声明函数check,用于检查队列是否按顺序排列
int main(int argc, const char *argv[])
{
linkqueue *lq; // 定义指向队列的指针
sqstack *s_hour, *s_five, *s_min; // 定义小时、五分钟和分钟的栈
int value;
int i, min = 0;
if((lq = queue_create()) == NULL){ // 创建队列,若失败则返回-1
return -1;
}
for(i = 1; i <= 27; i++){ // 初始化队列,模拟时钟的27个时间点
enqueue(lq, i);
}
if((s_hour = stack_create(11)) == NULL){ // 创建大小为11的小时栈
return -1;
}
if((s_five = stack_create(11)) == NULL){ // 创建大小为11的五分钟栈
return -1;
}
if((s_min = stack_create(4)) == NULL){ // 创建大小为4的分钟栈
return -1;
}
while (1){ // 模拟时钟运行,每循环一次表示时间增加一分钟
min++;
if(!queue_empty(lq)){ // 如果队列不为空
value = dequeue(lq); // 从队列中取出一个时间点
if(!stack_full(s_min)){ // 如果分钟栈未满
stack_push(s_min, value); // 将取出的时间点放入分钟栈
}
else{
while(!stack_empty(s_min)){ // 当分钟栈不为空时
enqueue(lq, stack_pop(s_min)); // 将分钟栈中的时间点重新放入队列
}
if(!stack_full(s_five)){ // 如果五分钟栈未满
stack_push(s_five, value); // 将取出的时间点放入五分钟栈
}
else{
while(!stack_empty(s_five)){ // 当五分钟栈不为空时
enqueue(lq, stack_pop(s_five)); // 将五分钟栈中的时间点重新放入队列
}
if(!stack_full(s_hour)){ // 如果小时栈未满
stack_push(s_hour, value); // 将取出的时间点放入小时栈
}
else {
while(!stack_empty(s_hour)){ // 当小时栈不为空时
enqueue(lq, stack_pop(s_hour)); // 将小时栈中的时间点重新放入队列
}
enqueue(lq, value); // 将取出的时间点放入队列
//0:0
if(check(lq) == 1){ // 检查队列中的时间点是否按顺序排列
break; // 若按顺序排列,表示模拟时钟已经转动了一轮,退出循环
}
}
}
}
}
}
printf("total:%d\n", min); // 输出模拟时钟转动的总分钟数
printf("dequeue:"); // 输出队列中的所有时间点
while(!queue_empty(lq))
printf("%d ", dequeue(lq));
puts("");
return 0;
}
int check(linkqueue * lq){
linklist p;
if(lq == NULL){
printf("lq is NULL\n");
return -1;
}
p = lq->front->next;
while(p && p->next){
if(p->data < p->next->data){ // 若队列中的时间点按顺序排列,则返回1
p = p->next;
}
else{
return 0; // 若不按顺序排列,则返回0
}
}
return 1;
}