球钟问题既栈和队列的结合实例

1 问题描述

问题.png
相当于有27个数,然后有三个栈,一个队列,数最开始的时候按顺序存储在队列中;开始时三个栈为空,这三个栈的分别是能容纳11个数的5分钟栈和小时栈,以及一个能容纳4个数的一分钟栈。

1.开始时27个数都在队列中,依次将出队,入一分钟栈,当一分钟栈满时,然后将一分钟栈中的元素依次出栈入队,然后再出队,入5分钟栈;
2.当5分钟栈满时,且一分钟栈也满时,先将一分钟栈中的元素出栈入队,再将5分钟栈的元素出栈入队,最后出队入小时栈;
3.当一分钟栈满,5分钟栈也满,且小时栈也满时,将依次将一分钟栈、5分钟栈和小时栈中的元素出栈入队,再将队头的元素出队入队,再回到 1 。
问:经过多少次出队,队列中的元素的顺序和最开始的元素顺序相同。

2 思路

我们只需要按照其要求进行模拟即可。
我们可以选择使用循环队列或者链式队列,循环队列比较难一点,使用链式队列的话在最后判断顺序的时候只需要判断对应位置的元素是否和初始元素相同;使用循环队列的话,元素的相对顺序判断比较麻烦,因为最后队头元素的绝对位置可能发生改变。

3 代码

3.1 队列

//定义循环队列的结构
#define K 27 //能够存放的数据的个数
typedef struct {
    int data[K + 1]; //存27个数,空一个数用判断
    int front, rear;
} loopqueue_t;

3.1.1 初始化队列

loopqueue_t* LoopQueueCreate(void){
    loopqueue_t *h;
    if((h = malloc(sizeof *h))== NULL){
        printf("malloc memory error\n");
        return NULL;
    }
    memset(h, 0, sizeof(h->data));
    //相当于给小球打编号,方便最后判断小球的顺序
    for(int i = 0; i < 27; i++)
        h->data[i] = i + 1;
    h->front = 0;  //队头
    h->rear = 27;  //队尾,其实是27个小球的下一个位置,方便判满、判空
    return h;
}

3.1.2 出队

int LoopQueueDeQueue(loopqueue_t* h){
    //使用判空,防止操作,也方便调试
   if(LoopQueueIsEmpty(h)){
        printf("队空,删除失败\n");
        return (int)-1;
    }
    int date = h->data[h->front];
    h->data[h->front] = 100000;     //销毁原来队列中存储的数据,为了安全安全,当发现出现了队中不应该出现的值,提示我们出错了
    h->front = (h->front + 1) % (K + 1);    //队头后移
    return date; //返回出队元素的值
}

3.1.3 入队

int LoopQueueEnQueue(loopqueue_t* h, int data){
    //使用判空,防止操作,也方便调试
    if(LoopQueueIsFull(h)){
        printf("队满,入队失败\n");
        return -1;
    }
    //因为rear是最后一个元素的下一位置,所以一定是先入队再移动
    h->data[h->rear] = data;    //入队
    h->rear = (h->rear + 1) % (K + 1);  //队尾后移
    return 0;
}

3.1.4 判队满

循环队列使用数组实现,当rear的下一个位置和front指向是同一个位置时就是数组满了

int LoopQueueIsFull(loopqueue_t* h){
    return (h->rear + 1) % (K + 1) == h->front ? 1 : 0;
}

3.1.5 判队空

当read和front指向的是同一个位置时,队列就空了

int LoopQueueIsEmpty(loopqueue_t* h){
    return h->rear == h->front ? 1 : 0;
}

3.2 栈

栈也使用顺序栈
因为需要大小不同的栈,所以我直接定义了两种不同的栈,下面的各种函数我也根据栈的大小实现了两次;
方便的方法是传参,根据参数进行操作

#define N 4
#define M 11

typedef struct {
    int data[N];
    int top;
} seqstack_t;

typedef struct {
    int data[M];
    int top;
} stack_t;

3.2.1 栈的初始化

seqstack_t* SeqStackCreate(void)
{
    seqstack_t* h;
    if ((h = malloc(sizeof *h)) == NULL) {
        printf("malloc memory error\n");
        return NULL;
    }
    h->top = -1;
    return h;
}
stack_t* StackCreate(void)
{
    stack_t* h;
    if ((h = malloc(sizeof *h)) == NULL) {
        printf("malloc memory error\n");
        return NULL;
    }
    h->top = -1;
    return h;
}

3.2.2 入栈

