1、基本思路:
先將算術表達式(中綴式)讀入到string對象中,再將其經過相關操作解析並轉換成後綴表達式(存放在一條鏈表中),最後才(遍歷該鏈表)對該表達式進行運算。
2、如何支持浮點數的運算:
a、使用atof()函數,它是C語言標準庫中的一個字符串處理函數,功能是把字符串轉換成浮點數,其頭文件爲<stdlib.h>,該函數名是 "ASCII to floating point numbers" 的縮寫。
語法格式爲:double atof(const char *nptr)。
b、說明:atof()會掃描參數nptr字符串,跳過前面的空格字符,直到遇上數字或正負符號纔開始做轉換,而再遇到非數字或字符串結束時('\0')才結束轉換,並將結果返回。
3、具體實現代碼(含詳細註釋,不懂的地方可以留言):
#include<iostream>
#include<stack>
#include<stdlib.h>
#include<string>
using namespace std;
//使用結點Node類來存儲操作數或運算符
struct Node
{
bool isOperand; //判斷結點裏存儲的是否爲操作數
double operand;
char Operator;
Node* next;
Node(bool isOpd = false, double opd = 0.0, char Opr = ' ')
{
isOperand = isOpd;
operand = opd;
Operator = Opr;
next = nullptr;
}
};
//定義一個Calculator類來存放計算後綴式算術表達式時所需的基本操作
class Calculator
{
public:
Calculator() {}
double runPostfixExpression(Node* head); //執行對後綴式算術表達式的計算
private:
stack<double> st; //存放操作數(double類型)的棧
void addOperand(double value); //操作數進棧
bool get2Operands(double& left, double& right); //從棧中取出(退出)兩個操作數
bool doOperator(char op); //使用該運算符進行一次基本算術運算
};
double Calculator::runPostfixExpression(Node* head)
{
double newOperand;
while (head != nullptr)
{
if (head->isOperand) addOperand(head->operand); //是操作數,直接進棧
else doOperator(head->Operator); //是運算符,執行基本算術運算
head = head->next;
}
newOperand = st.top();
return newOperand;
}
void Calculator::addOperand(double Operand)
{
st.push(Operand);
}
bool Calculator::get2Operands(double& leftOperand, double& rightOperand)
{
if (st.empty())
{
cerr << "缺少右操作數!" << endl;
return false;
}
rightOperand = st.top();
st.pop();
if (st.empty())
{
cerr << "缺少左操作數!" << endl;
return false;
}
leftOperand = st.top();
st.pop();
return true;
}
bool Calculator::doOperator(char op)
{
double left, right, value;
bool result = get2Operands(left, right);
if (result)
{
switch (op)
{
case '+':
value = left + right;
st.push(value);
break;
case '-':
value = left - right;
st.push(value);
break;
case '*':
value = left * right;
st.push(value);
break;
case '/':
if (right == 0.0)
{
cerr << "Divided by 0!" << endl;
return false;
}
else
{
value = left / right;
st.push(value);
}
break;
}
return true;
}
else return false;
}
//isp(in stack priority)爲該算術運算符棧內優先級
int isp(char c)
{
switch (c)
{
case '#': return 0;
case '(': return 1;
case '*':case'/': return 5;
case '+':case '-': return 3;
case ')': return 6;
default: return -1;
}
}
//icp(in coming priority)爲該算術運算符棧外優先級
int icp(char c)
{
switch (c)
{
case '#': return 0;
case '(': return 6;
case '*':case'/': return 4;
case '+':case '-': return 2;
case ')': return 1;
default: return -1;
}
}
Node* infixToPostfix(string str)
{
double operand;
//給中綴算術表達式str末尾添加個字符'#',以便利於後面棧內外運算符優先級比較時出棧的處理
str = str + '#';
Node* head, *current;
stack <char> st;
char charInStack; //存放在棧st中的操作數或運算符
int i = 0;
while (i < str.size())
{
if (isdigit(str[i])) //如果是操作數,則處理(取浮點數)後便可直接存入Node對象中
{
if (i == 0) //處理中綴表達式str中開頭的操作數
{
//讀取該操作數(double類型)並存入Node對象中
operand = atof(&str[i]);
current = new Node(true, operand, 0.0);
head = current; //建立表頭結點
}
else //處理中綴表達式str中的其他操作數
{
//讀取該操作數(double類型)並存入Node對象中
operand = atof(&str[i]);
current->next = new Node(true, operand, 0.0);
current = current->next;
}
while (isdigit(str[i]) || str[i] == '.') //過濾掉(跳過)string轉換double時已被使用的那些char字符
{
i++;
}
}
else //如果是運算符,則進行一系列(棧內外)運算符優先級的比較並結合相關的入棧出棧操作,適時將運算符存入Node對象
{
if (st.empty())
{
if (i == str.size() - 1) break; //若此時棧空且str已被掃描完,則結束循環
else //若此時棧空且str還未被掃描完,則繼續將當前掃描到的運算符進棧
{
st.push(str[i]);
i++;
}
}
else
{
charInStack = st.top();
//棧內運算符優先級<棧外運算符優先級,則將棧外運算符str[i]直接進棧
if (isp(charInStack) < icp(str[i]))
{
st.push(str[i]);
i++;
}
//棧內運算符優先級>棧外運算符優先級,則將棧頂的運算符出棧並將其存入Node對象中
else if (isp(charInStack) > icp(str[i]))
{
charInStack = st.top();
st.pop();
current->next = new Node(false, 0.0, charInStack);
current = current->next;
}
//棧內運算符優先級=棧外運算符優先級,此時只有一種可能,即棧內的'('/')'的優先級與棧外的')'/'('優先級相等且均爲1/6,
//即匹配情況爲“()”或“)(”,此時直接將棧內的運算符出棧,丟棄當前所掃描的str[i] 運算符,繼續掃描下一個運算符
else
{
st.pop();
i++;
}
}
}
}
return head;
}
int main(void)
{
string expression;
while (1)
{
Calculator c;
cout << "請輸入算術表達式:" << endl;
cin >> expression;
cout << "Result = " << c.runPostfixExpression(infixToPostfix(expression)) << endl;
}
return 0;
}
順便附上項目源碼,支持開源精神,歡迎star、fork:
https://github.com/Yuziquan/CalculateArithmeticExpressionForFloatingpoint
(希望可以幫到有需要的人~~)