【c++栈的应用】表达式的求值

今天我们来利用栈来实现一下表达式的求值。

之前我也写过关于栈的基本功能的内容,链接如下:

数据结构之栈与队列(一)

什么是“表达式求值“

表达式的求值,简单来说,就是实现任意加减乘除与括号的表达式求值,以文本的文件的方式来输入输出。

最终效果演示

1.这里我们需要先将未计算的表达式写入begin.txt文本
在这里插入图片描述
2.运行程序
.
3.查看finall.txt文本
在这里插入图片描述

实现代码

求取算数表达式的值,我们将这个过程分成两步:

1.将算数表达式exp转化为后缀表达式postexp。
2.使用后缀表达式postexp求值。

将算数表达式exp转化为后缀表达式postexp

在转换过程中,我们采用一个运算符栈,用来存储运算符结构如下:

struct
{
	char *data;
	int top;
}op;

将中缀表达式exp转化为后缀表达式postexp的过程为:

while(从exp读取字符ch,ch!='\0')
{
if ch 为数字,将后续的所有数字均以次存放在postexp中,并以字符“#”标志数值串结束。
if ch 为'(',则将括号进栈到运算符栈op中
if ch 为')',则将运算符op中左括号右边的运算符依次出栈并放在postexp中,并将左括号删除。
if ch 为 运算符 ,当ch的优先级不大于栈顶运算符(栈顶元素为"("除外)的优先级,则以此出栈并存入postexp中,然后将ch进栈。
}

当字符串exp扫描完毕时,则将运算符栈op中的所有运算符以此出栈并以此出栈存放到postexp,最后得到后缀表达式postexp.

这里给出一个例子,以便理解:
在这里插入图片描述

将exp转化为后缀表达式postexp的trans()算法如下。

void trans(char exp[], char postexp[])
{
	char ch;
	op.data = new char[MAXSIZE];
	op.top = -1;
	int i = 0, j = 0;//i为exp下标,j为postexp下标
	
	ch = exp[i];
	//cout << ch<<"_";
	i = 1;
	//cout << ch << "_";
	while (ch!='\0')//扫描字符数组exp
	{
		switch (ch)
		{
		
		case '(':      //左括号直接入栈
			op.top++;
			op.data[op.top] = ch;
			break;
		case ')':       
			while (op.data[op.top] != '(')   //‘(’之前的字符以此出栈并存入postexp
			{
				postexp[j] = op.data[op.top];  
				j++;
				op.top--;
			}
			op.top--;  //左括号出栈,并删除
			break;
		case'+':   //符号优先级不大于栈顶任何运算符的优先级,且栈顶不是‘(’
		case'-':
			//cout << op.top << "_";
			//if ((exp[0] == '+'|| exp[0] == '-')&&(op.top==-1))//当首运算符为+或-
			//{
			//	postexp[j] = 0;  
			//	postexp[++j] = '#';
			//	j++;
			//}
			
			while (op.top != -1 && op.data[op.top] != '(')//依次出栈,存入postexp
			{
				postexp[j] = op.data[op.top];
				j++;
				op.top--;
				//cout << op.top << "_";
			}

			op.top++;             //将ch进栈
			//cout << op.top<<"_";
			op.data[op.top] = ch;
			break;
		case'*':    //符号优先级不大于栈顶任何运算符的优先级,且栈顶不是‘(’
		case'/':
			while (op.top != -1 && op.data[op.top] != '('&&
				(op.data[op.top]=='*'||op.data[op.top]=='/'))
			{
				postexp[j] = op.data[op.top];//依次出栈,存入postexp
				j++;
				op.top--;
			}
			op.top++;//将ch进栈
			op.data[op.top]=ch;
			break;
		case' ':     //将空格过滤
			break;
		default:
			while (ch >= '0' && ch <= '9')  //判定为数字
			{
				postexp[j] = ch;
				j++;
				ch = exp[i];    
				i++; 
			}
			i--;
			postexp[j] = '#'; //在每段数字结束后加‘#’作为结束符
			j++;
		}
		ch = exp[i]; 
		i++;
	}
	while (op.top != -1)
	{
		postexp[j] = op.data[op.top];
		j++;
		op.top--;
	}
	postexp[j] = '\0';

}

使用后缀表达式postexp求值

在计算后缀表达式值得过程中使用中使用一个数值栈st,设计其结构如下:

struct
{
	float* data;
	int top;
}st;
求值过程如下:
 while(从postexp读取字符ch,ch!='\0')
 {
 if ch 为数字,将后继的所有数字构成一个整数存放在数值栈st中
 if ch 为“+,则从数值栈st中退站两个运算数,相加后进栈st中
 if ch 为“-,则从数值栈st中退站两个运算数,相减后进栈st中
 if ch 为“*,则从数值栈st中退站两个运算数,相乘后进栈st中
 if ch 为“/,则从数值栈st中退站两个运算数,相除后进栈st中(若除数为0,则提示错误)
 }

