从键盘上输入一个算数表达式,试编写算法,计算出该表达式的逆波兰表达式。规定:逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、、/四种运算。
例1:输入为:2+3$,输出逆波兰表达式为:2 3 +。
例2:输入为:23$,输出逆波兰表达式为:2 3 。
例3:输入为:1+23$,输出逆波兰表达式为:1 2 3 * +。
例4:输入为:(1+2)3$,输出逆波兰表达式为:1 2 + 3 。
例5:输入为:(1+23)4$,输出逆波兰表达式为:1 2 3 * + 4 。
例6:输入为:6((5+(2+3)*8)+3)$,输出逆波兰表达式为:6 5 2 3 + 8 * + 3 + *。
提示1:括号成对,输出运算符;否则,输出数字。
提示2:求逆波兰表达式规则如下:设立运算数栈OPND,对表达式从左到右扫描(读入),当表达式中扫描到数时,压入OPND栈。当扫描到运算符时,从OPND退出两个数,进行相应运算,结果再压入OPND栈。这个过程一直不断运行直至表达式结束符$。(代码注释详细点)
转换逆波兰表达式的过程称为求逆波兰式。求逆波兰式的过程主要分为两个步骤:
(1)初始化两个栈:运算符栈和储存中间结果的栈。
(2)从右至左扫描表达式,将数字和字符压入两个栈。
(3)遇到运算符时,比较其与栈顶运算符的优先级:如果栈顶运算符的优先级高于当前运算符,将栈顶运算符弹出并压入中间结果栈,再次比较;如果当前运算符的优先级高于栈顶运算符,直接将当前运算符压入运算符栈。
(4)遇到括号时:如果是右括号,直接压入运算符栈。如果是左括号,则依次弹出运算符栈的运算符,并压入中间结果栈,直到遇到右括号为止,此时将这一对括号丢弃。
(5)重复步骤2至4,直到表达式最左边。
(6)将运算符栈中剩余的运算符依次弹出并压入中间结果栈。
(7)将中间结果栈中的数据依次弹出,即为逆波兰式。
在 C++ 中,可以使用栈来实现求逆波兰式的算法。栈可以使用 STL 中的 std::stack 来实现。
下面是一个实现求逆波兰式的 C++ 代码示例:
#include <iostream>
#include <stack>
#include <string>
// 定义优先级
int priority(char op) {
if (op == '+' || op == '-') {
return 1;
} else if (op == '*' || op == '/') {
return 2;
} else {
return 0;
}
}
int main() {
std::stack<char> ops; // 运算符栈
std::stack<int> nums; // 中间结果栈
std::string input; // 输入的算数表达式
std::cin >> input; // 读入表达式
// 从右至左扫描表达式
for (int i = input.size() - 1; i >= 0; i--) {
char c = input[i];
if (c >= '0' && c <= '9') {
// 如果是数字,压入中间结果栈
nums.push(c - '0');
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
// 如果是运算符
// 比较优先级
while (!ops.empty() && priority(ops.top()) >= priority(c)) {
// 如果栈顶运算符的优先级高于当前运算符,将栈顶运算符弹出并压入中间结果栈
int num2 = nums.top();
nums.pop();
int num1 = nums.top();
nums.pop();
char op = ops.top();
ops.pop();
int result;
if (op == '+') {
result = num1 + num2;
} else if (op == '-') {
result = num1 - num2;
} else if (op == '*') {
result = num1 * num2;
} else if (op == '/') {
result = num1 / num2;
}
nums.push(result);
}
// 将当前运算符压入运算符栈
ops.push(c);
} else if (c == '(') {
// 如果是左括号,依次弹出运算符栈的运算符,并压入中间结果栈,直到遇到右括号为止
while (ops.top() != ')') {
int num2 = nums.top();
nums.pop();
int num1 = nums.top();
nums.pop();
char op = ops.top();
ops.pop();
int result;
if (op == '+') {
result = num1 + num2;
} else if (op == '-') {
result = num1 - num2;
} else if (op == '*') {
result = num1 * num2;
} else if (op == '/') {
result = num1 / num2;
}
nums.push(result);
}
// 将左括号丢弃
ops.pop();
} else if (c == ')') {
// 如果是右括号,直接压入运算符栈
ops.push(c);
}
}
// 将运算符栈中剩余的运算符依次弹出并压入中间结果栈
while (!ops.empty()) {
int num2 = nums.top();
nums.pop();
int num1 = nums.top();
nums.pop();
char op = ops.top();
ops.pop();
int result;
if (op == '+') {
result = num1 + num2;
} else if (op == '-') {
result = num1 - num2;
} else if (op == '*') {
result = num1 * num2;
} else if (op == '/') {
result = num1 / num2;
}
nums.push(result);
}
// 中间结果栈中的数据依次弹出即为逆波兰式
while (!nums.empty()) {
std::cout << nums.top() << " ";
nums.pop();
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STACK_SIZE 100
// 定义运算符优先级
#define PREC_PLUS 0 // +
#define PREC_MINUS 0 // -
#define PREC_MULTIPLY 1 // *
#define PREC_DIVIDE 1 // /
#define PREC_LEFT_PAREN 1 // (
#define PREC_RIGHT_PAREN 0 // )
// 定义栈
double stack[STACK_SIZE];
int top = -1;
// 压栈
void push(double value) {
if (top < STACK_SIZE - 1) {
stack[++top] = value;
} else {
printf("Error: stack overflow\n");
exit(EXIT_FAILURE);
}
}
// 弹栈
double pop(void) {
if (top >= 0) {
return stack[top--];
} else {
printf("Error: stack underflow\n");
exit(EXIT_FAILURE);
}
}
// 返回运算符优先级
int get_precedence(char operator) {
switch (operator) {
case '+':
return PREC_PLUS;
case '-':
return PREC_MINUS;
case '*':
return PREC_MULTIPLY;
case '/':
return PREC_DIVIDE;
case '(':
return PREC_LEFT_PAREN;
case ')':
return PREC_RIGHT_PAREN;
default:
printf("Error: invalid operator\n");
exit(EXIT_FAILURE);
}
}
// 计算两个数的运算结果
double calculate(double operand1, char operator, double operand2) {
switch (operator) {
case '+':
return operand1 + operand2;
case '-':
return operand1
}
int main() {
// 定义表达式字符串和计算结果变量
char expression[100];
double result;
// 读入表达式字符串
printf("Enter an expression: ");
scanf("%s", expression);
// 调用函数计算逆波兰表达式的结果
result = calculate_rpn(expression);
// 输出结果
printf("Result: %f\n", result);
return 0;
}
#include<iostream>
#include<sstream>
#include<stack>
#include<vector>
#include<map>
using namespace std;
int IsOper(char str, const vector<char> &oper) {
for (int i = 0; i < oper.size(); i++) {
if (oper[i] == str) return i;
}
return -1;
}
void Excharge(stack<char> &s2, stack<char> &s1) {
while (!s2.empty()) {
s1.push(s2.top());
s2.pop();
}
}
void Excharge_(stack<char>& s2, stack<char>& s1) {
while (!s2.empty() && s2.top() != '(') {
s1.push(s2.top());
s2.pop();
}
if (s2.empty()) return;
s2.pop();
}
void Show(stack<char> s1) {
if (s1.empty()) {
cout << endl;
return;
}
char val = s1.top();
s1.pop();
Show(s1);
cout << val;
}
void ReversePolish(string expression) {
stack<char> s1;
stack<char> s2;
vector<char> oper = { '*','/','+','-','(',')' };
map<char, int> rank;
rank['('] = 3;
rank['*'] = 2;
rank['/'] = 2;
rank['+'] = 1;
rank['-'] = 1;
for (int i = 0; i < expression.size(); i++) {
int ret = IsOper(expression[i], oper);
if (ret < 0) {
s1.push(expression[i]); //压入栈内
}
else {
if (s2.empty() || s2.top() == '(') {
s2.push(expression[i]);
}
else if (expression[i] == ')') {
Excharge_(s2, s1);
}
else if (rank[expression[i]] > rank[s2.top()]) {
s2.push(expression[i]);
}
else {
Excharge(s2, s1);
s2.push(expression[i]); // 栈为空,直接压入s2
}
}
}
Excharge(s2, s1);
Show(s1);
}
int main(void) {
ReversePolish("(1+2)*5");
ReversePolish("1+2*5");
ReversePolish("(a+b)*c+d-(e+g)*h");
return 0;
}
提供参考实例【C++逆波兰式转化成中缀表达式,并输出最终计算结果】,链接:https://www.cnblogs.com/pcwlcsm/p/15146986.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STACK_SIZE 100
// 定义运算符优先级
#define PREC_PLUS 0 // +
#define PREC_MINUS 0 // -
#define PREC_MULTIPLY 1 // *
#define PREC_DIVIDE 1 // /
#define PREC_LEFT_PAREN 1 // (
#define PREC_RIGHT_PAREN 0 // )
// 定义栈
double stack[STACK_SIZE];
int top = -1;
// 压栈
void push(double value) {
if (top < STACK_SIZE - 1) {
stack[++top] = value;
} else {
printf("Error: stack overflow\n");
exit(EXIT_FAILURE);
}
}
// 弹栈
double pop(void) {
if (top >= 0) {
return stack[top--];
} else {
printf("Error: stack underflow\n");
exit(EXIT_FAILURE);
}
}
// 返回运算符优先级
int get_precedence(char operator) {
switch (operator) {
case '+':
return PREC_PLUS;
case '-':
return PREC_MINUS;
case '*':
return PREC_MULTIPLY;
case '/':
return PREC_DIVIDE;
case '(':
return PREC_LEFT_PAREN;
case ')':
return PREC_RIGHT_PAREN;
default:
printf("Error: invalid operator\n");
exit(EXIT_FAILURE);
}
}
// 计算两个数的运算结果
double calculate(double operand1, char operator, double operand2) {
switch (operator) {
case '+':
return operand1 + operand2;
case '-':
return operand1
}
int main() {
// 定义表达式字符串和计算结果变量
char expression[100];
double result;
// 读入表达式字符串
printf("Enter an expression: ");
scanf("%s", expression);
// 调用函数计算逆波兰表达式的结果
result = calculate_rpn(expression);
// 输出结果
printf("result: %f\n", result);
return 0;
}
整行读入,先将括号里的视为整体,找到运算符并移到右边,然后处理括号里的部分,重复这一过程,直到找不到括号为止。
c代码:
#include<stdio.h>
#include<string.h>
//返回与第一个左括号配对的右括号的地址
char * BracketMatch(const char * str) {
int count = 1; //未配对的左括号个数
str = strchr(str, '(');
if (str) {
//如果找到左括号,寻找配对的右括号,当未配对括号个数为0时,就找到了配对的右括号
while (count && *str++) {
if (*str == '(')count++;
else if (*str == ')')count--;
}
if (count) //没有配对的右括号
return NULL;
else
return (char*)str; //如果是c++程序,这一句改成“return const_cast<char*>str;”
} else {
//没有左括号
return NULL;
}
}
//将left和right确定的一段字符的指定运算符移到右边,不处理括号里的内容,仅交换位置,不改变字符串。
//这段字符需要经过预处理,否则会出错。signs必须是同级的,且从高到低调用
//lsigns指向优先级不高于sign的运算符,如果有需要,改一下逻辑,用空格作为分隔,可以不用这个参数
void convert(char *left, char *right, const char * signs, const char *lsigns) {
char *i, *j, t;
//i遍历这段字符
for (i = left; i != right; i++) {
if (*i == '(') {
//如果*i是左括号,则找到配对的右括号,并将括号以及括号里的内容复制到dest里
j = BracketMatch(i);
if (!j)return; //表达式有误,括号不成对
while (i != j)*left++ = *i++;
*left++ = *i; //括号也复制
} else if (strchr(signs, *i)) {
//如果*i是指定的运算符,则将运算符后面的,直至下一个运算符(跳过括号)或结束为止的部分复制(忽略左边的空格),再将运算符放在最后(加一个空格)
t = *i;
for (i = i + 2; i != right && !strchr(lsigns, *i); i++) {
if (*i == '(') {
j = BracketMatch(i);
if (!j)return; //表达式有误,括号不成对
while (i != j)*left++ = *i++;
}
*left++ = *i;
}
if (i == right) {
*left++ = ' ';
*left++ = t;
} else {
*left++ = t;
*left++ = ' ';
}
i--;
} else {
//不是括号也不是运算符,直接复制
*left++ = *i;
}
}
}
//预处理,删'$',运算符前后加空格
void expressionPreTreatment(char * str, const char*operators) {
//删'$',r移到str右端
char *l, *r;
r = strchr(str, '$');
if (r) {
*r = '\0';
} else {
r = str + strlen(str);
}
char temp[(r - str) * 2], *t = temp; //2倍一般够了
//遍历,找到运算符就加空格(如果已经有空格就不加了)
for (l = str; l != r; l++) {
if (strchr(operators, *l)) {
if (l[-1] != ' ')*t++ = ' ';
*t++ = *l;
if (l[1] != ' ')*t++ = ' ';
} else {
*t++ = *l;
}
}
*t = '\0';
strcpy(str, temp);
}
int main() {
char expression[1000];
char *l, *r;//l和r分别指向表达式或子表达式(括号里的内容视为子表达式)的左右两端
printf("输入为:");
gets(expression);
expressionPreTreatment(expression, "+-*/");
l = expression;
r = l + strlen(l);
while (1) {
convert(l, r, "*/", "+-*/");
convert(l, r, "+-", "+-");
l = strchr(l, '(');
if (l) {
r = BracketMatch(l);
l++;
} else {
break;
}
}
//去掉括号
for (l = r = expression; *r; r++) {
if (*r != '(' && *r != ')')*l++ = *r;
}
*l = '\0';
printf("输出为:%s\n", expression);
return 0;
}
运行结果(临时套了个死循环)
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<assert.h>
#define INITSIZE 20
#define INCREMENT 10
#define MAXBUFFER 20
#define LEN sizeof(Elemtype)
/*栈的动态分配存储结构*/
typedef char Elemtype;
typedef struct{
Elemtype *base;
Elemtype *top;
int StackSize;
}SqStack;
/*初始化栈*/
void InitStack(SqStack *S)
{
S->base=(Elemtype*)malloc(LEN*INITSIZE);
assert(S->base !=NULL);
S->top=S->base;
S->StackSize=INITSIZE;
}
/*压栈操作*/
void PushStack(SqStack *S,Elemtype c)
{
if(S->top - S->base >= S->StackSize)
{
S->base=(Elemtype*)realloc(S->base,LEN*(S->StackSize+INCREMENT));
assert(S->base !=NULL);
S->top =S->base+S->StackSize;
S->StackSize+=INCREMENT;
}
*S->top++ = c;
}
/*求栈长*/
int StackLength(SqStack *S)
{
return (S->top - S->base);
}
/*弹栈操作*/
int PopStack(SqStack *S,Elemtype *c)
{
if(!StackLength(S))
{
return 0;
}
*c=*--S->top;
return 1;
}
/*中缀转后缀函数*/
int Change(SqStack *S,Elemtype str[])
{
int i=0;
Elemtype e;
InitStack(S);
while(str[i]!='\0')
{
while(isdigit(str[i]))
{/*过滤数字字符,直接输出,直到下一位不是数字字符打印空格跳出循环 */
printf("%c",str[i++]);
if(!isdigit(str[i]))
{
printf(" ");
}
}
/*加减运算符优先级最低,如果栈顶元素为空则直接入栈,否则将栈中存储
的运算符全部弹栈,如果遇到左括号则停止,将弹出的左括号从新压栈,因为左
括号要和又括号匹配时弹出,这个后面单独讨论。弹出后将优先级低的运算符压入栈中*/
if(str[i]=='+'||str[i]=='-')
{
if(!StackLength(S))
{
PushStack(S,str[i]);
}
else
{
do
{
PopStack(S,&e);
if(e=='(')
{
PushStack(S,e);
}
else
{
printf("%c ",e);
}
}while( StackLength(S) && e != '(' );
PushStack(S,str[i]);
}
}
/*当遇到右括号是,把括号里剩余的运算符弹出,直到匹配到左括号为止
左括号只弹出不打印(右括号也不压栈)*/
else if(str[i]==')')
{
PopStack(S,&e);
while(e!='(')
{
printf("%c ",e);
PopStack(S,&e);
}
}
/*乘、除、左括号都是优先级高的,直接压栈*/
else if(str[i]=='*'||str[i]=='/'||str[i]=='(')
{
PushStack(S,str[i]);
}
else if(str[i]=='\0')
{
break;
}
else if(str[i]=='$'){
while(StackLength(S))
{
PopStack(S,&e);
printf("%c ",e);
}
return 0;
}
else
{
printf("\n输入格式错误!\n");
return 0;
}
i++;
}
/*最后把栈中剩余的运算符依次弹栈打印*/
}
int main()
{
Elemtype str[MAXBUFFER];
SqStack S;
gets(str);
Change(&S,str);
getchar();
getchar();
return 0;
}
参考:
#include <iostream>
#include <stack>
#include <cctype>
using namespace std;
int main() {
stack<int> opnd; // 运算数栈
stack<char> optr; // 运算符栈
char c;
while (cin >> c && c != '$') {
if (isdigit(c)) {
// 输出数字
cout << c << ' ';
} else {
// 更新运算符栈
while (!optr.empty() && optr.top() != '(' && (optr.top() == '*' || optr.top() == '/' || (optr.top() == '+' || optr.top() == '-'))) {
// 弹出两个运算数和一个运算符
int b = opnd.top(); opnd.pop();
int a = opnd.top(); opnd.pop();
char op = optr.top(); optr.pop();
// 输出运算符
cout << a << ' ' << b << ' ' << op << ' ';
}
optr.push(c); // 压入新运算符
}
}
// 输出剩余的运算符
while (!optr.empty()) {
// 弹出两个运算数和一个运算符
int b = opnd.top(); opnd.pop();
int a = opnd.top(); opnd.pop();
char op = optr.top(); optr.pop();
// 输出运算符
cout << a << ' ' << b << ' ' << op << ' ';
}
cout << endl;
return 0;
}
#include <iostream>
#include <stack>
#include <string>
// 定义运算符优先级
const int PRIORITY[4] = {0, 1, 1, 2};
// 将字符转化为对应的数字
int charToInt(char c) {
switch (c) {
case '+': return 1;
case '-': return 2;
case '*': return 3;
case '/': return 4;
default: return 0;
}
}
int main() {
std::string expr; // 存储输入的表达式
std::stack<int> opnd; // 运算数栈
std::stack<char> optr; // 运算符栈
std::cout << "输入算数表达式(以$结束):" << std::endl;
std::cin >> expr;
for (int i = 0; i < expr.length(); i++) {
char c = expr[i];
if (c == '$') break; // 结束输入
// 如果是数字,则压入运算数栈
if (c >= '0' && c <= '9') {
opnd.push(c - '0');
}
// 如果是运算符
else {
// 如果是左括号,则压入运算符栈
if (c == '(') {
optr.push(c);
}
// 如果是右括号,则将运算符栈中的运算符依次弹出并输出,直到遇到左括号为止
else if (c == ')') {
while (optr.top() != '(') {
std::cout << optr.top() << " ";
optr.pop();
}
optr.pop(); // 弹出左括号
}
// 如果是运算符,则依次将运算符栈中的运算符弹出并输出,直到遇到优先级更低或者栈为空为止
else {
int currPriority = PRIORITY[charToInt(c)];
while (!optr.empty() && PRIORITY[charToInt(optr.top())] >= currPriority) {
std::cout << optr.top() << " ";
optr.pop();
}
optr.push(c);
}
}
}
// 将运算符栈中剩余的运算符依次弹出并输出
while (!optr.empty()) {
std::cout << optr.top() << " ";
optr.pop();
}
return 0;
}