学到数据结构时,遇到一个题目:球钟
问题描述:球钟是利用球的移动来记录时间的装置(吐槽:这么麻烦,球会准时放进去?)。它有三个可以容纳若干个球的容器:分钟指示器,五分钟指示器,小时指示器。若分钟指示器中有2个球,5分钟指示器中有3个球,小时指示器中有4个球,则时间为4:17。每过一分钟,球钟就会从球队列的队首取出一个球放入分钟指示器,分钟指示器最多可容纳4个球。在放进去第五个球的时候,分钟指示器内的4个球就会按照他们被放入时的相反顺序加入球队列的队尾。而第五个球就会进入五分钟指示器。按此类推,五分钟指示器最多可放11个球,小时指示器最多可放11个球。因此,该球种表示的时间范围是从00:00到11:59
1、要想表示00:00到12:00最少需要多少个球?
2、假设,指示器都为空,球队列需要多长时间能回到原来的状态?
即从初始球队列中球的顺序,经过球的循环后球队列中的球再次与初始顺序相同。
对于第一个问题,
想象一下,在11:59的时候,分钟指示器里面有4个球,五分钟指示器有11个球,小时指示器有11个球,则这时三个指示器都为临界状态,共用去26个球,而球钟要求能表示12:00,即可理解为00:00,就是要求能从11:59回到00:00,则还需一个球去触发这个临界状态,类似于多米洛骨牌,这个球依次进入三个指示器,并触发其临界状态,三个指示器里的球依次回到队列,然后最后一个球也回到队列,则最少需要27个球。
第二个问题:
这时,要理解,回到原来的状态,并不仅仅是27个球都回到队列就完事了!!而且27个球的顺序要和原来一摸一样。
对于这个问题,没得说,敲出来算一下。
那么,既然是数据结构的问题,这题肯定是用数据结构的知识去解答,题中的队列很好理解,队首出队尾进嘛,已经明说了用队列去表示,而三个指示器要求按他们的球放入的相反顺序取出,换句话说,就是后进的先出,先进的后出,就是用三个栈去表示三个指示器。
队列的话这里可以用链式队列、顺序循环队列,不能用单纯的顺序队列,不然就假溢出了。这里我用的顺序循环队列,代码上稍微省事一点。然后用了三个链式栈。代码如下
头文件:qiuzhong.h
#ifndef _QIUZHONG_
#define _QIUZHONG_
#define minite 4
#define five_minite 11
#define hour 11
#define num 28
typedef struct st_node
{
int data;
struct st_node *next;
}node,*node_p;
typedef struct st_stack
{
int n;
node_p top;
}stack,*stackp;
typedef struct queue_st
{
int a[num];
int front;
int rear;
}queue;
extern queue *createqueue();
extern int queueempty(queue *s);
extern int queuefull(queue *s);
extern int queue_in(queue *s,int data);
extern int queue_out(queue *s);
extern stackp creatstack();
extern int empty_stack(stackp s);
extern int stack_in(stackp s,int data);
extern int stack_out(stackp s);
extern int show_queue(queue *s);
extern int clear_stack(stackp s,queue *q);
extern int queue_traverl(queue *s,int flag);
#endif
操作函数qiuzhong.c
#include <stdio.h>
#include "qiuzhong.h"
#include "stdlib.h"
queue *createqueue()
{
queue *s=NULL;
s=(queue *)malloc(sizeof(queue));
if(s==NULL)
{
printf("malloc error!\n");
return NULL;
}
s->front=0;
s->rear=0;
return s;
}
int queueempty(queue *s)
{
return s->front==s->rear?1:0;
}
int queuefull(queue *s)
{
return (s->rear+1)%num==s->front?1:0;
}
int queue_in(queue *s,int data)
{
if(queuefull(s))
{
printf("the queue is full!\n");
return -1;
}
s->a[s->rear]=data;
s->rear=(s->rear+1)%num;
}
int queue_out(queue *s)
{
int ret=0;
if(queueempty(s))
{
printf("the queue is empty!\n");
return -1;
}
ret=s->a[s->front];
s->front=(s->front+1)%num;
return ret;
}
int show_queue(queue *s)
{
int i=s->front;
for(;i!=s->rear;i=(i+1)%num)
{
printf("%d ",s->a[i]);
}
printf("\n");
}
int queue_traverl(queue *s,int flag)
{
int i=0;
int j=s->front;
for(i=1;i<28;i++)
{
if(s->a[j]==i)
j=(j+1)%num;
else
break;
}
if(i==28)
{
printf("顺序回原:");
show_queue(s);
printf("经过%d分钟队列完全回原\n",flag);
}
}
/*---------------------------------------------*/
stackp creatstack()
{
stackp s=NULL;
s=(stackp)malloc(sizeof(stack));
if(s==NULL)
{
printf("malloc error1\n");
return NULL;
}
s->top=NULL;
s->n=0;
return s;
}
int empty_stack(stackp s)
{
return s->top==NULL?1:0;
}
int stack_in(stackp s,int data)
{
node_p p=NULL;
p=(node_p)malloc(sizeof(node));
if(p==NULL)
{
printf("malloc error!\n");
return -1;
}
p->next=s->top;
s->top=p;
p->data=data;
s->n++;
}
int stack_out(stackp s)
{
if(empty_stack(s))
{
printf("the stack is empty!\n");
return -1;
}
node_p p=NULL;
int ret=0;
p=s->top;
ret=p->data;
s->top=s->top->next;
free(p);
s->n--;
return ret;
}
int clear_stack(stackp s,queue *q)
{
int a;
int i=s->n;
for(;i>0;i--)
{
a=stack_out(s);
queue_in(q,a);
}
}
主函数main.c
#include <stdio.h>
#include "qiuzhong.h"
int main()
{
int qd=0;
int md=0,fd=0,hd=0;
int xunhuan=0;
int flag=0;
queue *s=createqueue();
for(qd=0;qd<27;qd++)
{
queue_in(s,qd+1);
}
stackp m=creatstack();
stackp f=creatstack();
stackp h=creatstack();
printf("Please input your data:");
scanf("%d",&xunhuan);
/*输入数据,开始循环*/
while(xunhuan--) //进行判断,时分秒循环
{
qd=queue_out(s);
if(m->n<4)
stack_in(m,qd);
else
{
if(f->n<11)
{
clear_stack(m,s);
stack_in(f,qd);
}
else
{
if(h->n<11)
{
clear_stack(m,s);
clear_stack(f,s);
stack_in(h,qd);
}
else
{
clear_stack(m,s);
clear_stack(f,s);
clear_stack(h,s);
queue_in(s,qd);
}
}
}
flag++;
queue_traverl(s,flag);
}
/*-----------------时间换算显示-----------*/
printf("the time is:%d:%d\n",h->n,f->n*5+m->n);
}
运行效果如图:
这里输入40000,让程序循环40000分钟,则经过33120分钟的时候队列完全回原,且第40000分钟的时间是6:40