顾客排队购买蛋挞问题(算法与数据结构设计)

课题内容和要求

顾客排队买蛋挞问题。有N个顾客排队,每人最多买M个。烘焙员每次烘焙1到K个蛋挞放入盘中,顾客只能购买盘中的蛋挞,未达到M个需重新排队。输出每个顾客购买情况和完成顺序。
例如——
输入:N=9,K=5;M=7
输出的购买情况为:

首次购买数量第二次购买数量第三次购买数量
顾客1151
顾客2214
顾客3322
顾客443
顾客552
顾客616
顾客7223
顾客8322
顾客943

购买到M个蛋挞的顾客的顺序为:4,5,6,9,1,2,3,7,8

数据结构说明

结构体Shop,存放商店营业信息,包括顾客数量N,蛋挞每次生产的上限K,每个顾客最多购买的数量M,以及每位顾客购买信息用结构体数组cu存放。数组result用于存放购买到M个蛋挞的顾客顺序,例如result[0]=i,表示顾客i第一个购买完M个蛋挞。list_col用于记录购买情况表的列数,控制最后输出购买情况的表头。

结构体Customer,存放顾客还需要购买蛋挞的数量(初始时需要购买数量M),顾客购买次数record,以及每次购买的记录以链表的形式按次序存储。

结构体Cal,存放顾客购买记录的链表结点,n表示该次购买的数量,next指向下一次购买记录结点。

算法设计

算法步骤:
(1)根据输入初始化shop当中的所有信息。
(2)初始化控制数组cu元素循环的下标cu_cal为0,初始化控制数组result下标的re_cal为0,标记flag初始化为0,蛋挞每次生产数量i初始化为0。
(3)若flag不为1,执行以下循环,直至flag=1。
a.i+1,若i>K重新置i=1,并将i加入到盘K_当中
b.通过循环判断顾客还需购买的数量mount是否为0,若为0表示购买完毕,数组cu下标cu_cal+1后对顾客数量N取模,遍历完数组cu直至找到一个还没购买完M个蛋挞的顾客,退出b步骤循环。该循环不会死循环,总能找到最后一个顾客未购买完M个蛋挞,并在后续步骤中将flag置为1,在下一轮大循环((3)步骤)中退出,不会再进到该循环。
c.判断盘中K_的数量是否大于顾客还需够买的数量mount,若mount大于K_则将mount的值减去K_的值,并添加该顾客的购买记录,置K_为0,接着判断该顾客的购买记录数record是否大于购买情况结果列数list_col,若大于则将record值赋值给list_col;若mount小于或等于K_,则将K_的值减去mount的值,并添加该顾客的购买记录,接着判断该顾客的购买记录数record是否大于购买情况结果列数list_col,若大于则将record值赋值给list_col,置该顾客的mount为0,此时该顾客已经购买完M个蛋挞,将该顾客的序号cu_cal加1后(加1后才是顾客真正的序号)赋值给购买顺序结果result[re_cal],re_cal加1使数组result下标后移。判断re_cal的值是否等于顾客数量N,若等于,表示所有顾客都已购买完M个蛋挞,置flag为1。
d.cu_cal加1并对N取模,使数组cu下标后移
(4)依据list_col值循环输出购买情况表头“第i+1次购买数量”
(5)依据顾客N值循环输出顾客的序号,并且遍历购买记录链表输出购买数量
(6)最后按顺序循环输出存放在数组result中顾客购买顺序

详细设计

程序包含文件shop_main.c、shop.h、shop.c

shop_main.c

#include <stdio.h>
#include <stdlib.h>
#include "shop.h"
int main()
{
    Shop *sh = (Shop*)malloc(sizeof(Shop));
    int N = 0;  // 顾客数量
    int K = 0;  // 商店生产蛋挞的上限
    int M = 0;  // 顾客需要购买的数量
    printf("蛋挞店\n");
    printf("请输入顾客数量:\n");
    scanf("%d",&N);
    printf("请输入商店生产蛋挞的上限:\n");
    scanf("%d",&K);
    printf("请输入顾客需要购买的数量:\n");
    scanf("%d",&M);
    Init_shop(sh,N,K,M);    // 调用函数初始化商店营业信息
    Shop_work(sh);      // 调用函数生成购买情况并输出
    printf("回车结束程序...\n");
    getchar();  // 将输入顾客需要购买的数量时按下的回车接收
    getchar();  // 等待输入回车结束程序运行
    free(sh);
}

shop.h

#ifndef __SHOP_H__
#define __SHOP_H__
typedef struct cal  // 存放顾客一次购买记录的结构体
{
    int n;  // 存放购买数量
    struct cal *next;   // 指向下一个结点的指针
}Cal;
typedef struct customer // 存放顾客购买信息的指针
{
    int mount;  // 存放还需要购买的数量
    int record; // 存放购买次数
    Cal *first; // 存放购买记录的链表头指针
}Customer;
typedef struct shop // 商店营业信息
{
    Customer *cu;   // 存放顾客信息的数组头指针
    int *result;    // 将已经购买到M个蛋挞顾客按顺序存入数组
    int list_col;   // 记录生成结果表的列数,用于构造结果表
    int N; // 顾客数量
    int K;  // 生产蛋挞的上限
    int K_; // 盘中被购买后剩余的蛋挞数量
    int M;  // 顾客需要购买蛋挞的数量
}Shop;
void Init_shop(Shop *shop,int N, int K, int M); // 商店初始化
void Creat_cal(Customer *cu, int n);    // 购买记录结点创建
void Shop_work(Shop *shop); // 商店程序运行
#endif

