数据结构栈和队列(五)栈的顺序存储结构和链式存储结构的实现

版权声明: https://blog.csdn.net/weixin_42442713/article/details/80959873

一、 实验目的

1. 熟悉栈的特点(先进后出)及栈的抽象类定义;

2. 掌握栈的顺序存储结构和链式存储结构的实现;

3. 熟悉队列的特点(先进先出)及队列的抽象类定义;

4. 掌握栈的顺序存储结构和链式存储结构的实现;

二、实验要求

1. 复习课本中有关栈和队列的知识;

2. C++语言完成算法和程序设计并伤及调试通过;

三、实验题目与要求

1. 停车场问题——栈和队列的应用

【问题描述】设停车场是一个可停放 n 辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端)。若停车场内已经停满 n辆车,那么后来的车只能在门外的便道上等候。一旦有车开走,则排在便道上的第一辆车即可开入。当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其他车辆再按原次序进入车场。每辆停放在车场的车在它离开停车场时必须按它停留的时间长短缴纳费用。试为停车场编制按上述要求进行管理的模拟程序。

【基本要求】以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入数据的序列进行模拟管理。每一组输入数据包括三个数据项:汽车的“到达”(‘A’表示)或“离去”(‘D’表示)信息、汽车标识(牌照号)以及到达或离去的时刻。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出汽车在停车场内或者便道上的停车位置;若是车辆离去,则输出汽车在停车场停留的时间和应缴纳的费用(便道上停留的时间不收费)。栈以顺序结构实现,队列以链表结构实现。

【输入输出】

① 初始,显示提示信息:“请输入停车场最大容量n=:”,提示用户输入停车场最大容量。

② 输入车辆信息:提示请输入车辆信息,提示用户输入车辆信息(“到达”或者“离开”,车牌编号,到达或者离开的时间),输入值的格式为:第一个必须为字母,后两个为数字,中间用逗号隔开。有以下几种情况:

③ 若车辆信息为“到达A”,车辆信息开始进栈(模拟停车场),当栈满,车辆会进队列(模拟停车场旁便道)。

④ 若车辆信息为“离开D”,会显示该车进入停车场的时间以及相应的停车费用,若该车较部分车早进停车场,这部分车需先退出停车场,暂时进入一个新栈为其让道,当待离开车离开停车场后,这部分车会重新进入停车场,同时便道上的第一辆车进入停车场。

⑤ 若输入(‘P’,0,0),会输出显示停车场的车数。

⑥ 若输入(‘W’,0,0),会输出显示便道上的车数。

⑦ 若输入(‘E’,0,0),程序会跳出循环,同时程序结束。

⑧ 用户每输入一组数据,程序就会根据相应输入给出输出。

【测试用例】

 

【算法分析】


【实现步骤】

(1) 步骤一:创建一头文件park.h,定义数据的结构及函数的声明

① 数据的表示

车辆信息的表示——表示汽车的状态(‘A’表示到达,‘D’表示离开)、车号、时间(到达或离开)

 

l 程序以顺序栈模拟停车场以及临时停放为给要离去的汽车让路而从停车场退出来的汽车的场地,以链表队列模拟车场外的便道,因此需要栈和队列这两个抽象数据类型。

 

上图为栈的结构定义,其中data数组存储栈元素信息,即车辆信息,top表示栈顶,MaxSize表示栈的最大容量。

 

上图为链队列结点的结构定义,其中data为结点的数据域,next为结点的指针域,以及链队列结构定义,包括队头指针front,及队尾指针rear,及队列元素总个数num。

② 数据的操作

声明以下函数

 

 

(2) 步骤二:创建文件park.cpp,实现park.h声明的函数

l 初始化栈

 

l 判断栈是否为空

 

 

