【数据结构与算法】栈的应用——表达式求值

前言:
我想了一下,我主要写博客的目标还是说为了自己,自己容易忘记,相当于自己来过一遍,所以这是写给我自己的,当然如果你也遇到了相同的问题,那么不防我们可以一起探讨一下.

一.表达式求值是什么?

表达式就是有加减乘除的式子,与正常的不同,我们这里用的是字符串的形式,来求其答案.
列如:
在这里插入图片描述
下面我们将用栈的形式来求其解.

二.表达式求值怎么做?

1.实现原理

对于字符串表达式,我们可以分为左操作数,运算符,右操作数.
我们可以将操作数放入一个栈中,运算符放入另外一个栈中.
然后通过运算符的优先级来进行计算.
计算的时候,我们要先出栈,然后进行计算,然后再将计算的结果入栈进行下次的计算.

2.栈实现

因为要使用栈来装操作数和运算符,那么我们先来创建栈.
可以将其作为头文件,我们需要用的时候引用一下头文件即可.

①.栈结构

在这里插入图片描述
用的两个指针来实现,一个分配内存,一个指向栈顶的下一个位置.

②.栈初始化

在这里插入图片描述
一个指针分配内存,另外一个指针指向分配好的位置.

③.入栈

在这里插入图片描述
在栈顶位置插入值,再移动到下一个位置.

④.出栈

在这里插入图片描述
直接对栈顶位置移动到上一个位置.

⑤.获取栈顶元素

在这里插入图片描述
栈顶指针减一个位置.

⑥.栈是否为空

在这里插入图片描述
如果两指针指向同一个位置则为空.

然后就可以实现我们的栈了,我们先初始化两个栈.
在这里插入图片描述

3.左操作数

字符串的第一个数肯定就是左操作数,所以status我们赋值为0.
在这里插入图片描述
首先对每个字符串进行循环拿取,isspace可以检验字符串的空格,我们可以跳过.

如果碰到了数字,那么我们可以用字符-'0’可以得到数值.
如果不是一位数的数字,我们需要*10再加上后面的,可以得到我们的操作数.

如果碰到了运算符,那么我们先将刚刚的数值入栈,然后改变状态,i–重新对运算符进行操作.

4.运算符

①.+,-,*,/

遇到第一个运算符不需要做任何操作,只需要入栈,然后改变状态,拿到右操作数.
在这里插入图片描述
如果已经不是第一个入栈的运算符了,那么我们需要比较优先级
如果这个运算符的优先级比栈顶的高,那么也只需要入栈就可以了.
因为12+3*6你不可能先算12+3.
在这里插入图片描述

如果优先级不高于前一个运算符
那么我们可以取出两操作数和一个运算符进行计算.
在这里插入图片描述
将运算的结果还是需要入栈,我们的循环条件是如果运算符栈不为空,同时当前运算符的优先级不高于前一个,那么可以继续进行计算.
如12+36+,36的结果放入栈中因为后面还是加号,还是可以继续进行计算12+18+
当不能进行计算后再将这个符号放入栈中.同时去拿右操作数.
在拿下一个右操作数时,需要将上一次的右操作数清零.

②.=

在这里插入图片描述
如果遇到=,那么我们可以出栈进行计算,循环的条件只需要,运算符不为空就可以继续进行计算了.

5.右操作数

在这里插入图片描述
与左操作数一样.

6.优先级比较

在这里插入图片描述
优先级高于的情况就是一个为*,/同时另一个为+,-,其他情况都是不高于.

7.运算结果

在这里插入图片描述

三.完整代码

#include <iostream>
#include "expression.h"
using namespace std;

bool isLarger(const int& lhs, const int& rhs)//rhs栈顶
{
	if ((rhs == '+' || rhs == '-') && (lhs == '*' || lhs == '/'))
	{
		return true;
	}
	return false;
}