我们将上一个例子得到的后缀表达式求值

在这里插入图片描述

根据上述原理得到compvalue算法

float compvalue(char postexp[])
{
	float d;
	char ch;
	int i = 0;
	st.data = new float[MAXSIZE];
	st.top = -1;
	ch = postexp[i];
	//cout << ch <<"_"<< endl;;
	i++;
	while (ch != '\0')
	{
		switch (ch)
		{
		case'+':
			st.data[st.top - 1] = st.data[st.top - 1] + st.data[st.top];
			st.top--;
			break;
		case'-':
			st.data[st.top - 1] = st.data[st.top - 1] - st.data[st.top];
			st.top--;
			break;
		case'*':
			st.data[st.top - 1] = st.data[st.top - 1] * st.data[st.top];
			st.top--;
			break;
		case'/':
			if(st.data[st.top]!=0)
			st.data[st.top - 1] = st.data[st.top - 1] / st.data[st.top];
			else
			{
				cout << ("\n\t除零错误!\n");
				exit(0);
			}
			st.top--;
			break;
		case' ':
			break;
		
		default:
			d = 0;
			while (ch >= '0' && ch <= '9')
			{
				d = 10 * d + ch - '0';    
				ch = postexp[i];
				i++;
			}
			st.top++;
			st.data[st.top] = d;
			
		}
		ch = postexp[i];
		i++;
	}
	return st.data[st.top];

}

以上就是表达式求值的核心部分。

接下来是完整的代码

1.头文件 calulate.h

#pragma once
#include<iostream>
using namespace std;
#include<fstream>
#include<string>
#include<string.h>

#define MAXSIZE 100

struct
{
	char *data;
	int top;
}op;
struct
{
	float* data;
	int top;
}st;
string read(int k);
void trans(char exp[], char postexp[]);
float compvalue(char postexp[]);
void Print(char over[]);

2.源文件calulate.cpp

#include"calulate.h"

void Init()
{
	
}
string read(int k)
{
	fstream ofs;
	ofs.open("begin.txt", ios::in|ios::out);
	if (!ofs.is_open())
	{
		cout << "文件打开失败!" << endl;
	}
	string data[100];
	int i = 0;
	while (getline(ofs, data[i]))
	{
		i++;
	}
	return data[k];


}
void trans(char exp[], char postexp[])
{
	char ch;
	op.data = new char[MAXSIZE];
	op.top = -1;
	int i = 0, j = 0;//i为exp下标,j为postexp下标
	
	ch = exp[i];
	//cout << ch<<"_";
	i = 1;
	//cout << ch << "_";
	while (ch!='\0')//扫描字符数组exp
	{
		switch (ch)
		{
		
		case '(':      //左括号直接入栈
			op.top++;
			op.data[op.top] = ch;
			break;
		case ')':       
			while (op.data[op.top] != '(')   //‘(’之前的字符以此出栈并存入postexp
			{
				postexp[j] = op.data[op.top];  
				j++;
				op.top--;
			}
			op.top--;  //左括号出栈,并删除
			break;
		case'+':   //符号优先级不大于栈顶任何运算符的优先级,且栈顶不是‘(’
		case'-':
			//cout << op.top << "_";
			//if ((exp[0] == '+'|| exp[0] == '-')&&(op.top==-1))//当首运算符为+或-
			//{
			//	postexp[j] = 0;  
			//	postexp[++j] = '#';
			//	j++;
			//}
			
			while (op.top != -1 && op.data[op.top] != '(')//依次出栈,存入postexp
			{
				postexp[j] = op.data[op.top];
				j++;
				op.top--;
				//cout << op.top << "_";
			}

			op.top++;             //将ch进栈
			//cout << op.top<<"_";
			op.data[op.top] = ch;
			break;
		case'*':    //符号优先级不大于栈顶任何运算符的优先级,且栈顶不是‘(’
		case'/':
			while (op.top != -1 && op.data[op.top] != '('&&
				(op.data[op.top]=='*'||op.data[op.top]=='/'))
			{
				postexp[j] = op.data[op.top];//依次出栈,存入postexp
				j++;
				op.top--;
			}
			op.top++;//将ch进栈
			op.data[op.top]=ch;
			break;
		case' ':     //将空格过滤
			break;
		default:
			while (ch >= '0' && ch <= '9')  //判定为数字
			{
				postexp[j] = ch;
				j++;
				ch = exp[i];    
				i++; 
			}
			i--;
			postexp[j] = '#'; //在每段数字结束后加‘#’作为结束符
			j++;
		}
		ch = exp[i]; 
		i++;
	}
	while (op.top != -1)
	{
		postexp[j] = op.data[op.top];
		j++;
		op.top--;
	}
	postexp[j] = '\0';

}
float compvalue(char postexp[])
{
	float d;
	char ch;
	int i = 0;
	st.data = new float[MAXSIZE];
	st.top = -1;
	ch = postexp[i];
	//cout << ch <<"_"<< endl;;
	i++;
	while (ch != '\0')
	{
		switch (ch)
		{
		case'+':
			st.data[st.top - 1] = st.data[st.top - 1] + st.data[st.top];
			st.top--;
			break;
		case'-':
			st.data[st.top - 1] = st.data[st.top - 1] - st.data[st.top];
			st.top--;
			break;
		case'*':
			st.data[st.top - 1] = st.data[st.top - 1] * st.data[st.top];
			st.top--;
			break;
		case'/':
			if(st.data[st.top]!=0)
			st.data[st.top - 1] = st.data[st.top - 1] / st.data[st.top];
			else
			{
				cout << ("\n\t除零错误!\n");
				exit(0);
			}
			st.top--;
			break;
		case' ':
			break;
		
		default:
			d = 0;
			while (ch >= '0' && ch <= '9')
			{
				d = 10 * d + ch - '0';    
				ch = postexp[i];
				i++;
			}
			st.top++;
			st.data[st.top] = d;
			
		}
		ch = postexp[i];
		i++;
	}
	return st.data[st.top];

}

