【数据结构】栈与队列的实际应用——球钟问题
球钟:
球钟为一种计时工具,其主要原理为通过小球的移动来进行实践的记录。它有三个能容纳若干球的指示器:小时指示器、五分钟指示器、分钟指示器。如果小时、五分钟、分钟指示器内存在小球分别为:5、4、1,那么其所表示的时间则为05:21。
当分钟指示器内小球达到5个时,进位到五分钟指示器,即清空分钟指示器内小球,五分钟指示器内小球加一;五分钟进位同理。在球钟问题内,球钟最多能够表示时间为11:59,再多一分钟为12:00时将自动清零。
球钟问题描述:
问题中,使用堆栈结构来表示三种指示器,使用队列结构作为小球的存储容器。初始状态下,三种指示器内小球数均为0,小球存储队列由队首到队尾存放编号为0~26的小球。(按照进位原则,分钟指示器最多存放4个小球,五分钟指示器和小时指示器最多存放11个小球,还有一个小球用于最后的进位)
问:最少经过多少分钟后,小球存储队列中的标号与初始状态相同
代码:
"linkqueue.h"和"sqstack.h"头文件分别为链式队列与顺序栈的程序头文件,具体相关内容在其他随笔内有。
#include <stdio.h> #include "linkqueue.h" #include "sqstack.h" #define N 27 int check(linkqueue *lq); //检查是否小球队列内编号顺序为0~26 int main() { linkqueue *lq; int i; sqstack *s_hour,*s_five,*s_min; int min = 0; int value; //squeue init if((lq=queue_create()) == NULL){ printf("lq is NULL\n"); return -1; } for(i=0;i<N;i++){ enqueue(lq,i); } //stack init if((s_hour=stack_create(11)) == NULL) return -1; if((s_five=stack_create(11)) == NULL) return -1; if((s_min=stack_create(4)) == NULL) return -1; while(1){ min++; if(!queue_empty(lq)){ //判断队列不为空 value = dequeue(lq); //出队一个元素 //s_min++ 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); //最后一个小球进位,放回小球存储队列 //00:00 check if(check(lq)) break; //检查是否编号与初始状态相同(只有00:00时,队列中才存在27个小球,才可能与初始相同) } } } } } //printf printf("min=%dmin\n",min); printf("hour=%dh\n",min/60); printf("lq is "); while(!queue_empty(lq)){ printf("%d ",dequeue(lq)); } puts(""); return 0; } int check(linkqueue *lq){ linklist p; if(lq == NULL){ printf("lq is NULL"); return -1; } p = lq->front->next; while(p && p->next){ if(p->data < p->next->data) p = p->next; else return 0; } return 1; }
最终运行计算结果为:
即:最少经过552小时,小球存储队列内的编号与初始状态相同为0~26