前缀表达式和后缀表达式 - C++代码


刷题向文章,不介绍原理,只介绍规则

速览

算术表达式分为:

  • 前缀表达式(波兰式)
  • 后缀表达式(逆波兰式)
  • 中缀表达式

中缀表达式是我们最熟悉的表达式,是常见的运算式,如下所示:

(2 + 3) * 4 - 5

这就是一个中缀表达式
相对于中缀表达式,前缀表达式的运算符在操作数之前,把上面的中缀表达式改写成前缀表达式为:

- * + 2 3 4 5

注意,并不是所有运算符在所有数字之前,如:

+ - 1 2 * 3 5

也可以是前缀表达式

前缀表达式

前缀表达式的运算规则

从右向左依次扫描表达式,如果扫描到数字,则把数字压入栈
如果扫描到运算符,则依次弹出栈顶的两个数字进行计算,并把计算结果压入栈

例:计算前缀表达式 - * +2345 的值

扫描值堆栈计算值
55
45 4
35 4 3
25 4 3 2
+5 4 52+3=5
*5 205*4=20
-1520-5=15

前缀表达式的值为 15

中缀表达式转换为前缀表达式

创建2个空栈 S1 和 S2,S1 为符号栈,S2 为临时栈,从右向左扫描中缀表达式

  1. 如果遇到数字,压入 S2 栈中
  2. 如果遇到符号:
    如果 S1 为空栈,或者 S1 栈顶为右括号,直接压入 S1 中
    如果扫描到的符号优先级大于等于 S1 栈顶的符号,直接压入 S1 中
    如果扫描到的符号优先级小于 S1 栈顶的符号,则把 S1 栈顶的符号弹出并压入 S2,重复这一步骤,直到可以把扫描到的符号压入 S1
  3. 如果遇到括号:
    如果遇到左括号,直接压入 S1
    如果遇到右括号,依次弹出 S1 栈顶的符号并压入 S2,直到遇到左括号时,丢弃这一对括号
    最后,依次把 S1 栈顶元素弹出压入 S2 中,依次弹出 S2 栈顶元素,得到前缀表达式

例:把中缀表达式 1+((2+3) * 4)-5 转换为前缀表达式

