一、算符優先法
前提
算符優先法需要設立兩個棧。(本來不應該是這兩個單詞,但是本教主覺得更加重要的是命名的易區分性)
- 寄存操作數的棧
nums
- 寄存操作符的棧
opters
基本思想
-
首先置
nums
棧爲空,表達式起始符#
爲opters
棧的棧底元素 -
依次讀入表達式中的每個字符,用
isOpters()
判斷是否是操作數-
如果是操作數則進
nums
棧 -
如果是操作符,則將棧頂元素和該操作符比較優先級(棧頂操作符和該操作符比較優先級)循環進行直到讀取到截斷符號
#
- 若棧頂操作符優先級低,則將該操作符入棧
- 如果相等,那麼就說明是括號,成對消去(彈出棧中的左括號即可)
- 如果棧頂操作符優先級高,則說明棧頂的操作符就是目前需要參與運算的運算符。
-
更簡單的後綴表示法
- 只需一個操作數棧
- 將中綴表達式轉換爲後綴表達式,因爲計算機更擅長於處理後綴表達式。(參考博客中綴表達式轉後綴表達式(c++))
- 操作數棧彈出兩個操作數,和剩下的操作符參與運算
二、源碼
caculate.h
文件
-
相比較從黑窗口讀取緩存區的字符,直接處理字符串的情況顯得更加大衆一點兒,所以選擇了將中綴表達式存放在字符串中。
-
string
類重載了[]
符號,因而可以像字符數組一樣直接使用str[i]
來獲取string
對象的第i個位置的字符。 -
將表示
int
的char
型轉換爲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;
}