停车场管理系统 数据结构工程实训

问题描述:停车场是一个能放 n 辆车的狭长通道,只有一个大门,汽车按到达的先后次序停放。若车场满了,车要在门外的便道上等候,一旦有车走,则便道上第一辆车进入。当停车场中的车离开时,由于通道窄,在它后面的车要先退出,待它走后依次进入。汽车离开时按停放时间收费。
基本功能要求:
1)建立三个数据结构分别是:停放队列,让路栈,等候队列
2)输入数据模拟管理过程,数据(入或出,车号)。

main.c:

#define _CRT_SECURE_NO_WARNINGS //兼容VS2017
/**********************************************************
兼容 vc6.0 、vs2010 、 vs2017 采用的 c89 标准
兼容 Windows 和 Linux 系统
问题描述:停车场是一个能放 n 辆车的狭长通道,只有一个大门,
汽车按到达的先后次序停放。若车场满了,车要在门外的便道上等候
,一旦有车走,则便道上第一辆车进入。当停车场中的车离开时,由
于通道窄,在它后面的车要先退出,待它走后依次进入。汽车离开
时按停放时间收费。
基本功能要求:
    1)建立三个数据结构分别是:停放队列,让路栈,等候队列
    2)输入数据模拟管理过程,数据(入或出,车号)。
***********************************************************/

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include "park.h"
#define EXIT '5'
#define Price    1          // 单价可以自己定义n
#define SYSTEM_FILE_NAME "parking_management_system.data"

// 保存系统文件
void save_system(Pavement *p_pavement, Stopping *p_stopping, Buffer   *p_buffer, Car *p_car, char *file_name)
{
    FILE *fp;
    LinkPavement *temp;
    int i;

    fp = fopen(file_name, "wb");
    if (fp)
    {
        fwrite(p_stopping, sizeof(Stopping), 1, fp);
        fwrite(p_buffer, sizeof(Buffer), 1, fp);
        fwrite(p_car, sizeof(Car), 1, fp);

        fwrite(p_pavement, sizeof(Pavement) - sizeof(void *), 1, fp);
        temp = p_pavement->head;

        for (i = 0; i < MAX_PAVE && temp!=NULL; i++)
        {
            fwrite(temp, sizeof(LinkPavement) - sizeof(void *), 1, fp);
            temp = temp->next;
        }

        fclose(fp);
    }
    else
    {
        fprintf(stderr, "%s", "Error: 无法打开或者创建文件\n");
    }
}

