【算符優先法】——表達式求值

一、算符優先法


前提

算符優先法需要設立兩個棧。(本來不應該是這兩個單詞,但是本教主覺得更加重要的是命名的易區分性)

  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;
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章