【算符优先法】——表达式求值

博客介绍了算符优先法求解表达式,需设立操作数和操作符两个栈,阐述其基本思想,还提及更简单的后缀表示法,只需一个操作数栈,将中缀转后缀表达式处理。此外,给出源码,包括将中缀表达式存于字符串及算符间优先关系等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、算符优先法


前提

算符优先法需要设立两个栈。(本来不应该是这两个单词,但是本教主觉得更加重要的是命名的易区分性)

  1. 寄存操作数的栈nums
  2. 寄存操作符的栈opters

基本思想

  1. 首先置nums栈为空,表达式起始符#opters栈的栈底元素

  2. 依次读入表达式中的每个字符,用isOpters()判断是否是操作数

    1. 如果是操作数则进nums

    2. 如果是操作符,则将栈顶元素和该操作符比较优先级(栈顶操作符和该操作符比较优先级)循环进行直到读取到截断符号#

      1. 若栈顶操作符优先级低,则将该操作符入栈
      2. 如果相等,那么就说明是括号,成对消去(弹出栈中的左括号即可)
      3. 如果栈顶操作符优先级高,则说明栈顶的操作符就是目前需要参与运算的运算符。

更简单的后缀表示法

  1. 只需一个操作数栈
  2. 将中缀表达式转换为后缀表达式,因为计算机更擅长于处理后缀表达式。(参考博客中缀表达式转后缀表达式(c++)
  3. 操作数栈弹出两个操作数,和剩下的操作符参与运算



二、源码


caculate.h文件

  1. 相比较从黑窗口读取缓存区的字符,直接处理字符串的情况显得更加大众一点儿,所以选择了将中缀表达式存放在字符串中。

  2. string类重载了[]符号,因而可以像字符数组一样直接使用str[i]来获取string对象的第i个位置的字符。

  3. 将表示intchar型转换为int型,最常用的办法是利用ASCII表,直接减去'\0'的ASCII值48就可以获取对应的int值。

#pragma once
#ifndef caculate_H
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;

//算符优先法
class Caculate {
public:
	static const char ERROR = 'E';
	stack<int> nums;														//操作数栈
	stack<char> opters;														//操作符栈
	string expression;														//中缀表达式

public:
	Caculate(string expression) {
		this->expression = expression;
	}

	//计算结果
public:
	int caculate() {
		int i = 0;															//用来读取下一位的位置指针
		//1.将 # 入栈
		opters.push('#');
		while (expression[i] != '#' || opters.top() != '#') {
			//2.如果是操作数,则入栈
			if (!this->isOpters(expression[i])) {
				nums.push(expression[i] - 48);
				i++;
			}
			//3.如果是操作符,则与栈顶符号比较优先级,来决定是否计算
			else if (this->isOpters(expression[i])) {
				switch (this->compare(opters.top(), expression[i])) {
				case '<':													//栈顶元素优先级低:符号入栈
					opters.push(expression[i]);
					i++;
					break;
				case '=':													//优先级相等:说明是栈顶的 ( 和 expression的 ),则消去一对括号
					opters.pop();
					i++;
					break;
				case '>':													//栈顶元素优先级高:计算并将计算结果入栈
					int opval2 = nums.top();
					nums.pop();
					int opval1 = nums.top();
					nums.pop();
					//将计算结果入栈
					int result = this->caculate(opval1, opters.top(), opval2);
					nums.push(result);
					//弹出运算符
					opters.pop();
					break;
				}
			}
		}
		//4.计算完后返回栈顶元素
		return nums.top();
	}


	//计算两个数的结果
public:
	int caculate(int a, char opters, int b) {
		if (opters == '+') {
			return a + b;
		} else if (opters == '-') {
			return a - b;
		} else if (opters == '*') {
			return a * b;
		} else if (opters == '/') {
			return a / b;
		} else {
			cout << "操作符有误!";
			return 0;
		}
	}


	//判断是否是操作符
public:
	bool isOpters(char opters) {
		return (opters == '+' ||
			opters == '-' ||
			opters == '*' ||
			opters == '/' ||
			opters == '(' ||
			opters == ')' ||
			opters == '#') ? true : false;
	}


	//比较操作符的优先级
public:
	char compare(char op1, char op2) {
		if (op1 == '+' || op1 == '-') {
			if (op2 == '+' || op2 == '-' || op2 == ')' || op2 == '#') {
				return '>';
			} else {
				return '<';
			}
		} else if (op1 == '*' || op1 == '/') {
			if (op2 == '(') {
				return '<';
			} else {
				return '>';
			}
		} else if (op1 == '(') {
			if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == '(') {
				return '<';
			} else if (op2 == ')') {
				return '=';
			} else {
				cout << "输入有误";
				return ERROR;
			}
		} else if (op1 == ')') {
			if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == ')' || op2 == '#') {
				return 1;
			} else if (op2 == '(') {
				cout << "输入有误";
				return ERROR;
			}
		} else if (op1 == '#') {
			if (op2 == ')') {
				cout << "输入有误";
				return ERROR;
			} else if (op2 == '#') {
				return 0;
			} else {
				return '<';
			}
		}
	}
};
#endif // !caculate_H

算符间的优先关系

在这里插入图片描述

	//比较操作符的优先级
public:
	char compare(char op1, char op2) {
		if (op1 == '+' || op1 == '-') {
			if (op2 == '+' || op2 == '-' || op2 == ')' || op2 == '#') {
				return '>';
			} else {
				return '<';
			}
		} else if (op1 == '*' || op1 == '/') {
			if (op2 == '(') {
				return '<';
			} else {
				return '>';
			}
		} else if (op1 == '(') {
			if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == '(') {
				return '<';
			} else if (op2 == ')') {
				return '=';
			} else {
				cout << "输入有误";
				return ERROR;
			}
		} else if (op1 == ')') {
			if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == ')' || op2 == '#') {
				return 1;
			} else if (op2 == '(') {
				cout << "输入有误";
				return ERROR;
			}
		} else if (op1 == '#') {
			if (op2 == ')') {
				cout << "输入有误";
				return ERROR;
			} else if (op2 == '#') {
				return 0;
			} else {
				return '<';
			}
		}
	}

main.cpp文件

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

int main() {
	Caculate c("3*(7-2)#");
	int m = c.caculate();
	cout << m << endl;
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值