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