球钟问题
球钟问题
1. 问题背景
球钟是一个利用球的移动来记录时间的简单装置。它有三个可以容纳若干个球的指示器:分钟指示器,五分钟指示器和小时指示器。
举例:若分钟指示器中有2个球,五分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32
2. 工作原理
每过一分钟,球钟就会从球队列的队首取出一个球放入分钟指示器,分钟指示器最多可容纳4个球。当放入第五个球时,在分钟指示器的4个球就会按照他们被放入时的相反顺序加入球队列的队尾。而第五个球就会进入五分钟指示器。
按此类推,五分钟指示器最多可放11个球,小时指示器最多可放11个球。
当小时指示器放入第12个球时,原来的11个球按照他们被放入时的相反顺序加入球队列的队尾,然后12个球也回到队尾。这时,三个指示器均为空,回到初始状态,从而形成一个循环。因此,该球钟表示时间的范围为0:00到11:59.
3. 问题
现设初始时球队列的球数为27,球钟的三个指示器初态均为空,问,经过多久,球队列才能恢复到原来的顺序?
4. 求解和实现
4.1 求解思路:
1. 球队列的功能是实现 <= 27 个球的头出,尾部插入: 用链式队列实现。(顺序队列要跑循环,相对没那么方便)
2. 三个指示器的功能是存球,然后反顺序输出,固定存储大小:用顺序栈实现。
3. 计时逻辑是指示器栈满向前+1,然后清空当前栈。
4. 问题判断是否恢复原来顺序。初始化队列为有序队列1到27,后续判断队列是否满足从小到大排序即可。
5. 可复用代码:linkqueue.c/h 链队列, sqstack.c/h 顺序栈。
4.2 实现代码:
main.c
#include <stdio.h>
#include "sqstack.h"
#include "linkqueue.h"
int check(linkqueue q);
int main()
{
// 1. 创建球队列和三个指示器栈和计时变量time
int time = 0;
linkqueue ballqueue = linkqueue_create();
if (ballqueue == NULL)
{
printf("创建球队列失败!\n");
return -1;
}
sqstack minstack = sqstack_create(4);
sqstack fivestack = sqstack_create(11);
sqstack hourstack = sqstack_create(11);
if (minstack == NULL || fivestack == NULL || hourstack == NULL)
{
printf("创建指示器栈失败!\n");
return -1;
}
// 2. 初始球队列
for (size_t i = 1; i <= 27; i++)
{
linkqueue_enqueue(ballqueue, i);
}
linkqueue_show(ballqueue);
printf("球队列初始化完成!\n");
// 3. 开始计时,并调用检查函数判断是否恢复原始球队列
while (1)
{
time++;
if (!sqstack_full(minstack))
{
sqstack_push(minstack, linkqueue_dequeue(ballqueue));
}
else
{
while (!sqstack_empty(minstack))
{
linkqueue_enqueue(ballqueue, sqstack_pop(minstack));
}
if (!sqstack_full(fivestack))
{
sqstack_push(fivestack, linkqueue_dequeue(ballqueue));
}
else
{
while (!sqstack_empty(fivestack))
{
linkqueue_enqueue(ballqueue, sqstack_pop(fivestack));
}
if (!sqstack_full(hourstack))
{
sqstack_push(hourstack, linkqueue_dequeue(ballqueue));
}
else
{
while (!sqstack_empty(hourstack))
{
linkqueue_enqueue(ballqueue, sqstack_pop(hourstack));
}
linkqueue_enqueue(ballqueue, linkqueue_dequeue(ballqueue));
if (check(ballqueue) == 1)
{
break;
}
}
}
}
}
printf("***********\n");
printf("检查球队列恢复是否原始状态!\n");
linkqueue_show(ballqueue);
printf("用时:%d\n",time);
linkqueue_free(&ballqueue);
sqstack_free(&minstack);
sqstack_free(&fivestack);
return 0;
}
int check(linkqueue q)
{
queuenode tem = q->front->next;
int i = 0;
while (tem->next != NULL)
{
if (tem->data < tem->next->data)
{
tem = tem->next;
i++;
}
else
{
return 0;
}
}
return 1;
}
linkqueue.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkqueue.h"
/**
* @name linkqueue_create()
* @brief 创建链式队列
* @param NULL
* @retval q 队列地址
*/
linkqueue linkqueue_create()
{
// 1. 申请队列头尾指针内存和队列节点内存
linkqueue p = (linkqueue)malloc(sizeof(linkqueue_struct));
if (p == NULL)
{
printf("linkqueue malloc error\n");
return NULL;
}
queuenode newnode = (queuenode)malloc(sizeof(queuenode_struct));
if (newnode == NULL)
{
printf("linknode malloc error\n");
free(p);
return NULL;
}
// 2. 初始化队列头尾指针和队列节点
p->front = p->rear = newnode;
newnode->next = NULL;
newnode->data = -1;
return p;
}
/**
* @name linkqueue_create()
* @brief p判断链式队列是否为空
* @param q 队列地址
* @retval 0 队列不为空,1 队列为空,-1 队列不存在
*/
int linkqueue_empty(linkqueue q)
{
// 1. 判断队列是否存在
if (q == NULL)
{
printf("linkqueue is invalid\n");
return -1;
}
// 2. 判断队列是否为空
return q->front == q->rear ? 1 : 0;
}
/**
* @name linkqueue_enqueue()
* @brief 入队
* @param q 队列地址
* @retval 0 入队成功,-1 入队失败
*/
int linkqueue_enqueue(linkqueue q, data_t x)
{
// queuenode tem;
// 1. 判断队列是否存在
if (q == NULL)
{
printf("linkqueue is invalid\n");
return -1;
}
// 2. 申请队列节点内存
queuenode newnode = (queuenode)malloc(sizeof(queuenode_struct));
if (newnode == NULL)
{
printf("queuenode malloc error\n");
return -1;
}
newnode->data = x;
newnode->next = NULL;
// 3. 将新节点插入到队列尾结点之后,并尾指针指向新节点
// tem = q->front;
// while (tem->next != NULL)
// {
// tem = tem->next;
// }
// tem->next = newnode;
q->rear->next = newnode;
q->rear = newnode;
return 0;
}
/**
* @name linkqueue_dequeue()
* @brief 出队
* @param q 队列地址
* @retval 出队元素
*/
data_t linkqueue_dequeue(linkqueue q)
{
// 1. 判断队列是否存在
if (q == NULL)
{
printf("linkqueue is invalid\n");
return -1;
}
// 2. 判断队列是否为空
if (q->front == q->rear)
{
printf("linkqueue is empty\n");
return -1;
}
// 3. 出队操作,释放队头结点,并头指针指向头结点下一个结点
queuenode tem = q->front->next;
data_t x = tem->data;
q->front->next = tem->next;
if (q->rear == tem)
{
q->rear = q->front;
}
free(tem);
return x;
}
/**
* @name linkqueue_show()
* @brief 遍历队列,输出队列元素
* @param q 队列地址
* @retval -1 遍历失败,0 遍历成功
*/
int linkqueue_show(linkqueue q)
{
// 1. 判断队列是否存在以及队列是否为空
if (q == NULL)
{
printf("linkqueue is invalid\n");
return -1;
}
if (q->front == q->rear)
{
printf("linkqueue is empty\n");
return -1;
}
// 2. 遍历队列,输出队列元素
queuenode tem = q->front->next;
while (tem != NULL)
{
printf("%d \n", tem->data);
tem = tem->next;
}
return 0;
}
/**
* @name linkqueue_free()
* @brief 遍历队列,输出队列元素
* @param q 队列地址
* @retval -1 释放失败,0 释放成功
*/
int linkqueue_free(linkqueue *q)
{
// 1. 判断队列是否存在
if (*q == NULL)
{
printf("linkqueue is invalid\n");
return -1;
}
// 2. 释放队列
queuenode tem = (*q)->front;
while (tem != NULL)
{
queuenode next = tem->next;
free(tem);
tem = next;
}
free(*q);
*q = NULL;
return 0;
}
linkqueue.h
typedef int data_t;
typedef struct node_t
{
data_t data; // 数据域
struct node_t *next; // 指针域
} queuenode_struct, *queuenode; // 队列结点结构体类型定义
typedef struct
{
queuenode front, rear;
} linkqueue_struct,*linkqueue; // 队列结构体类型定义
linkqueue linkqueue_create(); // 创建队列
int linkqueue_empty(linkqueue q); // 判断队列是否为空
int linkqueue_enqueue(linkqueue q, data_t x); // 入队
data_t linkqueue_dequeue(linkqueue q); // 出队
int linkqueue_show(linkqueue q); // 遍历队列
int linkqueue_free(linkqueue *q); // 释放队列
sqstack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset
#include "sqstack.h"
/**
* @name sqstack_create()
* @brief 创建顺序栈
* @param length 栈长
* @retval 栈地址
*/
sqstack sqstack_create(int length)
{
sqstack s;
// 1. 检查栈长参数是否合理
if (length < 0)
{
printf("length is invalid\n");
return NULL;
}
// 2. 申请栈空间,先申请栈结构体,然后申请data空间
if ((s = (sqstack)malloc(sizeof(sqstack_struct))) == NULL)
{
printf("malloc sqstack failed\n");
return NULL;
}
if ((s->data = (data_t *)malloc(length*sizeof(data_t))) == NULL)
{
printf("malloc sqstack->data failed\n");
free(s);
return NULL;
}
// 3. 初始化栈
memset(s->data, 0, length*sizeof(data_t));
s->maxlen = length;
s->top = -1;
return s;
}
/**
* @name sqstack_push()
* @brief 顺序栈入栈
* @param s 栈地址,x 入栈元素
* @retval 0 入栈成功,-1 入栈失败
*/
int sqstack_push(sqstack s, data_t x)
{
// 1. 检查栈是否存在以及栈是否满
if (s == NULL)
{
printf("sqstack is invalid\n");
return -1;
}
if (s->top == s->maxlen - 1)
{
printf("sqstack is full\n");
return -1;
}
// 2. 入栈
s->top++;
s->data[s->top] = x;
return 0;
}
/**
* @name sqstack_empty()
* @brief 顺序栈判断是否为空
* @param s 栈地址
* @retval 1 栈为空,0 栈不为空
*/
int sqstack_empty(sqstack s)
{
// 1. 检查栈是否存在
if (s == NULL)
{
printf("sqstack is invalid\n");
return -1;
}
// 2. 通过栈顶判断栈是否为空
return(s->top == -1 ? 1 : 0);
}
/**
* @name sqstack_full()
* @brief 顺序栈判断是否满
* @param s 栈地址
* @retval 1 栈为满,0 栈不满
*/
int sqstack_full(sqstack s)
{
// 1. 检查栈是否存在
if (s == NULL)
{
printf("sqstack is invalid\n");
return -1;
}
// 2. 通过栈顶判断栈是否为满
return(s->top == s->maxlen - 1 ? 1 : 0);
}
/**
* @name sqstack_pop()
* @brief 顺序栈出栈
* @param s 栈地址
* @retval 出栈元素
*/
data_t sqstack_pop(sqstack s)
{
// 1. 检查栈是否存在
if (s == NULL)
{
printf("sqstack is invalid\n");
}
// 2. 出栈
s->top--;
return s->data[s->top+1];
}
/**
* @name sqstack_top()
* @brief 顺序栈获取栈顶元素
* @param s 栈地址
* @retval 出栈元素
*/
data_t sqstack_top(sqstack s)
{
// 1. 检查栈是否存在
if (s == NULL)
{
printf("sqstack is invalid\n");
}
// 2. 返回栈顶元素
return s->data[s->top];
}
/**
* @name sqstack_clear()
* @brief 顺序栈清空
* @param s 栈地址
* @retval 0 清空成功,-1 清空失败
*/
int sqstack_clear(sqstack s)
{
// 1. 检查栈是否存在
if (s == NULL)
{
printf("sqstack is invalid\n");
return -1;
}
// 2. 清空栈。直接将栈顶置为-1,后续的入栈操作会覆盖原来的值。
s->top = -1;
return 0;
}
/**
* @name sqstack_free()
* @brief 顺序栈出栈
* @param s 栈地址
* @retval 0 释放成功,-1 释放失败
*/
int sqstack_free(sqstack *s)
{
if (*s == NULL)
{
printf("sqstack is invalid\n");
return -1;
}
if ((*s)->data != NULL)
{
free((*s)->data);
}
free(*s);
*s = NULL;
return 0;
}
sqstack.h
typedef int data_t; // 定义数据类型
typedef struct
{
data_t *data;
int maxlen; // 栈最大长度
int top; // 栈顶-1标准栈为空
} sqstack_struct,*sqstack;
sqstack sqstack_create(int length); // 创建一个长度为length的栈,返回值为栈的指针
int sqstack_push(sqstack s, data_t x); // 元素x入栈,返回值为 0表示成功,-1表示失败
int sqstack_empty(sqstack s); // 判断栈是否为空,返回值为 1表示空,0表示非空
int sqstack_full(sqstack s); // 判断栈是否为满,返回值为 1表示满,0表示非满
data_t sqstack_pop(sqstack s); // 栈顶元素出栈,返回值为栈顶元素
data_t sqstack_top(sqstack s); // 返回栈顶元素,栈顶元素不变
int sqstack_clear(sqstack s); // 清空栈,返回值为 0表示成功,-1表示失败
int sqstack_free(sqstack *s); // 释放栈,返回值为 0表示成功,-1表示失败
5 结果:


浙公网安备 33010602011771号