shop.c

#include "shop.h"
#include <stdio.h>
#include <stdlib.h>
/**
 * @brief 商店初始化
 * @param shop 指向商店营业信息的指针
 * @param N 顾客数量
 * @param K 商店生产蛋挞的上限
 * @param M 顾客需要购买蛋挞的数量
 * @return void
*/
void Init_shop(Shop *shop,int N, int K, int M)
{
    shop->list_col = 0; // 初始化购买情况结果列数为0
    shop->N = N;
    shop->cu = (Customer*)malloc(N*sizeof(Customer));   // 动态申请存顾客信息的数组空间
    shop->result = (int*)malloc(N*sizeof(int)); // 动态申请存放顾客编号
    if(!shop->cu&&!shop->result)
    {
        printf("申请空间失败————顾客数组,购买顺序\n");
    }
    for(int i = 0;i<N;i++)  // 初始化每个顾客信息
    {
        shop->cu[i].mount = M;
        shop->cu[i].first = NULL;
        shop->cu[i].record = 0;
        shop->result[i] = 0;
    }
    shop->K = K;
    shop->K_ = 0;
    shop->M = M;
}
/**
 * @brief 购买记录结点创建
 * @param cu 指向顾客信息的指针
 * @param n 该次购买蛋挞的数量
 * @return void
*/
void Creat_cal(Customer *cu, int n)
{
    if(cu->first==NULL) // 当没有购买记录时创建第一次购买记录
    {
        cu->first = (Cal*)malloc(sizeof(Cal));
        if(!cu->first)
        {
            printf("申请空间失败————购买记录");
        }
        cu->first->n = n;
        cu->record+=1;
        cu->first->next = NULL;
        return;
    }
    Cal *p = cu->first;
    for(;p->next; p=p->next);  // 将p指向最后一个不为空的结点,链表元素尾插
    p->next = (Cal*)malloc(sizeof(Cal));
    if(!p->next)
    {
        printf("申请空间失败————购买记录");
    }
    p->next->n = n;
    cu->record += 1;
    p->next->next = NULL;
}
/**
 * @brief 商店程序运行
 * @param shop 指向商店营业信息的指针
 * @return void
*/
void Shop_work(Shop *shop)
{
    int cu_cal = 0; // 数组下标,用于循环顾客排队购买蛋挞
    int re_cal = 0; // 数组下标,用于result数组的计数,每当一个顾客购买完所需的蛋挞,+1
    int flag = 0;   // 标记,用于提前退出循环
    int i = 0;  // 蛋挞生产计数1~K
    while(!flag)
    {
        i++;
        if(i>shop->K)   // 当蛋挞生产计数大于K时,重新置为1开始累加
        {
            i=1;
        }
        shop->K_+=i;    // 将该次生产的蛋挞数加入到被购买后剩余的蛋挞数量中
        while(shop->cu[cu_cal].mount==0)    // 判断顾客是否购买完蛋挞,如果购买完,将数组下标向后移
        {
            // 该循环不会死循环,总能找到最后一个顾客未购买完M个蛋塔,
            // 并在后续步骤中将flag置为1,在下一轮大循环中退出,不会再进到该循环
            cu_cal = (cu_cal+1)%shop->N;   // 数组下标后移
        }
        if(shop->cu[cu_cal].mount>shop->K_) // 顾客还需要购买的数量大于盘中剩余数量
        {
            shop->cu[cu_cal].mount-=shop->K_;
            Creat_cal(&(shop->cu[cu_cal]),shop->K_);    // 调用函数创建购买记录结点
            shop->K_ = 0;
            if(shop->list_col<(shop->cu[cu_cal].record))    // 如果顾客的购买记录数大于结果表的列数,更新列数
            {
                shop->list_col = shop->cu[cu_cal].record;
            }
        }
        else    // 顾客还需要购买的数量小于或等于盘中剩余数量
        {
            shop->K_ -= shop->cu[cu_cal].mount;
            Creat_cal(&(shop->cu[cu_cal]),shop->cu[cu_cal].mount);     // 调用函数创建购买记录结点
            if(shop->list_col<(shop->cu[cu_cal].record))
            {
                shop->list_col = shop->cu[cu_cal].record;
            }
            shop->cu[cu_cal].mount = 0;
            shop->result[re_cal] = cu_cal+1;    // 顾客所需数量已足够,将顾客编号记录在数组中
            re_cal +=1; // 数组下标后移
            if(re_cal==shop->N) // 如果re_cal等于顾客数量,则表示所有顾客都购买完蛋挞,置flag标志位为1
            {
                flag = 1;
            }
        }
        cu_cal = (cu_cal+1)%shop->N;    // 数组下标后移
    }
    // 将购买情况输出
    printf("购买情况如下:\n");
    printf("          ");
    for(i = 0;i<shop->list_col;i++) // 输出表头
    {
        printf("第%d次购买数量 ",i+1);
    }
    printf("\n");
    for(i = 0;i<shop->N;i++)
    {
        Cal *p = shop->cu[i].first;
        printf("顾客%2d",i+1);
        for(;p;p = p->next) // 将每个顾客购买信息一行一行的输出
        {
            printf("%13d",p->n);
        }
        printf("\n");
    }
    printf("购买到%d个蛋挞的顾客的顺序为:",shop->M);
    for(i = 0;i<shop->N;i++)
    {
        printf("顾客%d ",shop->result[i]);
    }
    printf("\n");
}

测试数据及其结果分析

运行结果1(题目例子):
在这里插入图片描述
运行结果2:
在这里插入图片描述

  • 31
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值