l 其它函数请自行完成(可参考书P81P100

(3) 步骤三:创建文件main.cpp,完成主函数(在横线上补充合适的代码)

 

 

   


 


2. 表达式计算问题——栈的应用

利用栈将中缀表达式转成后缀表达式,并栈利用对转化后的后缀表达式求值(设计性实验),假设操作数均为整数。

           中缀表达式                      后缀表达式

            a*b+c                            ab*c+

            a+b*c                            abc*+

            a+(b*c+d)/e                     abc*d+e/+

例如计算后缀表达式4 3 5 * +   即计算 4+3*5

应输出结果 19

实现提示

中缀表达式转成后缀表达式算法思想:

1. 首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入后缀表达式的栈S2(空栈),S1栈可先放入优先级最低的运算符#。

2. 从中缀表达式的左端开始取字符,逐序进行如下步骤:     

Ø 若取出的字符是数字,则分析出完整的操作数,将该操作数直接送入S2栈  

Ø 若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。

Ø 若取出的字符是“(”,则直接送入S1栈栈顶。

Ø 若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。

Ø 重复上面的1~4步,直至处理完所有的输入字符。

Ø 若取出的字符是'\0',则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。     

完成以上步骤,S2栈便为后缀表达式输出结果,但需要对S2的内容进行逆序。因此,S2也可考虑用队列。

对已转化的后缀表达式求值步骤:

1. 若表达式输入未完毕,读入一个字符

2. 若是操作数,压入栈,转1

3. 若是运算符,从栈中弹出2个数,将运算结果再压入栈

4. 若表达式输入完毕,栈顶即所求表达式的值;

数与数之间采用空格进行分隔,若读到数字字符直到遇到空格,则将所有数字字符凑好形成操作数。

 下面附上完整代码:

头文件park.h


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#pragma warning(disable:4996)
using namespace std;
#define price 0.1 //车费 0.1元/分
typedef struct time{
	int hour;
	int min;
}Time;//时间结点

typedef struct node{
	char num[10];//车牌
	Time reach;//到达
	Time leave;//离去
}CarNode;//车辆信息结点

typedef struct{
	CarNode *elem;
	int top;  //top=-1为空栈
}SeqStackCar;   //顺序栈 模拟停车场

typedef struct car{
	CarNode data;   //数据域
	struct car *next;//指针域
}QueueNode;   //链队列结点

typedef struct{
	QueueNode *front;//头指针
	QueueNode *rear;//尾指针
}LinkQueue; //链队列  模拟停车便道

void InitStack(SeqStackCar *s,int n);//初始化停车场栈道
void In(SeqStackCar *s, CarNode x,int n);//进栈
void Out(SeqStackCar *s, CarNode *x);//出栈
void GetTop(SeqStackCar *s, CarNode *x);//获取栈顶

void InitQueue(LinkQueue *q);//初始化停车便道
void Enter(LinkQueue *q, CarNode x);//入队
void Delte(LinkQueue *q, CarNode *x);//出队

void Arrive(SeqStackCar *s, LinkQueue *q,int n);//车辆到达
void Leave(SeqStackCar *s, LinkQueue *p,int n);//车辆离开

void PrintfSeq(SeqStackCar *s);//打印停车场内车辆的信息
void PrintfQue(LinkQueue *q);//打印便道内车辆的信息

2. park.cpp(实现park.h声明的函数)

#include"park.h"
void InitStack(SeqStackCar *s,int n)
{
	s->elem = new CarNode[n];
	s->top = -1;
}
void In(SeqStackCar *s, CarNode x,int n)
{
	if (s->top == n- 1) return;
	s->top++;
	s->elem[s->top] = x;
}
void Out(SeqStackCar *s, CarNode *x)
{
	if (s->top == -1) return;
	else
	{
		*x = s->elem[s->top]; 
		s->top--;
	}
}
void GetTop(SeqStackCar *s, CarNode *x)
{
	if (s->top == -1) return;
	else *x = s->elem[s->top];
}
void InitQueue(LinkQueue *q)
{
	q->front = q->rear = (QueueNode *)malloc(sizeof(QueueNode));
	q->front->next = NULL;
}
void Enter(LinkQueue *q, CarNode x)
{
	QueueNode *newnode;
	newnode = (QueueNode *)malloc(sizeof(QueueNode));
	if (newnode != NULL)
	{
		newnode->data = x;
		newnode->next = NULL;
		q->rear->next = newnode;
		q->rear = newnode;
	}
	else return;
}
void Delte(LinkQueue *q, CarNode *x)
{
	QueueNode *s;
	if (q->front == q->rear) return;
	s = q->front->next;
	q->front->next = s->next;
	if (q->rear == s)
		q->rear = q->front;
	*x = s->data;
	free(s);
}
void Arrive(SeqStackCar *s, LinkQueue *q,int n)//s停车场,q便道
{
	CarNode p;
	if (s->top == n - 1)
	{ 
		printf("停车场已满,请将车停往免费便道等候!\n");
		printf("车正在进入免费便道,请录入车辆信息!\n");
		printf("车辆车牌:");
		scanf("%s", &p.num);
		Enter(q, p);
		printf("车辆已停入便道!\n");
	}
	else
	{
		printf("车正在进入停车场,请录入车辆信息!\n");
		printf("车辆车牌:");
		scanf("%s", &p.num);
		printf("进入的时间(x时x分):");
		scanf_s("%d %d", &p.reach.hour,&p.reach.min);
		printf("该车进入的时间为:%d:%d\n",p.reach.hour,p.reach.min);
		In(s, p,n);
		printf("该车辆停在车场的第%d位置上.\n", s->top+1);
	}
}
void Leave(SeqStackCar *s, LinkQueue *q,int n)
{
	CarNode p;
	SeqStackCar w;//临时栈,存放让路的车辆
	InitStack(&w,n);//初始化临时栈
	int i;
	double free;
	printf("离开车辆的车牌为:");
	scanf("%s", &p.num);
	for (i = 0; i <= s->top; i++)
	{
		if (strcmp(p.num,s->elem[i].num)==0)  //查找离开的车辆在停车场中的位置,返回i
		{
			printf("该车辆在停车场的第%d位置上.\n", i+1);
			printf("输入该车辆离开的时刻(x时x分):");
			scanf_s("%d %d", &s->elem[i].leave.hour, &s->elem[i].leave.min);
			printf("该车离开的时间为:%d:%d\n",s->elem[i].leave.hour, s->elem[i].leave.min);
			free = ((s->elem[i].leave.hour * 60 + s->elem[i].leave.min) - (s->elem[i].reach.hour * 60 + s->elem[i].reach.min))*price;
			printf("该车辆改收取的停车费用为%.2f元:\n", free);
			while (s->top != i)  //有车辆离开时,后面的车依次出栈,进入临时栈w,
			{
				CarNode x;
				Out(s, &x); //从模拟停车场出栈
				In(&w, x,n);//进入临时栈
			}
			s->top--;
			while (w.top > -1) //该车离开后,再让临时栈w停放的车进停车场栈s
			{
				CarNode y;   
				Out(&w, &y);
				In(s, y,n);
			}
			//有空位了,便道的第一辆车可进停车场
			if (q->front == q->rear)
				printf("便道内无停车,没车需进停车场!\n");
			else
			{
				CarNode c;
				Delte(q, &c);
				printf("车正在进入停车场,请录入车辆信息!\n");
				printf("车辆车牌:%s\n", c.num);
				printf("进入的时间(x时x分):");
				scanf_s("%d %d", &c.reach.hour, &c.reach.min);
				printf("该车进入的时间为:%d:%d\n",c.reach.hour, c.reach.min);
				In(s, c,n);
				printf("该车辆停在车场的第%d位置上.\n", s->top+1);
			}
		}
	}
}

void PrintfSeq(SeqStackCar *s)//打印停车场内车辆的信息
{
	if (s->top == -1)
		printf("停车场内为无停车!\n");
	else
	{
		printf("===============停车场内车辆信息如下===============\n");
		for (int i = 0; i <= s->top; i++)
		{
			printf("%d号车辆:车牌:%s\t进入时间:%d:%d\n", i+1, s->elem[i].num,s->elem[i].reach.hour,s->elem[i].reach.min);
		}
		printf("==================================================\n");
	}
}
void PrintfQue(LinkQueue *q)//打印免费便道内车辆的信息
{
	int i = 1;
	QueueNode *temp = q->front->next;
	if (q->front == q->rear)
		printf("免费便道内无停车!\n");
	else
	{
		printf("====免费便道内车辆信息如下====\n");
		while (temp!=NULL)
		{
			printf("\t%d号车辆:车牌:%s\n", i,temp->data.num);
			i++;
			temp = temp->next;
		}
		printf("==============================\n");
	}
}

3. main.cpp(程序入口)

#include"park.h"
void menu();//菜单
int main()
{
	int n;
	printf("请输入停车场的容量:");
	scanf("%d",&n);
	printf("停车能容纳%d辆车\n",n);
	system("pause");
	SeqStackCar S;
	LinkQueue Q;
	InitStack(&S,n);
	InitQueue(&Q);
	int userchoice;
	do{
		menu();
		scanf_s("%d", &userchoice);
		switch (userchoice)
		{
		case 0:break;
		case 1:Arrive(&S, &Q, n); break;
		case 2:Leave(&S, &Q, n); break;
		case 3:PrintfSeq(&S); break;
		case 4:PrintfQue(&Q); break;
		}
		system("pause");
	} while (userchoice != 0);
	return 0;
}
void menu()
{
	system("cls");
	printf("\t停车场系统\n\n\t0.退出\n\t1.车辆到达\n\t2.车辆离开\n\t3.打印停车场车辆信息\n\t4.打印便道车辆信息\n\n请输入你的选择:");
}

二、表达式计算问题
#include <iostream>
#include <string>
#include <cstdio>
#include <stack>
#include <queue>
#include <map>
using namespace std;

const char oper[] = { ' ', '(', '+', '-', '*', '/', ')'};

bool isNum(char &ch) {
	if (ch >= '0' && ch <= '9') return true;
	return false;
}

int main(void) {
	map<char, int> mp; /*运算符与优先级的映射*/
	for (int i = 0; oper[i]; i++) {
		mp[oper[i]] = i;
	}
	char str[110];
	stack<char> ope; /*中缀转后缀暂存操作数栈*/
	queue<char> que; /*中缀转后缀暂存后缀表达式队列*/
	string PostFixExp;  /*保存后缀表达式*/
	stack<int> ss;   /*后缀表达式计算暂存操作数栈*/
	std::cout<<"输入算术表达式"<<endl;
	while (gets_s(str)) {
		for (int i = 0; str[i]; i++) {
			if (isNum(str[i])) {
				que.push(str[i]);/*如果是操作数是进队*/
			}
			else {
				que.push(' ');/*如果是操作符则先将空格进队,目的是用空格隔开操作数*/
				if (str[i] == '(') {
					ope.push(str[i]);/*左括号直接进队*/
					continue;
				}
				if (str[i] == ')') {
					while (ope.top() != '(') {
						que.push(ope.top());
						ope.pop();
					}
					ope.pop();
					continue;
				}
				while (!ope.empty() && ope.top() != '(' && mp[str[i]] <= mp[ope.top()]) {
					que.push(ope.top());
					ope.pop();
					
				}
				ope.push(str[i]);
			}
		}
		while (!ope.empty()) {
			que.push(ope.top());
			ope.pop();
		}
		while (!que.empty()) {
			if (isNum(que.front())) {
				int num = 0;
				while (isNum(que.front())) {
					num = num * 10 + que.front() - '0';
					PostFixExp+=que.front();
					que.pop();
				}
				ss.push(num);
 			}
			else {
				PostFixExp+=que.front();
				if (que.front() == '+') {
					int num2 = ss.top(); ss.pop();
					int num1 = ss.top(); ss.pop();
					ss.push(num1 + num2);
				}
				else if (que.front() == '-') {
					int num2 = ss.top(); ss.pop();
					int num1 = ss.top(); ss.pop();
					ss.push(num1 - num2);
				}
				else if (que.front() == '*') {
					int num2 = ss.top(); ss.pop();
					int num1 = ss.top(); ss.pop();
					ss.push(num1 * num2);
				}
				else if (que.front() == '/') {
					int num2 = ss.top(); ss.pop();
					int num1 = ss.top(); ss.pop();
					ss.push(num1 / num2);
				}
				que.pop();
			}
		}
		cout<<"后缀表达式为"<<PostFixExp<<"=";
		cout  << ss.top() << endl;
	}
}

举例:

(12+133)*10-340

读完字符串,队列的情况

空格

1

2

空格

1

3

3

空格

+

空格

1

0

空格

*

3

4

0

-




 

阅读更多

扫码向博主提问

小木铲

非学,无以致疑;非问,无以广识
去开通我的Chat快问

没有更多推荐了,返回首页