扫描值操作S1S2
5压入S25
-压入S1-5
)压入S1-)5
4压入S2-)5 4
*压入S1-)*5 4
)压入S1-)*)5 4
3压入S2-)*)5 4 3
+压入S1-)*)+5 4 3
2压入S2-)*)+5 4 3 2
(弹出+,压入S2-)*5 4 3 2+
(弹出*,压入S2-5 4 3 2+*
+压入S1-+5 4 3 2+*
1压入S2-+5 4 3 2+*1
NULL依次弹出S1栈顶压入S25 4 3 2+*1+ -

所求前缀表达式为:-+1*+2345

代码实现:

// 前缀表达式练习 - 只能输入 0-9 的数
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;

bool isoperator(int _C);
bool isbrackets(int _C);

int main(int argc, char*argv[]) {
	// 输入中缀表达式
	string infix;
	cin >> infix;
	// 中缀表达式 => 前缀表达式
	stack<char>S1, S2;
	for (auto it = infix.crbegin(); it != infix.crend(); it++) {
		if (isdigit(*it))S2.push(*it);
		else if (isoperator(*it)) {
		CASE_ISOPERATOR:
			if (S1.empty() || ')' == S1.top())S1.push(*it);
			else if ('+' == S1.top() || '-' == S1.top())S1.push(*it);
			else if ('*' == *it || '/' == *it)S1.push(*it);
			else {
				S2.push(S1.top());
				S1.pop();
				goto CASE_ISOPERATOR;
			}
		}
		else if (isbrackets(*it)) {
			if (')' == *it)S1.push(*it);
			else {
				while (!isbrackets(S1.top())) {
					S2.push(S1.top());
					S1.pop();
				}
				S1.pop();
			}
		}
	}
	while (!S1.empty()) {
		S2.push(S1.top());
		S1.pop();
	}
	string prefix;
	while (!S2.empty()) {
		prefix.push_back(S2.top());
		S2.pop();
	}
	// 计算前缀表达式的值
	stack<int>value;
	for (auto it = prefix.crbegin(); it != prefix.crend(); it++) {
		if (isdigit(*it))value.push(*it - '0');
		else {
			int top, second_top;
			top = value.top();
			value.pop();
			second_top = value.top();
			value.pop();
			switch (*it) {
			case'+':value.push(top + second_top); break;
			case'-':value.push(top - second_top); break;
			case'*':value.push(top*second_top); break;
			case'/':value.push(top / second_top); break;
			}
		}
	}
	// 输出前缀表达式及其值
	cout << prefix << '=' << value.top() << endl;
	return 0;
}

bool isoperator(int _C) {
	return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}

bool isbrackets(int _C) {
	return '(' == _C || ')' == _C ? true : false;
}

后缀表达式

后缀表达式的运算

从左向右依次扫描表达式,如果扫描到数字,则把数字压入栈
如果扫描到运算符,则弹出栈顶的两个数字进行计算,并把计算结果压入栈
(和前缀表达式不同,结果 = 次顶数字 operator 顶部数字)

例:计算后缀表达式 23+4 * 5- 的值

扫描值堆栈计算值
22
32 3
+52+3=5
45 4
*205*4=20
5205
-1520-5=15

后缀表达式的值为 15

中缀表达式转换为后缀表达式

创建2个空栈 S1 和 S2,S1 为符号栈,S2 为临时栈,从左向右扫描中缀表达式

  1. 如果遇到数字,压入 S2 栈中
  2. 如果遇到符号:
    如果 S1 为空栈,或者 S1 栈顶为左括号,直接压入 S1 中
    如果扫描到的符号优先级大于 S1 栈顶的符号,直接压入 S1 中
    (注意前缀表达式是大于等于,而后缀表达式只有大于才可以直接压入)
    如果扫描到的符号优先级小于 S1 栈顶的符号,则把 S1 栈顶的符号弹出并压入 S2,重复这一步骤,直到可以把扫描到的符号压入 S1
  3. 如果遇到括号:
    如果遇到右括号,直接压入 S1
    如果遇到左括号,依次弹出S1栈顶的符号并压入 S2,直到遇到左括号时,丢弃这一对括号
    最后,依次把 S1 栈顶元素弹出压入 S2 中,依次弹出 S2 栈顶元素,“反向输出”,得到前缀表达式

例:把中缀表达式 1+((2+3) * 4)-5 转换为前缀表达式

扫描值操作S1S2
1压入S2NULL1
+压入S1+1
(压入S1+(1
(压入S1+((1
2压入S2+((1 2
+压入S1+((+1 2
3压入S2+((+1 2 3
)弹出+,压入S2+(1 2 3+
*压入S1+(*1 2 3+
4压入S2+(*1 2 3+4
)弹出*,压入S2+1 2 3+4*
-弹出+压入S1,压入S1-1 2 3+4*+
5压入S2-1 2 3+4*+5
NULL依次弹出S1顶部元素,压入S21 2 3+4*+5-

所求后缀表达式为:1 2 3+4*+5-

代码实现:

// 后缀表达式练习 - 只能输入 0-9 的数
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;

bool isoperator(int _C);
bool isbrackets(int _C);

int main(int argc, char*argv[]) {
	// 输入中缀表达式
	string infix;
	cin >> infix;
	// 中缀表达式 => 后缀表达式
	stack<char>S1, S2;
	for (auto it = infix.cbegin(); it != infix.cend(); it++) {
		if (isdigit(*it))S2.push(*it);
		else if (isoperator(*it)) {
		CASE_ISOPERATOR:
			if (S1.empty() || '(' == S1.top())S1.push(*it);
			else if (('+' == S1.top() || '-' == S1.top()) && ('*' == *it || '/' == *it))S1.push(*it);
			else {
				S2.push(S1.top());
				S1.pop();
				goto CASE_ISOPERATOR;
			}
		}
		else if (isbrackets(*it)) {
			if ('(' == *it)S1.push(*it);
			else {
				while (!isbrackets(S1.top())) {
					S2.push(S1.top());
					S1.pop();
				}
				S1.pop();
			}
		}
	}
	while (!S1.empty()) {
		S2.push(S1.top());
		S1.pop();
	}
	string prefix;
	while (!S2.empty()) {
		prefix.insert(prefix.begin(), S2.top());
		S2.pop();
	}
	// 计算后缀表达式的值
	stack<int>value;
	for (auto it = prefix.cbegin(); it != prefix.cend(); it++) {
		if (isdigit(*it))value.push(*it - '0');
		else {
			int top, second_top;
			top = value.top();
			value.pop();
			second_top = value.top();
			value.pop();
			switch (*it) {
			case'+':value.push(second_top + top); break;
			case'-':value.push(second_top - top); break;
			case'*':value.push(second_top*top); break;
			case'/':value.push(second_top / top); break;
			}
		}
	}
	// 输出后缀表达式及其值
	cout << prefix << '=' << value.top() << endl;
	return 0;
}

bool isoperator(int _C) {
	return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}

bool isbrackets(int _C) {
	return '(' == _C || ')' == _C ? true : false;
}
优化代码:
// 后缀表达式求值
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;

bool isop(char _C);
void orgnize(string&str);

int main() {
	string input, buffer;
	while (!cin.eof()) {
		cin >> buffer;
		input.append(buffer);
		input.push_back(32);
		buffer.clear();
	}
	orgnize(input);
	stack<int>value;
	for (auto it = input.begin(); it != input.end();) {
		if (isdigit(*it)) {
			while (isdigit(*it))
				buffer.push_back(*it++);
			value.push(atoi(buffer.c_str()));
			buffer.clear();
		}
		else if (isop(*it)) {
			int top, second_top;
			top = value.top();
			value.pop();
			second_top = value.top();
			value.pop();
			switch (*it++) {
			case'+':value.push(second_top + top); break;
			case'-':value.push(second_top - top); break;
			case'*':value.push(second_top * top); break;
			case'/':value.push(second_top / top); break;
			}
		}
		else it++;
	}
	cout << "postfix(" << input << ")=" << value.top() << endl;
	return 0;
}

bool isop(char _C) {
	return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}

void orgnize(string&str) {
	while (!str.empty())
		if (isspace(*str.rbegin()))str.pop_back();
		else break;
	while (!str.empty())
		if (isspace(*str.begin()))str.erase(str.begin());
		else break;
	for (auto it = str.begin(); it != str.end();)
		if (isspace(*it++))
			while (isspace(*it))it = str.erase(it);
	for (auto it = str.begin(); it != str.end() - 1; it++) {
		if (isdigit(*it) && isop(it[1]))
			it = str.insert(it + 1, 32);
		else if (isop(*it) && (isdigit(it[1]) || isop(it[1])))
			it = str.insert(it + 1, 32);
	}
}
// 中缀 - 后缀转换
// infix to postfix
#include<iostream>
using std::cin;
using std::cout;
using std::ostream;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;
#include<vector>
using std::vector;

struct CharInt {
	bool ischar;
	int charint;
	CharInt(bool isch, int chint) :ischar(isch), charint(chint) {}
};
ostream&operator<<(ostream&output, CharInt x) {
	if (x.ischar)output << static_cast<char>(x.charint);
	else output << x.charint;
	return output;
}

bool isop(char _C) {
	return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}

int main() {
	char buffer[128];
	cin.getline(buffer, sizeof(buffer));
	stack<char>S1;
	stack<CharInt>S2;
	for (auto it = buffer; *it;) {
		if (isdigit(*it)) {
			string temp;
			while (isdigit(*it))
				temp.push_back(*it++);
			S2.push(CharInt(false, atoi(temp.c_str())));
		}
		else if (isop(*it)) {
		CASE_ISOP:
			if (S1.empty() || '(' == S1.top())S1.push(*it);
			else if (('+' == S1.top() || '-' == S1.top()) && ('*' == *it || '/' == *it))
				S1.push(*it);
			else {
				S2.push(CharInt(true, S1.top()));
				S1.pop();
				goto CASE_ISOP;
			}
			it++;
		}
		else if ('(' == *it)S1.push(*it++);
		else if (')' == *it++) {
			while (S1.top() != '(') {
				S2.push(CharInt(true, S1.top()));
				S1.pop();
			}
			S1.pop();
		}
	}
	while (!S1.empty()) {
		S2.push(CharInt(true, S1.top()));
		S1.pop();
	}
	vector<CharInt>output;
	while (!S2.empty()) {
		output.insert(output.begin(), S2.top());
		S2.pop();
	}
	for (auto it : output)
		cout << it << ' ';
	cout.put(10);
	return 0;
}
  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值