3.测试文件test.cpp

#include"calulate.h"

void test()
{
	fstream fst;
	fst.open("final.txt", ios::app);

	char*postexp;
	postexp = new char[20];
	int i = 0;
	int j = 0;
	float tiv=0;
	string s;
	char mine[20]="0";
	for (i = 0; i < 20; i++)
	{
		if (read(i) != "")
		{
			s = read(i);
		           
					strncpy_s(mine, s.c_str(), s.length()-1);
					//当首元素为运算符时
					if (mine[0] == '-'||mine[0]=='+')
					{
						for (int m = 18; m > -1; m=m - 1)
						{
							mine[m + 1] = mine[m];
						}
						mine[0] = '0';
					}

					//当出现(-x)时
					for (int y = 1; y < 20; y++)
					{
						if (mine[y] == '-'&&mine[y-1]=='(')
						{
							for (int w = 18; w > y - 1; w = w - 1)
							{
								mine[w + 1] = mine[w];
							}
							mine[y] = '0';
						}
					}
					trans(mine, postexp);


	//char postexp[20] = "0#1#-2#+";
					tiv=compvalue(postexp);
					//cout <<endl<< postexp;
					if (mine[0] != '0')
					{
						for (j = 0; mine[j];j++)
						{
							cout << mine[j];
							fst << mine[j];
						}
					}
					if(mine[0]=='0')
					{
						for (j = 1; mine[j]; j++)
						{
							cout << mine[j];
							fst << mine[j];
						}
					}
                    
					cout <<"="<< tiv << endl;
					fst << "=" << tiv << endl;
		}
		

	}
	
}
int main()
{
	test();
	return 0;
}
  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
中缀表达式转后缀表达式的过程可以使用来实现。下面是实现该转换的算法: 1. 创建一个空和一个空字符串,用于存储后缀表达式。 2. 从左到右遍历中缀表达式的每个字符: - 如果字符是数字或字母,直接将其添加到后缀表达式字符串中。 - 如果字符是左括号"(",将其入。 - 如果字符是右括号")",则将顶元素出并添加到后缀表达式字符串,直到遇到左括号为止。左括号不添加到后缀表达式中,也不入。 - 如果字符是运算符(如"+", "-", "*", "/"等): - 如果为空,或者顶元素是左括号"(",则将该运算符入。 - 否则,将顶运算符与当前运算符进行比较: - 如果顶运算符的优先级大于等于当前运算符,则将顶运算符出并添加到后缀表达式字符串中,循环执行该步骤直到不满足条件。 - 将当前运算符入。 3. 遍历完中缀表达式后,将中剩余的所有运算符依次出并添加到后缀表达式字符串中。 4. 后缀表达式字符串即为转换后的结果。 以下是一个示例的实现(使用Python语言): ```python def infix_to_postfix(expression): # 定义运算符优先级 precedence = {"+": 1, "-": 1, "*": 2, "/": 2} stack = [] postfix = "" for char in expression: if char.isalnum(): postfix += char elif char == "(": stack.append(char) elif char == ")": while stack and stack[-1] != "(": postfix += stack.pop() stack.pop() # 弹出左括号 else: while stack and stack[-1] != "(" and precedence[char] <= precedence.get(stack[-1], 0): postfix += stack.pop() stack.append(char) while stack: postfix += stack.pop() return postfix ``` 可以通过调用 `infix_to_postfix` 函数将中缀表达式转换为后缀表达式。例如,`infix_to_postfix("3+4*2/(1-5)^2^3")` 将返回后缀表达式字符串 "342*15-23^^/"。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ornamrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值