IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【栈】实现表达式求值(C++)(详解) -> 正文阅读

[C++知识库]【栈】实现表达式求值(C++)(详解)

【栈】实现表达式求值

思路 && 理解 && 注意

给定一串表达式,字符串类型,依次遍历从头开始遍历每一个位置的内容。

第一个数字,第一个运算符先直接往栈里面push(两个不同的栈)
接着走,遇到数push进来,接着走,遇到运算符,和前面那个已经push进栈的运算符进行优先级比较,如果当前运算符优先级大,那就接着push进来,反之,pop出栈,运算前面的式子之和(之后判断运算符栈中是否还有内容,并且当前运算符的优先级是否小于等于已有的运算符,小于等于就接着运算前面的表达式,完成push当前运算符,反之继续往下遍历push…pop…),直到最后一个元素。

注意;

一直发生变化的是rdata-右操作数,所以每次压完运算符找新的右操作数都会将他置空,准备重新赋值。

没有添加括号优先级运算。

expression.h

#pragma once
#include<iostream>
using namespace std;


#define MAX_SIZE 128

typedef struct _Postion//地图中点的坐标,这个栈中存的元素就是点的坐标
{
	int _x;
	int _y;
}Postion;

typedef int DataType;


//栈的结构体
typedef struct _Stack
{
	DataType* top;
	DataType* base;
}Stack;

//栈的初始化
bool initStack(Stack& S)
{
	S.base = new DataType[MAX_SIZE];
	if (!S.base)
	{
		return false;
	}
	S.top = S.base;
	return true;
}

//入栈
bool pushStack(Stack& S, DataType data)
{
	if (!S.base)
	{
		return false;
	}
	if (S.top - S.base == MAX_SIZE)
	{
		return false;
	}

	*(S.top) = data;
	S.top++;
	return true;
}

//出栈
bool popStack(Stack& S, DataType& e)
{
	if (S.top == S.base)
	{
		return false;
	}
	e = *(--S.top);
	return true;
}

//返回栈顶元素         
DataType* getTop(Stack& S)
{
	if (S.top - S.base == 0)
	{
		return NULL;
	}
	//注意何时自增何时不自增
	return S.top - 1;//返回栈顶元素的指针
}

//返回栈中元素个数
int getSize(Stack& S)
{
	return S.top - S.base;
}

//判断栈是否为空
bool isEmpty(Stack& S)
{
	if (S.top == S.base)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//销毁栈
void destoryStack(Stack& S)
{
	if (S.base)
	{
		delete[] S.base;
		S.top = S.base = NULL;
	}
}

experssion.cpp

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

//比较 lhs 的优先级是否高于 rhs,rhs 表示栈顶的符号

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

//计算左右操作数+运算符 (对运算符求值)
int operate(int left, int right, int op)
{
	int result = 0;
	switch (op)
	{
	case '+':
		result = left + right;
		break;
	case '-':
		result = left - right;
		break;
	case '*':
		result = left * right;
		break;
	case '/':
		result = left / right;
		break;
	default:
		break;
	}
	return result;
}

//运算主体
int calculate(string input)
{
	Stack data_stack;//操作数堆栈
	Stack opt_stack;//运算符堆栈

	int status = 0;//0接收左操作数,1接收操作符,2,接收右操作数

	//左右操作数
	//一直在发生变化的是右操作符
	int ldata = 0;
	int rdata = 0;

	char last_opt = '\0';

	//初始化堆栈
	initStack(data_stack);
	initStack(opt_stack);

	//从第一个开始遍历
	for (int i = 0; i < input.length(); i++)
	{
		if (isspace(input[i]))//跳过空白符
		{
			continue;
		}

		//不是空白,第一次到这里,默认是status = 0是左操作数
		switch (status)
		{
			//isdigit-判断是否是十进制数字
		case 0:
			//得到做操作数左操作数
			/*
				左操作数是如何得到的
				遍历字符串,第一个得到的肯定是左操作数,但我们不知道它是几位数。默认ldata为0
				其实就是——这个数是几位,这个if()条件就能进来几次
				累加在ldata中,得到左操作数
			*/
			if (isdigit(input[i]))
			{
				ldata *= 10;
				ldata += input[i] - '0';//求出该位上这个数是几
			}
			
			//什么时候执行到这里?
			//第一个数字得到之后,也就是得到了ldata之后
			else
			{

				pushStack(data_stack, ldata);//左操作数进栈

				//现在input[i]的位置是运算符
				//因为结束case结束之后,出来for循环还得++,这样就错过这个运算符了
				//为了保证到case 1的语句中此时的input[i]是运算符,所以要字先--
				i--;

				status = 1;//操作数确定了,下一个就该运算符了。
			}
			break;



		case 1://遇到操作符
			if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
			{
				if (isEmpty(opt_stack))//第一个运算符暂时不做任何处理,先入栈保存
				{
					pushStack(opt_stack, input[i]);//第一个操作符进栈
					//运算符进栈存的是对应符号的ASCII码

					status = 2;//状态标记为2 下一个为右操作数
				}
				else//不是第一个运算符,那么就将这个与之前的做优先级比较,如果这个优先级高,那就先算这个
				{
				

					//当前运算符高于前一个运算符

								//当前input[i]运算符  栈里面的存的第一个运算符
					if (isLarger(input[i], *getTop(opt_stack)))//如果当前运算符的优先级高于前一个
					{
						//压进栈
						pushStack(opt_stack, input[i]);//操作符入栈
						
						status = 2;//下一个是右操作数
						rdata = 0;//将右操作数置空
					}
					else//当前运算符的优先级小于(等于)前一个(栈顶)运算符。则计算前一个运算符的值
					{
						int right = 0;
						int left = 0;
						int opt = 0;

						do
						{
							//拿到操作符 和 前面两个左右操作数
							//先取到右边的,在取左边的(倒着拿出来)
							//运算的时候注意参数传递顺序
							popStack(data_stack, right);
							popStack(data_stack, left);
							popStack(opt_stack, opt);
							
							int result = operate(left, right, opt);
							pushStack(data_stack, result);//得到一部分的结果压进栈
						} while (!isEmpty(opt_stack) && !isLarger(input[i],*getTop(opt_stack)));//自动再往前判断,是否可以对前面的表达式进行运算
						//运算符栈不为空 并且当前运算符优先级小于等于栈顶运算符(前面的)那么就能一并进行运算

						//将当前input[i]运算符压入栈
						pushStack(opt_stack, input[i]);

						status = 2;//去右操作数
						rdata = 0;//置空
					}
				}
			}
			else if (input[i] == '=')//到达结尾
			{
				int opt = 0;
				int result = 0;
				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右操作数
			{
				rdata *= 10;
				rdata += input[i] - '0';
			}
			else
			{
				pushStack(data_stack, rdata);//右操作数入栈
				i--;
				status = 1;
			}
			break;
		}
	}
	return -1;
}


int main(void)
{
	string str = "12+3*6/3+4*5=";
	cout << calculate(str) << endl;//38
	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-16 19:28:07  更:2021-10-16 19:28:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 19:29:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计