数据结构——队列

队列是一种重要的数据结构,它广泛应用于各种软件系统中,这两种数据结构与线性表有密切的联系。从逻辑上看,队列也属于线性结构,是一种特殊的线性表。其特殊性在队列的基本操作是线性表操作的子集,是限定仅在表尾进行插入或删除操作的线性表。队列是操作受限的线性表。

学习要点:

1.了解队列的概念。

2.掌握队列的数据结构定义方法和基本运算的实现方法。

3.能使用队列这种数据结构解决具体的问题。

队列的定义

队列和栈类似,也可以看成是一种运算受限的线性表。但栈是一种后进先出的数据结构,而队列是一种先进先出(First In First Out, FIFO)的数据结构,即插入在表一端进行,而删除在表的另一端进行。

1. 循环队列的实现

【问题描述】

通过具体的算法实现循环队列的初始化、入队、出队等基本运算操作。

【算法描述】

首先定义循环队列的最大容量和存储结构,然后通过分别编写相应的函数,如队列初始化、置空、数据元素的插入和删除等,然后通过主函数调用,来实现循环队列的各种运算。

代码实现:

#include <stdio.h>
/* 循环队列实现 */
#include <stdlib.h>
#include <malloc.h>
#include <string.h>


/* 队列中最大 100 个数据 */
#define QueueSize 100
typedef char DataType;
typedef struct queuenode
{
    int front; /* 队头 */
    int rear; /* 队尾 */
    int count; /* 队列长度 */
    DataType data[QueueSize];
}CirQueue;

void InitQueue(CirQueue * q)
{
    q->front = q->rear = 0;
    q->count = 0;
}

int QueueEmpty(CirQueue * q)
{
    return q->count==0;
}
int QueueFull(CirQueue * q)
{
    return q->count==QueueSize;
}
void EnQueue(CirQueue * q,DataType x)
{
    if (QueueFull(q))
    { printf("队列已空,不能出队…\n");
        exit(-1);
    }
    else
    {
        q->count++;
        q->data[q->rear]=x; /* 队尾插入数据 */
        q->rear=(q->rear+1)%QueueSize; /* 模运算 */
    }
}
DataType DeQueue(CirQueue * q)
{
    DataType x;
    if (QueueEmpty(q))
    {
        printf("队列已空,不能出队…\n");
        exit(-1);
    }
    x=q->data[q->front]; /* 队头出队 */
    q->count--;
    q->front=(q->front+1) % QueueSize;
    return x;
}
void Disp(CirQueue * p)
{
    int i;
    printf("=====================================\n");
    printf("队长:%d 队列数据为:\n",p->count);
    for (i=0;i<p->count;i++)
        printf("%d -> %c\n",i,p->data[i]);
    printf("=====================================\n\n");
}
DataType QueueFront(CirQueue * q)
{
    if (QueueEmpty(q))
    {
        printf("队列已空,不能出队…\n");
        exit(-1);
    }
    return q->data[q->front];
}
int main(void)
{
    CirQueue *q = malloc(sizeof(CirQueue));
    printf("============== 循环队列 DEMO ================\n\n");
    printf("q->front = %d, q->rear = %d, q->count = %d\n", q->front, q->rear, q->count);
    InitQueue(q);
    printf("q->front = %d, q->rear = %d, q->count = %d\n", q->front, q->rear, q->count);
    printf("a,b,c,d 入队后的队列:\n");
    EnQueue(q,'a');
    EnQueue(q,'b');
    EnQueue(q,'c');
    EnQueue(q,'d');
    Disp(q);
    printf("第一个出队数据:%c\n",DeQueue(q));
    printf("第二个出队数据:%c\n",DeQueue(q));
    printf("此时的队头数据:%c\n",QueueFront(q));
    free(q);
    return 0;
}

运行结果:

 

2. 停车场问题模拟

【问题描述】

设有一个可以停放 n 辆汽车的狭长停车场,它只有一个大门可以供车辆进出。车辆按到达停车场时间的早晚依次从停车场最里面向大门口处停放(最先到达的第一辆车放在停车场的最里面)。如果停车场已放满 n 辆车,则后来的车辆只能在停车场大门外的停车道上等待,一旦停车场内有车开走,则排在停车道上的第一辆车就进入停车场。停车场内如有某辆车要开走,在它之后进入停车场的车都必须先退出停车场为它让路,待其开出停车场后,这些车辆再依原来的次序进场。每辆车在离开停车场时,都应根据它在停车场内停留的时间长短交费。如果停留在停车道上的车未进停车场就要离去,按停留时间收取停车费,并且仍然保持在停车道上等待的车辆的次序。

【算法描述】

本题可用栈和队列来模拟实现。

1) 存储结构设计

