中缀表达式式转后缀表达式,后缀表达式计算结果(支持小数)

基础知识

占坑

代码,内含注释,基本上看注释就能看懂

#include<iostream>
#include<cstdio>
#include<stack>
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#pragma warning(disable:4996)
using namespace std;

/*
*中缀转后缀,后缀再计算
*这些函数整理得比较规整,可以轻松写成一个类。
*注释详实,不再进行过多解释。

infixToPostfix:中缀表达式转后缀表达式
	in:
		char* infix		输入的中缀表达式,可以有小数,不能有空格,以 '\0' 结尾。
		char* postfix	输出的后缀表达式,每个元素以空格分隔,以 '\0' 结尾

calPostfix:后缀表达式计算
	in:
		char* postfix	输入的后缀表达式,每个元素以空格分隔,以 '\0' 结尾。
	out:
		double			输出的结果。

isNumber		输入一个字符,返回是不是0-9的数字字符
isOperator		输入一个字符,返回是不是操作符
priority		输入一个字符,返回该操作符的优先级
enum cal_err	可能出现的错误
*/
typedef enum { wrong_char, no_such_operator }cal_err;
inline bool isNumber ( char c ) {
	if ( c >= '0' && c <= '9' ) {
		return true;
	} else {
		return false;
	}
}
inline bool isOperator ( char c ) {
	switch ( c ) {
	case '*':
	case '/':
	case '+':
	case '-':
		return true;
	default:
		return false;
	}
}

int priority ( char c ) {
	switch ( c ) {
	case '*':return 5; break;
	case '/':return 5; break;
	case '+':return 4; break;
	case '-':return 4; break;
	default:throw no_such_operator;
	}
}

/*计算后缀表达式*/
double calPostfix ( char* postfix ) {
	stack<double> result;

	/*
	计算后缀表达式比中缀转后缀简单
	首先准备一个后缀表达式与一个数字栈

	对于后缀表达式从左到右每个元素
	如果是数字,则压入数字栈
	如果是操作符,则弹出数字栈中的两个,以第一次弹出作为右值,第二次弹出作为左值,进行相应计算并入数字栈(因为/与-与数字顺序相关)
	直到后缀表达式结束,返回栈顶数字
	*/
	for ( int i = 0;;) {
		if ( isNumber ( postfix[i] ) || postfix[i] == '.' ) {

			/*这里将浮点字符串转化为浮点数,有时间可以抽离成单独的函数*/
			double temp = 0;
			bool is_int = true;
			while ( isNumber ( postfix[i] ) || postfix[i] == '.' ) {
				if ( postfix[i] == '.' ) {
					is_int = false;
				} else {
					if ( is_int ) {
						temp = ( postfix[i] - '0' ) + temp * 10;
					} else {
						temp = ( postfix[i] - '0' ) * 0.1 + temp;
					}
				}
				i++;
			}
			i--;
			result.push ( temp );
		} else if ( postfix[i] == ' ' ) {
		} else if ( postfix[i] == '*' ) {
			double a = result.top ();
			result.pop ();
			double b = result.top ();
			result.pop ();

			result.push ( a * b );
		} else if ( postfix[i] == '/' ) {
			double a = result.top ();
			result.pop ();
			double b = result.top ();
			result.pop ();

			result.push ( b / a );
		} else if ( postfix[i] == '+' ) {
			double a = result.top ();
			result.pop ();
			double b = result.top ();
			result.pop ();

			result.push ( a + b );
		} else if ( postfix[i] == '-' ) {
			double a = result.top ();
			result.pop ();
			double b = result.top ();
			result.pop ();

			result.push ( b - a );
		} else if ( postfix[i] == '\0' ) {
			return result.top ();
		} else {
			throw wrong_char;
			return 0;
		}
		i++;
	}

}

/*中缀转后缀,注释详实*/
void infixToPostfix ( char* infix, char* postfix ) {
	int j = 0;//目的下标
	int i = 0;//源下标
	stack<char> op_stack;

	/*
	中缀转后缀需要一个中缀表达式,一个存放后缀表达式的缓冲区,一个符号栈

	对于中缀表达式从左到右每个元素
	1.如果是数字,直接进入后缀表达式
	2.如果是操作符
		->循环判断开始
		1.如果 符号栈为空 或 栈顶为左括号,则直接入栈
		2.如果 当前操作符比栈顶符号优先级高,也直接入栈
		3.如果 当前操作符比栈顶符号优先级低或相等,则栈顶元素弹出到后缀表达式,并重新进行此判断
		(强调“重新进行此的判断”是为了优化程序结构,这样表述就只需要写一个while循环)
		<-循环判断结束
	3.如果是左右括号
		1.如果是左括号,则入栈
		2.如果是右括号,则栈弹出到后缀表达式,直到左括号,并抛弃左括号
	*/

	/*每次循环,i均指向当前循环需要被判断的位置*/
	for ( ;;) {
		if ( isNumber ( infix[i] ) || infix[i] == '.' ) {
			/*数字字符直接输出到后缀表达式,直到下一位不是数字字符输出空格到后缀表达式并跳出循环 */
			while ( isNumber ( infix[i] ) || infix[i] == '.' ) {
				postfix[j++] = infix[i++];
			}
			postfix[j++] = ' ';
			i--;
		} else if ( isOperator ( infix[i] ) ) {
			while ( true ) {
				if ( op_stack.empty () || op_stack.top () == '(' ) {
					op_stack.push ( infix[i] );
					break;
				} else if ( priority ( infix[i] ) > priority ( op_stack.top () ) ) {
					op_stack.push ( infix[i] );
					break;
				} else {
					postfix[j++] = op_stack.top ();
					postfix[j++] = ' ';
					op_stack.pop ();
				}
			}
		} else if ( infix[i] == ')' ) {
			while ( op_stack.top () != '(' ) {
				postfix[j++] = op_stack.top ();
				postfix[j++] = ' ';
				op_stack.pop ();
			}
			op_stack.pop ();
		} else if ( infix[i] == '(' ) {
			op_stack.push ( infix[i] );
		} else if ( infix[i] == '\0' ) {
			break;
		} else {
			throw wrong_char;
			return;
		}

		i++;//循环末,i处于本次循环判断处,需要让其指向下次循环判断处。
	}
	while ( !op_stack.empty () ) {
		postfix[j++] = op_stack.top ();
		postfix[j++] = ' ';
		op_stack.pop ();
	}
	postfix[j++] = '\0';
	return;

}



int main () {
	//freopen ( "input.txt", "r", stdin );

	char  str[2000];
	int num;
	cin >> num;//输入表达式数量

	for ( int i = 0; i < num; i++ ) {
		cin >> str;//输入一个表达式,前后都不加"#"
		char* postfix = new char[strlen ( str ) * 4];
		infixToPostfix ( str, postfix );
		//cout << postfix << '\n';
		printf ( "%.2lf\n", calPostfix ( postfix ) );
		delete[] postfix;
	}

	return 0;
}
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值