int SeqStackPush(seqstack_t* h, int data){
    if(SeqStackIsFull(h)){
        return 1;
    }
    h->data[++(h->top)] = data;
    return 0;
}
int StackPush(stack_t* h, int data){
    if(StackIsFull(h)){
        return -1;
    }
    h->data[++(h->top)] = data;
    return 0;
}

3.2.3 出栈

直接移动栈顶指针进行覆盖

int SeqStackPop(seqstack_t* h){
    return h->data[h->top--];
}
int StackPop(stack_t* h){
    return h->data[h->top--];
}

3.2.4 栈判满

top指向栈顶元素,所以只需要判断top是指向的栈的最大下标

int SeqStackIsFull(seqstack_t* h)
{
    return h->top == N - 1 ? 1 : 0;
}
int StackIsFull(stack_t* h)
{
    return h->top == M - 1 ? 1 : 0;
}

3.3 main函数

只有小时指示器,5分钟指示器,一分钟指示器都空的时候小球才全在队列中,此时才有可能出现队列中元素和初始元素相同


int main(int argc, const char* argv[])
{
    loopqueue_t* ball; //球队列
    stack_t *h, *min_five; //小时和五分钟指示器
    seqstack_t* min; //分钟指示器
    int day = 0;
    int date;
    int n = 50;

    //球钟初始化
    if ((ball = LoopQueueCreate()) == NULL) {
        printf("ball error\n");
        return -1;
    }
    if ((h = StackCreate()) == NULL) {
        printf("h error\n");
        return -1;
    }
    if ((min_five = StackCreate()) == NULL) {
        printf("min_five error\n");
        return -1;
    }
    if ((min = SeqStackCreate()) == NULL) {
        printf("min error\n");
        return -1;
    }

    while (1) {
        date = LoopQueueDeQueue(ball);
        if (SeqStackPush(min, date)) { //如果分钟指示器满将指示器中的小球加入ball队列中
            for (int i = 0; i < 4; i++) //加入ball队列,4次出队
                LoopQueueEnQueue(ball, SeqStackPop(min));
            if (StackPush(min_five, date)) { //如果5分钟指示器满则将指示器中的小球加入ball队列中
                for (int i = 0; i < 11; i++) //加入ball队列,11次出队
                    LoopQueueEnQueue(ball, StackPop(min_five));
                if (StackPush(h, date)) { //如果小时指示器满则将指示器中的小球加入ball队列中
                    for (int i = 0; i < 11; i++) //加入ball队列,11次出队
                        LoopQueueEnQueue(ball, StackPop(h));
                    LoopQueueEnQueue(ball, date);
                    day++;

                    int flag = 0;
                    for (int i = 0; i < 27; i++) {
                            if (ball->data[(i + ball->front) % (K + 1)] != i + 1) {
                            flag = 1;
                            break;
                        }
                    }
                    if (!flag)
                        break;
                }
            }
        }
    }
    printf("%d\n", day);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构是计算机科学中重要的基础知识,它以逻辑关系来组织和存储数据,使得数据的操作、管理和检索更加高效和方便。C语言作为一种功能强大且广泛使用的编程语言,常常与数据结构结合,实现各种实际应用。 一个常见的数据结构应用实例是栈(Stack)。栈是一种后进先出(LIFO)的数据结构,类似于我们日常生活中的堆放物品的方式。我们可以通过C语言实现一个栈的数据结构,并使用它进行一些实际应用。 例如,我们可以使用栈来实现浏览器的“后退”功能。当我们在浏览器中点击“后退”按钮时,程序会从一个存储浏览历史记录的栈中取出上一个页面的信息,并在浏览器窗口中显示出来。这个栈的结构可以用C语言的数组来实现,通过push()函数将浏览的每个页面信息按照时间顺序依次入栈,而当点击“后退”按钮时,可以通过pop()函数将栈顶的元素弹出,然后将其信息显示在浏览器窗口中。 另一个常见的数据结构应用实例是队列(Queue)。队列是一种先进先出(FIFO)的数据结构,就像我们排队等待的方式。我们可以通过C语言实现一个队列的数据结构,并将其应用于实际场景。 例如,我们可以使用队列来实现多线程任务调度。当我们在一个多线程程序中有多个任务需要执行时,可以使用队列将这些任务按顺序依次入队,并由一个线程来负责出队并执行任务。这个队列的结构可以用C语言的链表来实现,通过enqueue()函数将任务依次入队,而出队时则可以使用dequeue()函数将队头的任务弹出,然后由执行线程来执行。 通过以上两个实例,我们可以看到,数据结构在现实中的应用非常广泛,并且C语言作为一种高效且灵活的编程语言,可以很好地与数据结构结合,实现各种实际应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值