模拟汽车到达或离去的输入数据格式可定义为:

(1) 车牌号码:字符串;

(2) 时间:数值;

(3) 动作:区分是“到达”还是“离去”;

(4) 约定:“A”表示到达,用“D”表示离开,“E”表示结束输入。

根据题目要求,停车场只有一个大门,因此可用一个栈来模拟,称为主栈。当停车场满后,后来的车辆只能停在停车道上,根据停车道停车的特点,可用一个队列来模拟(先排队的车辆先离开停车道,进入停车场)。而每当停车场中间的车辆离开时,要求大门到欲离开车辆之间的车辆必须先离开停车场,让此车辆离去,然后再依序进入停车场,为保存这些车辆的位置也需栈,称为辅助栈。因此本问题需要用到两个栈和一个队列。

2) 基本操作分析与定义

停车场的操作有车辆进入和离开。根据不同情况对应以下的基本操作:

(1) 车辆进入;

(2) 当主栈不满时,由主栈的入栈操作实现;

(3) 若主栈已满,对应队列的入队操作;

(4) 车辆离开。

当位于门口的车辆(用主栈的栈顶表示)离开时,对应主栈的出栈操作。

当中间车辆离开时的操作比较复杂,需要辅助栈和队列,步骤如下:

首先在主栈中查找车辆信息,若在主栈中,则循环进行车辆由主栈出栈,进入辅助栈的操作,直到该车辆对应的元素位于栈顶。

(1) 车辆出栈;

(2) 将辅助栈元素依次入主栈;

(3) 队列的对头元素出队;

(4) 对头元素进入主栈。

由此可见,停车场的基本操作可用队列和栈的基本操作实现。

注意:当停车场已没有车辆时,若输入数据仍要求车辆开出,则应显示错误信息。停车场的停车数量可以设定,即为主栈的大小未做说明时,认为停车道可以停放任意多的车辆。因此,栈结构可采用顺序存储结构,而队列宜采用链式队列。

代码实现:

#include <stdio.h>
#include <stdlib.h>
typedef struct{
    char car_action;
    /* A-车辆到达;D-车辆离开;E-结束标志 */
    int car_no;
    /* 车辆号 */
    int time_point;
    /* 车辆离开或到达的时间 */
    int cost;
    /* 停车费 */
}CarInfo;
typedef struct{
    int top;
    CarInfo *elements;
    int MaxSize;
}Stack;

void InitStack(Stack *b,int n) /* 初始化栈 */
{
    b->MaxSize=n;
    b->elements=(CarInfo*)malloc(b->MaxSize*sizeof(CarInfo));
    if(b->elements==NULL)
        printf("申请空间失败…\n");
    else
        printf("b->MaxSize = %d\n", b->MaxSize);
    b->top=-1;
}

int IsFull(Stack *b)
{
    if(b->top==(b->MaxSize-1)) return(1);
    else return(0);
}
int IsEmpty(Stack *b){
    if(b->top==-1) return(1);
    else return(0);
}
int Push(Stack *b,CarInfo *t){
    if(IsFull(b))
        return 0;
    b->top++;
    b->elements[b->top].car_action=t->car_action;
    b->elements[b->top].car_no=t->car_no;
    b->elements[b->top].time_point=t->time_point;
    b->elements[b->top].cost=t->cost;
    return 0;
}
CarInfo Pop(Stack *b){
    if(IsEmpty(b)){printf("栈为空\n");}
    else{
        return(b->elements[b->top--]);
    }
}
int SearchInStack(Stack *a,Stack *b,CarInfo *current_car,int park_cost)
{
    /* 在停车场中查找是否有离开车辆车号 */
    int find=0;
    int cost;
    CarInfo temp_info;
    while(!IsEmpty(a)&&!find)
    {
        temp_info=Pop(a);
        if(temp_info.car_no==current_car->car_no)
        {
            find=1;
            cost=(current_car->time_point-temp_info.time_point)*park_cost;
            temp_info.cost+=cost;
            cost=temp_info.cost;
        }
        else Push(b,&temp_info);
    }
    while(!IsEmpty(b))
    {
        temp_info=Pop(b);
        Push(a,&temp_info);
    }
    if(find==0) return(0);
    else return(cost);
}
typedef struct QNode{
    CarInfo data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
    QueuePtr front;
    QueuePtr rear;
    int num;
}Queue;