int main()
{
    int i;
    Pavement *p_pavement;
    LinkPavement *temp,buf_link;
    Stopping stopping = { 0 };
    Buffer   buffer = { 0 };
    Car car = { 0 };
    char ch;

    FILE *fp = NULL;
    char opt = '\0';//专门用来储存选项

    p_pavement = (Pavement *)malloc(sizeof(Pavement));
    memset(p_pavement, 0, sizeof(Pavement));
    fp = fopen(SYSTEM_FILE_NAME, "rb");
    if (fp)
    {
        printf("%s",
            "检测到系统数据库文件,即将载入文件\n"
            "您可以输入 n 取消载入,或者直接回车载入系统数据库文件\n"
            ">>> ");
        fflush(stdout);
        setbuf(stdin, NULL); // 清空输入流流,防止数据污染
        if (fgetc(stdin) != 'n')
        {
            fread(&stopping, sizeof(Stopping), 1, fp);
            fread(&buffer, sizeof(Buffer), 1, fp);
            fread(&car, sizeof(Car), 1, fp);

            fread(p_pavement, sizeof(Pavement) - sizeof(void *), 1, fp);
            if (-1 != fread(&buf_link, sizeof(LinkPavement) - sizeof(void *), 1, fp))
            {
                p_pavement->head = (LinkPavement *)malloc(sizeof(LinkPavement));
                memcpy(p_pavement->head, &buf_link, sizeof(LinkPavement) - sizeof(void *));
            }
            temp = p_pavement->head;

            for (i = 0; i < MAX_PAVE-1 ; i++)
            {
                if (-1 == fread(&buf_link, sizeof(LinkPavement) - sizeof(void *), 1, fp))
                {
                    break;
                }
                
                temp->next = (LinkPavement *)malloc(sizeof(LinkPavement));
                memcpy(temp->next, &buf_link, sizeof(LinkPavement) - sizeof(void *));
            }

            temp->next = NULL;
        }
        else
        {
            // 初始化
            stopping.top = -1;
            buffer.top = 0;
            p_pavement->count = 0;
            p_pavement->head = NULL;
        }
        setbuf(stdin, NULL);// 清空输入流流,防止输入流溢出
        fclose(fp);
    }
    else
    {
        // 初始化
        stopping.top = -1;
        buffer.top = 0;
        p_pavement->count = 0;
        p_pavement->head = NULL;
    }

    while (opt != EXIT)
    {
#ifdef _WIN32 // 兼容MSVC编译器
        system("cls");
#elif  __GNUC__ // 兼容gcc编译器
        system("clear");
#endif
        // 主界面函数
        printf("\t*******************目前停车场状况***********************\n");
        printf("\t停车场共有%d个车位,当前停车场共有%d辆车,等候区共有%d辆车\n", MAX_STOP, stopping.top + 1, p_pavement->count);
        printf(
            "\t********************************************************\n"
            "\t---------------欢迎使用停车管理系统---------------\n"
            "\t请输入功能号进行任务选择:                            \n"
            "\n"
            "\t*                  1.停车                           *\n"
            "\t*                  2.离开                           *\n"
            "\t*                  3.当前状态                       *\n"
            "\t*                  4.保存系统数据库文件             *\n"
            "\t*                  5.退出                           *\n"
            "\t-----------------------------------------------------\n");

        fprintf(stdout, "%s", ">>> ");
        fflush(stdout);// 刷新输入流,否则在部分系统不会自动刷新

        opt = fgetc(stdin); // 从输入流中直接获取
        setbuf(stdin, NULL); // 刷新输入流,防止输入流溢出

        switch (opt)
        {
        case '1':
            car_come(p_pavement, MAX_PAVE, &stopping);
            break;
        case '2':
            car_leave(p_pavement, &stopping, &buffer, &car, Price, MAX_PAVE, MAX_STOP);
            break;
        case '3':
            Display(&stopping, Price);
            break;
        case '4':
            save_system(p_pavement, &stopping, &buffer, &car, SYSTEM_FILE_NAME);// 保存系统文件
            printf("保存成功!\n\n");
            break;
        case EXIT:
            break;
        default:
            fprintf(stderr, "%s", "您的输入有误,请重新输入\n"); // 输入到错误流中
            break;
        }

        if (opt != EXIT)
        {
            fprintf(stdout, "%s", "按下 Enter 键返回到主系统\n");
            fflush(stdout);// 刷新输入流流,否则在部分系统不会自动刷新

            while((ch=getchar())!='\n'&&ch!=EOF);
            fgetc(stdin);
            setbuf(stdin, NULL); // 刷新输入流,防止输入流溢出
        }
    }
    save_system(p_pavement, &stopping, &buffer, &car, SYSTEM_FILE_NAME); // 保存系统文件
    printf("\n自动保存系统数据库文件成功\n");
    printf("欢迎下次使用,再见!\n");

    free_link_pavement(p_pavement);
    return 0;
}

park.h

#ifndef  PARK
#define PARK

#define MAX_STOP 4
#define MAX_PAVE 4

// 汽车信息
typedef struct
{

    long long timeIn;              // 进入停车场时间
    long long timeOut;             // 离开停车场时间
    char plate[0x100];
    // 汽车牌照号码,定义一个字符指针类型
}Car;

// 停放栈(用于停放车辆)
typedef struct
{
    Car Stop[MAX_STOP];   // 用于停放车辆的栈
    int top;                  // 标记栈顶位置
}Stopping;

// 等候链队列
typedef struct LinKPavement
{
    Car car;
    struct LinKPavement *next;                 // 等候停车的队列
}LinkPavement;

// 等候队列链首
typedef struct
{
    int count;                // 用来指示队中的数据个数
    int max_pave;
    struct LinKPavement *head;                 // 等候停车的队列
}Pavement;

// 让路栈
typedef struct
{
    Car Help[MAX_STOP];   // 用于让路的队列
    int top;                  // 标记站定位置
}Buffer;


