在数据结构的栈和队列的学习过程中,除了需要了解栈、队列的基本特点外,需要掌握包括创建、出栈入栈、出队入队等基本操作。并熟悉一些常见的应用问题,比如球钟问题就是一个典型利用栈和队列实现的实际问题。本文描述球钟问题的具体实现过程。
球钟问题描述问题描述:球钟是一个利用球的移动来记录时间的简单装置。它有三个可以容纳若干个球的指示器:分钟指示器,五分钟指示器,小时指示器。若分钟指示器中有2个球,五分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32。
工作原理:每过一分钟,球钟就会从球队列的队首取出一个球放入分钟指示器,分钟指示器最多可容纳4个球。当放入第五个球时,在分钟指示器的4个球就会按照他们被放入时的相反顺序加入球队列的队尾。而第五个球就会进入五分钟指示器。按此类推,五分钟指示器最多可放11个球,小时指示器最多可放11个球。当小时指示器放入第12个球时,原来的11个球按照他们被放入时的相反顺序加入球队列的队尾,然后第12个球也回到队尾。这时,三个指示器均为空,回到初始状态,从而形成一个循环。因此,该球钟表示时间的范围是从0:00到11:59。
现设初始时球队列的球数为27,球钟的三个指示器初态均为空。问,要经过多久,球队列才能回复到原来的顺序。
球钟问题程序流程图如下,S1、S5、S60分别为1分钟、5分钟、60分钟栈,队列出队成员赋值给x。
#ifndef __DATA__H #define __DATA__H #include <stdio.h> #include <stdlib.h> #include <string.h> typedef int DataType; //定义结点类型 struct node { DataType data; struct node *next; }; #endif
#ifndef __LINKQUEUE__H
#define __LINKQUEUE__H
#include "data.h"
//#include <stdio.h>/*{{{*/
//#include <stdlib.h>
//#include <string.h>
//
//typedef int DataType;
结点类型
//struct node
//{
// DataType data;
// struct node *next;
//};/*}}}*/
队列头/*{{{*/
//typedef struct
//{
// //front指向链表头
// struct node *front;
// //rear指向链表尾
// struct node *rear;
//}LinkQueue;
//
//extern LinkQueue *creat_linkqueue();
//extern int is_empty_linkqueue(LinkQueue *q);
//extern int enter_linkqueue(LinkQueue *q,DataType data);
//extern DataType delete_linkqueue(LinkQueue *q);
///*}}}*/
//队列头
typedef struct
{
//front指向链表头
struct node *front;
//rear指向链表尾
struct node *rear;
}LinkQueue;
extern LinkQueue *creat_linkqueue();
extern int is_empty_linkqueue(LinkQueue *q);
extern int enter_linkqueue(LinkQueue *q,DataType data);
extern DataType delete_linkqueue(LinkQueue *q);
#endif
#ifndef __LKSTACK__H
#define __LKSTACK__H
#include "data.h"
//#include <stdio.h>/*{{{*/
//#include <stdlib.h>
//#include <string.h>
//
//typedef int DataType;
定义结点类型
//struct node
//{
// DataType data;
//
// struct node *next;
//};/*}}}*/
//栈头类型
typedef struct
{
//指向栈顶结点
struct node *top;
//记录栈中元素
int n;
}LinkStack;
extern LinkStack *create_empty_stack();
extern int is_empty_stack(LinkStack *s);
extern int push_linkstack(LinkStack *s,DataType data);
extern DataType pop_linkstack(LinkStack *s);
extern DataType get_top_data(LinkStack *s);
#endif
#include "linkqueue.h"
//新建一个队列头
LinkQueue *creat_linkqueue()
{
//先分配一个头结点,head保存其地址
//在为队列头在堆区分配空间,q保存其首地址
struct node *head = NULL;
LinkQueue *q = NULL;
//创建空链表,链表队列头结点
head = (struct node *)malloc(sizeof(struct node));
memset(head,0,sizeof(struct node));//清空后指针域为NULL。表示空链表
//队列头,指向链表头跟链表尾
q = (LinkQueue *)malloc(sizeof(LinkQueue));
q->front = head;
q->rear = head;
return q;
}
///链表判空
int is_empty_linkqueue(LinkQueue *q)
{
return q->front == q->rear;
}
//尾插法插入数据
int enter_linkqueue(LinkQueue *q,DataType data)
{
struct node *temp = NULL;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->next = q->rear->next;
q->rear->next = temp;
//更新rear
q->rear = temp;
return 0;
}
//删头法对头数据出队
DataType delete_linkqueue(LinkQueue *q)
{
struct node *temp = NULL;
//保存原头结点首地址
temp = q->front;
//更新front
q->front = q->front->next;
free(temp);
temp = NULL;
return q->front->data;
}
#include "lkstack.h"
//创建空栈
LinkStack *create_empty_stack()
{
LinkStack *s =NULL;
s = (LinkStack*)malloc(sizeof(LinkStack));
s->top = NULL;
s->n = 0;
return s;
}
//栈判空
int is_empty_stack(LinkStack *s)
{
//return s->n;
return s->top == NULL;
}
int push_linkstack(LinkStack *s,DataType data)
{
struct node *temp = NULL;
temp = (struct node*)malloc(sizeof(struct node));
temp->data = data;
temp->next = s->top;//在新结点后链接链式栈
s->top = temp;//更新栈顶指针
s->n++;//跟新栈元素个数
return 0;
}
//出栈
DataType pop_linkstack(LinkStack *s)
{
struct node *temp = NULL;
DataType data;
temp = s->top ;
data = temp->data;
s->top = s->top->next;
s->n--;
free(temp);
return data;
}
DataType get_top_data(LinkStack *s)
{
return s->top->data;
}
#include "data.h"
#include "lkstack.h"
#include "linkqueue.h"
//判断队列内的钟球是不是按照0-26的顺序排列的
//若是则返回0,若不是则返回-1
int is_order_linkqueue(LinkQueue *lq)
{
int i = 0;
//LinkQueue *temp = lq;
struct node *temp = lq->front->next;//这里为什么要指向front->next呢?????
//为什么呢??????
//为什么呢???????
//struct node *temp = lq->front;
//while(delete_linkqueue(lq) != i++)
for(i = 0;i < 27;i++)
{
if(temp->data != i)
return 0;
temp = temp->next;
}
return 1;
}
int main()
{
int time = 0;
int i = 0;
int flag = 0;
int ball_data = 0;
int temp_ball = 0;
int minute = 0;
LinkQueue *lq= NULL;//定义一个链式队列头
LinkStack *ls_1s = NULL;//定义一个一分钟的链式栈头
LinkStack *ls_5s = NULL;//定义一个五分钟的链式栈头
LinkStack *ls_1h = NULL;//定义一个一小时的链式栈头
lq = creat_linkqueue();//创建一个链式队列,用lq指向队列头队列尾说明为空队列
//lq->front = lq->rear = NULL;//因为在创建新队列时已经将队头队尾初始化
ls_1s = create_empty_stack();//创建一个一分钟链式空栈
ls_5s = create_empty_stack();//创建一个五分钟链式空栈
ls_1h = create_empty_stack();//创建一个一小时链式空栈
for(i = 0;i < 27;i++)
{
enter_linkqueue(lq,i);
}
while(!is_empty_linkqueue(lq))/*{{{*/
//for(i = 26;i >= 0;i--)
//{
// printf("%-3d",delete_linkqueue(lq));
//}
//putchar('\n');/*}}}*/
//ball_data = delete_linkqueue(lq);
//while(!is_order_linkqueue(lq))
while(!flag)
{
minute++;
ball_data = delete_linkqueue(lq);
if(ls_1s->n < 4)
{
push_linkstack(ls_1s,ball_data);
//ball_data = delete_linkqueue(lq);
}
else
{
while(!is_empty_stack(ls_1s))
{
//temp_ball = pop_linkstack(ls_1s);
//enter_linkqueue(lq,temp_ball);
enter_linkqueue(lq,pop_linkstack(ls_1s));
}
if(ls_5s->n < 11)
{
push_linkstack(ls_5s,ball_data);
//ball_data = delete_linkqueue(lq);
}
else
{
while(!is_empty_stack(ls_5s))
{
temp_ball = pop_linkstack(ls_5s);
enter_linkqueue(lq,temp_ball);
}
if(ls_1h->n < 11)
{
push_linkstack(ls_1h,ball_data);
//ball_data = delete_linkqueue(lq);
}
else
{
while(!is_empty_stack(ls_1h))
{
temp_ball = pop_linkstack(ls_1h);
enter_linkqueue(lq,temp_ball);
}
enter_linkqueue(lq,ball_data);
if(is_order_linkqueue(lq))
{
flag = 1;
}
}
}
}
time = minute / 60;
printf("%d day:%d hour:%d minute\n",time/24,time%24,minute%60);
}
//time = minute / 60;
//printf("%d day:%d hour:%d minute\n",time/24,minute%24,minute%60%24);
//printf("%d day:%d hour:%d minutse\n",minute/60/20,minute%24/60,minute%20%60);
//printf("");
return 0;
}