int InitQueue(Queue *Q)
{
    Q->front=(QueuePtr)malloc(sizeof(QNode));
    printf("InitQueue==========%p\n", Q->front);
    if(!Q->front)
        return 0;
    Q->front = Q->rear;
    printf("InitQueue==========%p\n", Q->front);
    Q->front->next=NULL;
    Q->num=0;
    return 1;
}
int EnQueue(Queue *Q,CarInfo *current_car)
{
    QueuePtr p;
    p=(QueuePtr)malloc(sizeof(QNode));
    if(!p) return(0);
    p->data.car_action=current_car->car_action;
    p->data.car_no=current_car->car_no;
    p->data.cost=current_car->cost;
    p->data.time_point=current_car->time_point;
    p->next=NULL;Q->rear->next=p;Q->rear=p;
    Q->num++;
    return 1;
}
CarInfo DeQueue(Queue *Q)
{
    CarInfo temp_car;
    QueuePtr p;
    if(Q->front==Q->rear) {printf("队列空\n");}
    else
    {
        p=Q->front->next;
        temp_car.car_action=p->data.car_action;
        temp_car.car_no=p->data.car_no;
        temp_car.cost=p->data.cost;
        temp_car.time_point=p->data.time_point;
        Q->front->next=p->next;
        if(Q->rear==p) Q->rear=Q->front;
        free(p);Q->num--;
        return(temp_car);
    }
}
int SearchInQueue(Queue *Q,CarInfo *current_car,int road_cost)
/* 在停车道中查找要离开的车 */
{
    int i=0,num;
    int find=0;
    int cost;
    CarInfo temp_car;
    num=Q->num;
    if (!num) {printf("队列为空");return(0);}
    while(i<num)
    {
        temp_car=DeQueue(Q);
        if(temp_car.car_no==current_car->car_no)
        {
            find=1;
            cost=temp_car.cost+(current_car->time_point-temp_car.time_point)*road_cost;
        }
        else
        {
            EnQueue(Q,&temp_car);
        }
        i++;
    }
    if(find) return(cost);
    else return(0);
}
void CarArrive(Stack *Park,Queue *Road,CarInfo car_info)
{
    if(IsFull(Park))
    {
        EnQueue(Road,&car_info);
        printf("车号为%d 的车辆进入停车道.\n",car_info.car_no);
    }
    else{
        Push(Park,&car_info);
        printf("车号为%d 的车辆进入停车场.\n",car_info.car_no);}
}
void CarLeave(Stack *a,Stack *b,Queue *Road,CarInfo car_info,int park_cost,
              int road_cost)
/* 当车辆离开时候判断 */
{ CarInfo temp_car;
    int temp_cost;
    if(temp_cost==SearchInStack(a,b,&car_info,park_cost))
    {
        printf("车号为%d的车辆离开停车场,停车费为:%d.\n",car_info.car_no,temp_cost);
        if(Road->num>0){
            temp_car=DeQueue(Road);
            temp_car.cost+=(car_info.time_point-temp_car.time_point)*road_cost;
            temp_car.time_point=car_info.time_point;
            Push(a,&temp_car);
            printf("车号为%d 的车辆从停车道进入停车场.\n",temp_car.car_no);}
    }
    else
        if(temp_cost=SearchInQueue(Road,&car_info,road_cost)){
            printf("车号为%d 的车辆离开停车道,停车费为:%d\n",car_info.car_no,temp_cost);}
        else{
            printf("对不起,您输入的信息无效, 请核对后重新输入.\n");}
}

int main()
{
    Stack Park,Aux_Park;
    Queue Road;
    int park_cost,road_cost,park_hold,temp_cost;
    CarInfo car_info,temp_car;
    printf("请输入停车场的单位时间停车费:");
    scanf("%d",&park_cost);
    printf("请输入停车道的单位时间停车费:");
    scanf("\n%d",&road_cost);
    printf("请输入停车场的容量:");
    scanf("\n%d",&park_hold);
    InitStack(&Park,park_hold);
    InitStack(&Aux_Park,park_hold);
    int ni = InitQueue(&Road);
    printf("ni=====%d\n", ni);
    printf("请输入车辆信息(到达离开或退出标志 A D 或 E,车牌号,当前时间):");
    scanf("\n%c,%d,%d",&car_info.car_action,&car_info.car_no,&car_info.time_point);
    car_info.cost=0;
    while(car_info.car_action!='e'&&car_info.car_action!='E')
    {
        switch(car_info.car_action)
        {case 'a':
        case 'A':CarArrive(&Park,&Road,car_info); break;
        case 'd':
        case
        'D':CarLeave(&Park,&Aux_Park,&Road,car_info,park_cost,road_cost);
            break;
        default: printf("对不起,您的输入有错误, 请核对后重新输入。\n");
        }
        printf("请输入车辆信息(到达离开或退出标志 A D 或 E,车牌号,当前时间):");
        scanf("\n%c,%d,%d",&car_info.car_action,&car_info.car_no,&car_info.time_point);
    }
    printf("感谢您使用本车库管理系统\n");

    return 0;
}


 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值