// 释放链队列
void free_link_pavement(Pavement *p_pavement);
void stop_to_pave(Pavement *p_pavement, int max_pave, char *licence_plate);       // 车停入便道
void car_come(Pavement *p_pavement, int max_pave, Stopping *p_stopping);       // 车停入停车位
void stop_to_buff(Pavement *p_pavement, Stopping *p_stopping, Buffer *p_buffer, Car *p_car, char *info, int price, int max_pave, int max_stop);       // 车进入让路栈
void car_leave(Pavement *p_pavement, Stopping *p_stopping, Buffer *p_buffer, Car *p_car, int price, int max_pave, int max_stop);       // 车离开
void Display(Stopping *p_stopping, int price);       // 显示车辆信息

#endif //PARK

park.c

#define _CRT_SECURE_NO_WARNINGS //兼容VS2017

#include <stdlib.h>
#include <stdio.h>
#include <time.h>                           // 包含时间函数的头文件
#include <string.h>

#include "park.h"


void free_link_pavement(Pavement *p_pavement)
{
    LinkPavement *temp,*head;
    int i,max_pave;

    head = p_pavement->head;
    max_pave = p_pavement->max_pave;

    free(p_pavement);
    for (i = 0; i < max_pave && head !=NULL; i++)
    {
        temp = head;
        head = head->next;
        free(temp);
    }
}

void stop_to_pave(Pavement *p_pavement, int max_pave, char *licence_plate) // 车停入便道
{
    LinkPavement *link;
    // 判断队满
    if (p_pavement->count>=max_pave)
    {
        printf("便道已满,请下次再来\n");
    }
    else
    {
        link = (LinkPavement *)malloc(sizeof(LinkPavement));// 分配空间
        memset(link, 0, sizeof(LinkPavement));// 清零

        strcpy(link->car.plate, licence_plate);  // 车进入便道
        link->next = p_pavement->head;
        p_pavement->head = link;

        (p_pavement->count)++;                        // 计数器加1
        printf("牌照为 %s 的汽车停入便道\n", licence_plate);
    }
}

void car_come(Pavement *p_pavement, int max_pave, Stopping *p_stopping) // 车停入停车位
{
    time_t t1;
    long int t;
    char buf[0x100] = { 0 }; // 用于缓存字符
    char time_str[0x100] = { 0 };
    char ch;

    printf("请输入即将停车的车牌号:"); // 输入车牌号

#ifdef __GNUC__
    while ((ch = getchar()) != '\n'&&ch != EOF); // 清空输入流流,防止数据污染
#endif // __GNUC__

    fgets(buf, 0x100, stdin); // 防止溢出
    buf[strlen(buf) - 1] = '\0';
    setbuf(stdin, NULL);// 刷新输入流流,防止输入流流溢出

    if (p_stopping->top >= MAX_STOP - 1) // 如果停车位已满,停入便道
    {
        stop_to_pave(p_pavement, max_pave, buf); // 停入便道
    }
    else
    {
        p_stopping->top++; // 停车位栈顶指针加1

        t = (long long)time(&t1); // 记录进入停车场的时间

        strftime(time_str, sizeof(time_str), "%Y-%m-%d %X", localtime(&t1));

        p_stopping->Stop[p_stopping->top].timeIn = t;

        strcpy(p_stopping->Stop[p_stopping->top].plate, buf); // 将车牌号登记
        printf("牌照为 %s 的汽车停入停车位的 %d 车位, 当前时间: %s\n", buf, p_stopping->top + 1, time_str);
    }

    return;
}

