10.数据结构学习4.0
1、队列的顺序存储
1、定义:分配一块连续的存储单元存放队列中的元素,并附设两个指针:队头指针front指向对头元素,队尾指针rear指向队尾元素的下一个位置;
#define MaxSize 50 //定义队列中元素的个数
typedef struct{
ElementType data[MxSize];//存放队列元素
int front,rear;//队头指针,队尾指针
}SqQueue;
2、循环队列:将顺序队列臆造成一个环状的空间,即把存储队列元素的表从逻辑上视为一个环,称为循环队列。
struct Queue
{
ElementType data[Max];
int front,rear;
//int len;//记录数组长度
//ElementType FrontData;//记录出队的元素
//int flag;设置标志位记录当前是否插入了元素
};
3、循环队列的初始化:
int InitQueue(struct Queue *q)
{
q->front = 0;
q->rear = 0;
}
4、判断队满还是队空的三种处理方法
【1】、牺牲一个单元来区分队空和队满,入对时少用一个队列单元,约定以对头指针在队尾指针的下一位置作为队满的标志;
队满条件:(Q.rear+1)%MaxSize == Q.front
队空条件:Q.rear == Q.front
队列中元素的个数:(Q.rear-Q.front+MaxSize)%MaxSize
//判断队空
bool IsEmpty(SqQueue Q)
{
if(Q.rear == Q.front)
{
return true
}
else
{
return false;
}
}
【2】、类型中增设元素个数的数据成员len
。这样队空的条件为Q.len==0
;队满的条件为Q.len == MaxSize
。
【3】、类型中增设 flag
数据成员,以区分是队满还是队空。flag == 0
时,若因删除导致Q.front == Q.rear
,则队空;flag == 1
的时候,若因插入导致Q.front == Q.rear
,则队满。
5、入队
void Push(struct Queue *q,ElementType element)
{
if(Q.rear+1)%MaxSize == Q.front)
{
printf("The queue is full!\n");
return ;
}
q->data[q->rear] = element;
q->rear++;
q->rear = q->rear%MaxSize;
q->len++;
}
6、出队
ElementType* Pop(struct Queue *q)
{
if(q->rear == q->front)
{
printf("The queue is empty!\n");
return ;
}
q->FrontData = q->data[q->front];
q->len--;
q->front++;
q->front = q->front%Max;
return &q->FrontData;
}
2、栈和队列的相互转换
- 两个栈实现一个队列
#include<stdio.h>
#include"LinkStack.h"//自己封装的栈头文件,在数据结构学习3.0中有相关代码
#define true 1
#define false 0
struct Queue
{
LStack inputStack;//初始化两个栈用来模拟入队、出队
LStack outputStack;
};
//对队列的初始化就是对两个栈分别进行初始化
int InitQueue(struct Queue *q)
{
Init
tack(&q->inputStack);
InitStack(&q->outputStack);
return true;
}
//判断队列是否为空
int IsStackQueueEmpty(struct Queue *q)
{
if(IsEmpty(&q->inputStack) == true && IsEmpty(&q->outputStack) == true)
{
return true;
}
else
{
return false;
}
}
//入队列,判断哪个队列有数据将当前元素压入栈
void StackQueuePush(struct Queue *q,ElementType element)
{
while(IsEmpte(&q->outPutStack) == false)
{
Push(&q->inputStack,*Pop(&q->outputStack));
}
Push(&q->inputStack,element);
}
//出队列,将一个有数据的栈里n个数据转移到另一个栈中,然后弹出栈顶元素
ElementType* StackQueuePop(struct Queue *q)
{
if(IsStackQueueEmpty(q) == true)//判断当前模拟队列是否为空,即为两个栈是否为空
{
printf("Queue is Empty!\n");
return NULL;
}
while(IsEmpty(&q->inputStack) == false)
{
Push(&q->outputStack,*Pop(&q->inputStack));
}
return Pop(&q->outputStack);
}
int main()
{
struct Queue queue;
InitQueue(&queue);
for(int i=0;i<10;i++)
{
StackQueuePush(&queue,i+1);//模拟入栈
}
while(IsStackQueueEmpty(&queue) == false)
{
printf("%d ",*StackQueuePop(&queue));//模拟出栈
}
return 0;
}
//输出结果1 2 3 4 5 6 7 8 9 10
- 两个队列实现一个栈
算法思想:因为队列的操作是先进先出,所以对于队列来说,实现模拟栈的出栈操作,需要设置两个队列,如果当前队列中有数据,即将当前队列中的前n-1个数据转移到另一个队列中,然后输出剩余的最后一个元素。模拟栈的入栈操作,只需要将所在的元素入队即可。
#include<stdio.h>
#include"Queue.h"//自己封装的队列头文件,在数据结构学习3.0中有相关代码
#define true 1
#define false 0
//定义一个栈的结构体,用两个队列进行模拟
struct Stack
{
LQueue queue1;
LQueue queue2;
};
//初始化一个栈,分别对两个队列进行初始化
int InitQueueStack(struct Stack *s)
{
InitLQueue(&s->queue1);
InitLQueue(&s->queue2);
return true;
}
//判断队列是否为空
int IsQueueStackEmpty(struct Stack *s)
{
if(s->queue1.queue.len == 0&& s->queue2.queue.len == 0)
{
return true;
}
else
{
return false;
}
}
//模拟入队,哪个栈中有元素将那个元素入栈
void QueueStackPush(struct Stack *s,ElementType element)
{
if(IsQEmpty(s->queue1) == true)
{
QPush(&s->queue2,element);
}
else
{
QPush(&s->queue1,element);
}
}
//模拟出队,哪个栈中有元素将该栈中的前n-1个转移到另一个栈中,然后弹出栈顶元素
ElementType* QueueStackPop(struct Stack *s)
{
if(IsQEmpty(&s->queue1) == true)
{
while(s->queue2.queue.len>1)
{
QPush(&s->queue1,*QPop(&s->queue2));
}
return QPop(&s->queue2);
}
if(IsQEmpty(&s->queue2) == true)
{
while(s->queue1.queue.len>1)
{
QPush(&s->queue2,*QPop(&s->queue1));
}
return QPop(&s->queue1);
}
}
int main()
{
struct Stack s;
InitQueueStack(&s);
for(int i=0;i<10;i++)
{
QueueStackPush(&s,i+1);
}
while(IsQueueStackEmpty(&s) == false)
{
printf("%d ",*QueueStackPop(&s));
}
printf("\n");
return 0;
}
//输出结果10 9 8 7 6 5 4 3 2 1
3、栈和队列的实际应用
问题描述:设停车场只有一个可停放几辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达的先后依次排序,若停车场内已经停满几辆汽车,则后来的汽车只能在门外的便道上等候,一旦停车场内有车开走,则排在便道上的第一辆车即可进入;当停车场内某辆车要离开的时候,由于停车场是狭长的通道,在它之后开入的车辆必须先退出车场为它让路,待该辆车开出大门后,为它让路的车辆再按原次序进入车场。在这里假设汽车不能从便道上开走。
基本要求:
以栈模拟停车场,以队列模拟车场外的便道,按照从终端输入数据序列进行模拟管理,每一组输入数据包括三个数据项:汽车”到达“或”离去“信息、汽车牌照号码以及达到或离去的时刻。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出车辆在停车场或便道上的停车位置;若是车辆离去,则输出车辆在停车场内停留的时间和应该缴纳的费用(在便道上停留的时间不收费)。
#include<stdio.h>
#include<stdlib.h>
#include"LinkStack.h"//自定义的链栈
#include"Queue.h"//自定义的队列
#include"MyString.h"
#define Max_Size 3 //定义停车场最大容量
#define true 1
#define false 0
struct Car
{
MyString name;//记录车牌号
double arriveTime;//记录到达时间
double leaveTime;//记录离开时间
};
struct Car* CreateCar(const char *name,double arriveTime)
{
//申请一个车的结构体对象
struct Car* newCar = (struct Car*)malloc(sizeof(struct Car));
if(newCar == NULL)
{
printf("Create malloc error!\n");
return NULL;
}
Initialize(&newCar->name,name);//对车牌号用MyString字符串的初始化函数进行初始化
newCar->arriveTime = arriveTime;
return newCar;
}
void FreeCar(struct Car* car)
{
if(car == NULL)//判断要操作的对象是否为空
{
return ;
}
FreeMyString(&car->name);//释放车牌号,因为车牌号是在堆上申请的字符串类型,所以用自定义的字符串释放函数
free(car);//释放小车
}
void Come_car(LStack *CarStop,LQueue *pavement)
{
char CarName[100] = {0};
double arriveTime =0.0;
printf("请输入车牌号: ");
scanf("%s",CarName);
printf("请输入到达的时间: ");
scanf("%lf",&arriveTime);
struct Car* newCar = CreateCar(CarName,arriveTime);
if(newCar == NULL)
{
printf("没有车达到!\n");
return;
}
if(CarStop->stack.len < Max_Size)//判断当前停车场是否还有空位
{
Push(CarStop,newCar);//将车压入栈中
printf("当前停车场未满,车辆 |%s| 停在停车场第 %d 号车位!\n",newCar->name.String,CarStop->stack.len);
}
else//没有位置则将车子停入便道
{
QPush(pavement,newCar);
printf("当前停车场已满,车辆 |%s| 停在了便道的第 %d 号车位!\n",newCar->name.String,pavement->queue.len);
}
}
//车辆离开
void Leave_car(LStack *CarStop,LQueue *pavement)
{
char CarName[100] = {0};
printf("请输入要离开的车牌号: ");
scanf("%s",CarName);
Init_MyString(LeaveCarName,CarName);//初始化车辆名字
LStack TempStack;//申请一个临时栈用来存放开出去的车
InitLStack(&TempStack);//初始化临时栈
double LeaveCarTime = 0.0;//记录离开时间
while(IsEmpty(CarStop) == false)//当停车场有车的时候
{
//申请一个变量记录弹出的车辆
struct Car *car=(struct Car*)*Pop(CarStop);
if(car->name.isEqual(&car->name,&LeaveCarName) == true)//判断当前车牌号和要离开的车牌号是否相同
{
printf("请输入汽车要离开的时间: ");
scanf("%lf",&car->leaveTime);//键入离开时间
LeaveCarTime = car->leaveTime;
printf("\n");
printf("车辆|%s|将要离场,到达时间是%lf,离开时间是%lf,停车费用为%lf\n",car->name.string,car->arriveTime,car->leaveTime,(car->leaveTime-car->arriveTime)*5);
FreeCar(car);//释放小车变量
break;
}
Push(&TempStack,car);//和要找的车牌号不相同,则将车压入临时栈
}
while(IsEmpty(&TempStack) == false)//将进入临时栈的小车重新返回
{
Push(CarStop,*Pop(&TempStack));//将临时栈中的元素重新返回停车场
}
if(CarStop->stack.len<Max_Size)//当停车场有空位将便道上的车压入停车场
{
if(IsQEmpty(pavement) == false)//判断便道上是否有车
{
//设置一个临时变量用来记录从便道队列中弹出的元素
struct Car *car=(struct Car*)*QPop(pavement);
car->arriveTime = LeaveCarTime;
Push(CarStop,car);//将小车压入停车场栈中
printf("便道上的车|%s|进入了停车场,时间为%lf\n",car->name.string,car->arriveTime);
}
}
else
{
printf("未找到输入的车牌!\n");
}
}
//显示停车场中车辆信息
void DisplayCarStop(LStack *carStop)
{
printf("----------------------------------------------------\n");
Node *TravelPoint = carStop->stack.head;
while(TravelPoint != NULL)
{
struct Car *car=(struct Car*)TravelPoint->data;
printf("车牌:|%s| 到达时间:%lf\n",car->name.string,car->arriveTime);
TravelPoint = TravelPoint->next;
}
printf("\n");
printf("----------------------------------------------------\n");
}
//显示便道中车辆信息
void DispalyPavement(LQueue *pavement)
{
printf("----------------------------------------------------\n");
Node *TravelPoint = pavement->queue.head;
while(TravelPoint != NULL)
{
struct Car *car=(struct Car*)TravelPoint->data;
printf("车牌:|%s| 到达时间:%lf\n ",car->name.string,car->arriveTime);
TravelPoint = TravelPoint->next;
}
printf("\n");
printf("----------------------------------------------------\n");
}
int main()
{
LStack carStop;
InitLStack(&carStop);
LQueue pavement;
InitLQueue(&pavement);
int choice=0;
while(1)
{
printf("~~~~~~~~~~~~~~~~carStop~~~~~~~~~~~~~~~~\n");
printf("1、车辆进入停车厂\n");
printf("2、车辆离开停车厂\n");
printf("3、显示停车场信息\n");
printf("4、显示便道信息\n");
printf("5、退出系统\n");
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
scanf("%d",&choice);
switch (choice)
{
case 1:
Come_Car(&carStop,&pavement);
break;
case 2:
Leave_car(&carStop,&pavement);
break;
case 3:
DisplayCarStop(&carStop);
break;
case 4:
DispalyPavement(&pavement);
break;
case 5:
Node *TravelPoint = pavement.queue.head;
while(TravelPoint != NULL)
{
struct Car *car=(struct Car*)TravelPoint->data;
FreeCar(car);
TravelPoint = TravelPoint->next;
}
FreeQueue(&pavement);
TravelPoint = carStop.stack.head;
while(TravelPoint != NULL)
{
struct Car *car=(struct Car*)TravelPoint->data;
FreeCar(car);
TravelPoint = TravelPoint->next;
}
FreeStack(&carStop);
return 0;
default:
break;
}
}
return 0;
}