(請看下一篇改進版)
本來是想寫一個逆波蘭的,寫着寫着就寫歪了,寫成了直接處理表達式字符串並輸出結果,寫的差不多了才發現逆波蘭
比這樣寫應該要簡單,也可能是我的思路有問題吧,還有一些需要優化的地方以後再說吧。
主要的思路是這樣的,先處理括號,把一個帶括號的表達式分解成前段,括號內的內容爲中段,括號後面的內容分爲
後段,遞歸處理中段括號內的字符串,因爲這樣可以完美的處理好括號的問題,然後把不帶括號的表達式傳遞給計算不帶
括號的表達式的函數,先掃描一遍字符串的高階運算*和/,同理把字符串分成前段,2個操作數和中間的符號,還有後面的
內容,當字符串的所有高階運算處理完成之後,就傳遞給下一個只處理+和-運算的函數,因爲還沒有寫負負得正這些規則
,所以目前只能處理2個(包括2個)以下的負號,處理+-運算的時候也是用的和上述方法同樣的原理,把表達式分割成一
個帶一個操作符號和2個操作數的字符串和後面的字符串,這樣遞歸了3層之後,就得到了最終的結果了.
#include "reverse_polish.h"
void reverse_polish()
{
string st;
cout << "輸入一個表達式" << endl;
cin >> st;
cout<<main_logic(st);
}
//處理括號
string main_logic(string st)
{
if (0 == check_parentheses(st))
{
return calculate(st);
}
else
{
string start = "", mid = "", end = "";//將字符串分割成第一個正括號前面,第一個反括號後面,還有中間,中間的遞歸
int count = check_parentheses(st);
auto it = st.begin(), mid_s = it, mid_e = it, temp = it;
while (it != st.end())
{
if (*it == ')')
{
break;
}
++count;
++it;
}
mid_e = it;
while (it != st.begin())
{
if (*it == '(')
{
break;
}
--count;
--it;
}
mid_s = it;
if (mid_s != st.begin())
{
temp = st.begin();
while (temp != mid_s)
{
start += *temp;
++temp;
}
}
if (mid_s != mid_e)
{
temp = mid_s + 1;
while (temp != mid_e)
{
mid += *temp;
++temp;
}
}
if (mid_e != st.end())
{
temp = mid_e + 1;
while (temp != st.end())
{
end += *temp;
++temp;
}
}
return main_logic(start + main_logic(mid) + end);
}
}
int check_parentheses(string st)
{
int count = 0;
for (auto it : st)
{
if (it == '(')
{
++count;
}
}
return count;
}
//處理不帶括號的表達式並把結果轉換成string輸出
string calculate(string st)
{
if (0 == check_high(st))
{
return calculate_low(st);
}
else
{
string start = "", mid = "", end = "", temp = "";//處理字符串中的高階乘除法
auto it = st.begin(), start_m = it, end_m = it, point= st.begin();
while (*it != '*'&&*it != '/')
{
++it;
}
point = it + 1;
while (point != st.end())
{
if (*point == '+' || *point == '-' || *point == '*' || *point == '/')
{
if (point != it + 1)
{
break;
}
}
++point;
}
end_m = point;//確定乘除號後面的操作數
point = it;
while (point != st.begin())
{
if (*point == '+' || *point == '-'&&*(point - 1) != '+'&&*(point - 1) != '-')
{
break;
}
--point;
}
start_m = point;//確定乘除號前面的操作數
if (start_m != st.begin())
{
point = st.begin();
while (point != start_m + 1)
{
start += *point;
++point;
}
}
if (end_m != st.end() - 1)
{
point = end_m;
while (point != st.end())
{
end += *point;
++point;
}
}
if (start_m != st.begin())
{
point = start_m + 1;
}
else
{
point = start_m;
}
while (point != end_m)
{
mid += *point;
++point;
}
return calculate(start + calculate_high(mid) + end);
}
}
string calculate_low(string st)
{
if (0 == check_low(st))
{
return st;
}
else
{
string next;
double total = atof(st.c_str());
int count = 0;
auto it = st.begin();
if (*it == '-' || *it == '+')
{
if (*(it + 1) != '+'&&*(it + 1) != '-')
{
++count;
++it;
}
}
while (*it != '+' && *it != '-')
{
++count;
++it;
}
if (*it == '+')
{
total += atof(st.c_str() + count + 1);
}
else
{
total -= atof(st.c_str() + count + 1);
}
while (*it < '0' || *it > '9')
{
++count;
++it;
}
while (*it != '+' && *it != '-')
{
++count;
++it;
if (it == st.end())
{
break;
}
}
if (it != st.end())
{
while (it != st.end())
{
next += *it;
++it;
}
}
return calculate_low(to_string(total) + next);
}
}
string calculate_high(string st)
{
int count = 0;
auto it = st.begin();
double total = atof(st.c_str());
string temp;
while (*it != '*'&&*it != '/')
{
++count;
++it;
}
if (*it == '*')
{
total *= atof(st.c_str() + count + 1);
}
else
{
total /= atof(st.c_str() + count + 1);
}
temp = to_string(total);
return temp;
}
int check_high(string st)
{
int count = 0;
for (auto it : st)
{
if (it == '*' || '/' == it)
{
++count;
}
}
return count;
}
int check_low(string st)
{
int count = 0;
auto it = st.begin();
if (*it == '+' || *it == '-')
{
++it;
}
for (; it != st.end(); ++it)
{
if (*it == '+' || '-' == *it)
{
++count;
}
}
return count;
}
因爲本人比較懶,就沒怎麼寫註釋,見諒.
頭文件和main文件
#include <iostream>
#include <string>
#include <stack>
using namespace std;
void reverse_polish();
string main_logic(string st);
int check_parentheses(string st);
string calculate(string st);
string calculate_high(string st);
string calculate_low(string st);
int check_high(string st);
int check_low(string st);
#include "reverse_polish.h"
int main()
{
reverse_polish();
system("pause");
return 0;
}
其實寫到了這裏就差不多實現了我想要的功能了,可能會改進處理多個無意義的運算符號的功能。
幾經修改,修正了大概10個左右的bug,現在應該問題很小了.