void stop_to_buff(Pavement *p_pavement, Stopping *p_stopping, Buffer *p_buffer, Car *p_car, char *info, int price, int max_pave, int max_stop) // 车进入让路栈
{
    time_t t1;
    int i, count;
    long long t;
    char time_str[0x100] = { 0 };
    LinkPavement *temp1, *temp2;

    // 停车位栈压入临时栈,为需要出栈的车辆让出道
    while (p_stopping->top >= 0)
    {
        if (0 == strcmp(p_stopping->Stop[p_stopping->top].plate, info))
        {
            break;
        }

        // 让出的车进入让路栈
        strcpy(p_buffer->Help[(p_buffer->top)++].plate, p_stopping->Stop[p_stopping->top].plate);
        printf("牌照为 %s 的汽车暂时退出停车场\n", p_stopping->Stop[(p_stopping->top)--].plate);
    }

    // 如果停车位中的车都让了道,说明停车位中无车辆需要出行
    if (p_stopping->top < 0)
    {
        printf("停车位上无此车消息\n");
    }
    else
    {
        printf("牌照为 %s 的汽车从停车场开走\n", p_stopping->Stop[p_stopping->top].plate);

        t = time(&t1);
        p_car->timeOut = t; // 标记离开停车场的时间

        strftime(time_str, sizeof(time_str), "%Y-%m-%d %X", localtime(&t1));

        printf("\n离开时间%s\n需付%lld元\n\n", time_str, price * (p_car->timeOut - p_stopping->Stop[p_stopping->top].timeIn));
        (p_stopping->top)--;
    }

    // 将让路栈中的车辆信息压入停车位栈
    while (p_buffer->top > 0)
    {
        strcpy(p_stopping->Stop[++(p_stopping->top)].plate, p_buffer->Help[--(p_buffer->top)].plate);
        printf("牌照为 %s 的汽车停回停车位 %d 车位\n", p_buffer->Help[p_buffer->top].plate, p_stopping->top);
    }

    // 从便道中 -> 停车位
    while (p_stopping->top < max_stop - 1)
    {
        if (p_pavement->count <= 0) // 判断队列是否为空
        {
            break;
        } // 不为空,将便道中优先级高的车停入停车位
        else
        {
            temp1 = p_pavement->head;
            count = --(p_pavement->count);
            for (i = 0; i < count-1; i++)
            {
                temp1 = temp1->next;
            }
            
            if (count == 0)
            {
                printf("牌照为 %s 的汽车从便道中进入停车位的 %d 车位\n", temp1->car.plate, p_stopping->top);

                strcpy(p_stopping->Stop[++(p_stopping->top)].plate, temp1->car.plate);

                t = (long long)time(&t1); // 记录进入停车场的时间

                p_stopping->Stop[p_stopping->top].timeIn = t;

                p_pavement->head = NULL;
                free(temp1);
            }
            else
            {
                temp2 = temp1;
                temp1 = temp1->next;

                printf("牌照为 %s 的汽车从便道中进入停车位的 %d 车位\n", temp1->car.plate, p_stopping->top);
                strcpy(p_stopping->Stop[++(p_stopping->top)].plate, temp1->car.plate);

                t = (long long)time(&t1); // 记录进入停车场的时间

                p_stopping->Stop[p_stopping->top].timeIn = t;

                free(temp1);
                temp2->next = NULL;
            }
        }
    }
}

void car_leave(Pavement *p_pavement, Stopping *p_stopping, Buffer *p_buffer, Car *p_car, int price, int max_pave, int max_stop) // 车离开
{
    char buf[0x100] = { 0 }; // 用于缓存字符
    char ch;


    printf("请输入即将离开的车牌号:\t");

#ifdef __GNUC__
    while ((ch = getchar()) != '\n'&&ch != EOF); // 清空输入流流,防止数据污染
#endif // __GNUC__

    fgets(buf, 0x100, stdin); // 防止溢出
    buf[strlen(buf) - 1] = '\0';
    setbuf(stdin, NULL); // 清空输入流流,防止输入流溢出

    if (p_stopping->top < 0) // 判断停车位是否有车辆信息
    {
        printf("车位已空,无车辆信息!\n");
    }
    else
    {
        stop_to_buff(p_pavement, p_stopping, p_buffer, p_car, buf, price, max_pave, max_stop);
    }
}

void Display(Stopping *p_stopping, int price)
{
    int i;
    int count;
    time_t t1;
    long int t;

    i = p_stopping->top;
    count = 1;

    if (-1 == i)
    {
        printf("停车场为空\n");
    }

    t = time(&t1); // 标记显示时的时间

    while (i != -1)
    {
        printf("%d:\n", count);
        printf("\t车牌号:\t%s\n", p_stopping->Stop[i].plate);
        printf("\t停放时间:\t%lld秒\n", t - p_stopping->Stop[i].timeIn);
        printf("\t当前所需支付金额:\t%lld元\n", price * (t - p_stopping->Stop[i].timeIn) / 10);
        puts("");
        i--;
        count++;
    }
}