int operate(int left, int right, int op)
{
	int result = 0;
	cout << "left:" << left << " right:" << right << "op:" << (char)op << endl;
	switch (op)
	{
	case '+':
		result = left + right;
		break;
	case '-':
		result = left - right;
		break;
	case '*':
		result = left * right;
		break;
	case '/':
		result = left / right;
		break;
	default:
		break;
	}
	cout << "result:" << result << endl;
	return result;
}

int calculate(string input)
{
	SqStack data_stack;//操作数栈
	SqStack opt_stack;//运算符栈
	int status = 0;//0左操作数,1运算符,2右操作数状态
	int ldata = 0;//左操作数值
	int rdata = 0;//右操作数值

	initStack(data_stack);
	initStack(opt_stack);

	for (int i = 0; i < input.length(); i++)
	{
		if (isspace(input[i]))continue;//跳过空格
		switch (status)
		{
		case 0:
			if (isdigit(input[i]))//碰到数值
			{
				ldata *= 10;//在原有的基础上*10
				ldata += input[i] - '0';//相加现在的
			}
			else//碰到操作符
			{
				cout << "得到左操作数:" << ldata << endl;
				PushStack(data_stack, ldata);//操作数入栈
				i--;//字符串回退一下
				status = 1;//交给操作符的处理
			}
			break;
		case 1:
			if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
			{
				if (isEmpty(opt_stack))//第一个操作符入栈
				{
					cout << "符号栈为空" << endl;
					PushStack(opt_stack, input[i]);//操作符入栈
					cout << "符号" << (char)(*GetTop(opt_stack)) << "入栈" << endl;
					status = 2;
				}
				else
				{
					cout << "isLarger:" << (char)(*GetTop(opt_stack)) << " &" << input[i] << endl;
					if (isLarger(input[i], *GetTop(opt_stack)))//当前运算符高于前一个,不能计算前一个运算符
					{
						cout << "true" << endl;
						PushStack(opt_stack, input[i]);//当前运算符入栈
						cout << "符号" << (char)input[i] << "入栈" << endl;
						status= 2;
						rdata = 0;
					}
					else//当前运算符的优先级不高于前一个运算符,则计算前一个运算符的值
					{
						int left = 0;
						int right = 0;
						int opt;
						cout << "false" << endl;
						do
						{
							PopStack(data_stack, right);
							PopStack(data_stack, left);
							PopStack(opt_stack, opt);
							cout << "符号" << (char)opt << "出栈" << endl;
							cout << "计算前一个运算符" << (char)opt << endl;
							int result = operate(left, right, opt);
							PushStack(data_stack, result);
						} while (!isEmpty(opt_stack)&&!isLarger(input[i],*GetTop(opt_stack)));

						PushStack(opt_stack, input[i]);
						cout << "符号" << (char)input[i] << "入栈" << endl;
						status = 2;
						rdata = 0;
					}
				}
			}
			else if (input[i] == '=')
			{
				int opt, result;
				do
				{
					PopStack(data_stack, rdata);
					PopStack(data_stack, ldata);
					PopStack(opt_stack, opt);
					result = operate(ldata, rdata, opt);
					PushStack(data_stack, result);
				} while (!isEmpty(opt_stack));
				return result;
			}
			else
			{
				cerr << "输入运算符错误!" << endl;
			}
			break;
		case 2:
			if (isdigit(input[i]))//碰到数值
			{
				rdata *= 10;//在原有的基础上*10
				rdata += input[i] - '0';//相加现在的
			}
			else//碰到操作符
			{
				cout << "得到右操作数:" << rdata << endl;
				PushStack(data_stack, rdata);//操作数入栈
				i--;//字符串回退一下
				status = 1;//交给操作符的处理
			}
			break;
		default:
			break;
		}
	}
}

int main()
{
	string str = "12+3*6/3+4*5=";
	cout << calculate(str) << endl;
	system("pause");
	return 0;
}

列子手绘图:
在这里插入图片描述
运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值