因爲自身思惟不夠活躍,思考問題邏輯不夠清晰,因此小弟的師傅給小弟我佈置了個做業,字符串表達式求值,以此但願達到鍛鍊我思惟邏輯能力的目的。
歷時14天,完成做業,相關知識以及技術並不高深,目的在於鍛鍊邏輯思惟能力。在此也想跟有相關須要的同窗們分享下解題思路,有不足之處也但願你們不吝賜教,指點出來。謝謝。ios
解決該問題時首先要解決判斷運算符優先級問題,後來瞭解到後綴表達式(即逆波蘭表達式)後,決定先將表達式分解成逆波蘭表達式 ,而後再根據每一個運算符取出數字進行相應的運算。計算到最後即爲表達式的值
涉及string字符串、動態數組vector、逆波蘭表達式(網上由相應的解析,書上並無出現),迭代器(主要起取出以及做轉換範圍使用)的相關知識。數組
低配版(僅支持0-9的正整數計算,能夠計算的運算符包含+ - * / % ^ & |)
代碼以下:`//原型: double Exper(const char * expr);
//使用: double retval = Expr("1*2+(10/4)-3^1234");
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
#include<stack>
#include<cstdio>
using namespace std;app
bool gettruefalse(char a) //判斷當前符號是否爲符號
{
if (a == '+' || a == '-' || a == '*' || a == '/' || a == '%' || \
a == '^' || a == '|' || a == '&' || a == '(' || a == ')')
return true;
else
return false;
}函數
int getpriority(char c)
{
int temp;
if (c == '(')
temp = 6;
else if (c == '*' || c == '/' || c == '%')
temp = 5;
else if (c == '+' || c == '-')
temp = 4;
else if (c == '&')
temp = 3;
else if (c == '^')
temp = 1;
else if (c == '|')
temp = 1;
else if (c == ')') //若是爲')',則一直將符號取出放入新字符串,直到遇到'('(6)
temp = 0;
return temp;
}spa
string getnbl(string str)
{
string ok;//用於存放轉換成後綴表達式的容器
vector<char>flag;//用於存放轉換時的符號容器blog
while (str.length() != 0)//將舊字符串轉換完成前,無限循環
{
for (int a = 0; a < str.length(); a++) //遍歷字符串
{
if (gettruefalse(str[a])) //若是當前字符爲符號
{
//若是符號容器爲空,或者當前符號優先級大於符號容器優先級,或者符號容器最後一個符號爲(,壓入
if (flag.size() == 0 || (getpriority(str[a]) > getpriority(*(flag.end() - 1))) || getpriority(*(flag.end() - 1)) == 6)
{
flag.push_back(str[a]);//將當前符號放入符號容器
str.erase(str.begin(), str.begin() + 1); //截斷舊字符串中的符號
break;//跳出for循環,從新遍歷
}
else if (getpriority(str[a]) == 0) //是)嗎
{
str.erase(str.begin(), str.begin() + 1);//刪掉舊字符串的),並將符號容器的符號移到新字符串,直到遇到(
while (getpriority(*(flag.end() - 1)) != 6)//遇到(以前 無限彈出容器裏的符號
{
ok += *(flag.end() - 1);//將符號容器的符號添加到新字符
flag.erase(flag.end() - 1);//將剛被添加到新字符的字符刪去
}
if ((getpriority(*(flag.end() - 1)) == 6))//將(去掉
{
flag.erase(flag.end() - 1);
break;//跳到開頭while循環處
}
}
else if (getpriority(str[a]) <= getpriority(*(flag.end() - 1))) //當前符號優先級小於或等於符號容器最後一個符號
{
ok += *(flag.end() - 1);//將符號容器的符號添加到新字符
flag.erase(flag.end() - 1);//將剛被添加到新字符的字符刪去
break;
}
}
else //若是當前字符不爲符號(即爲數字或小數點)
{
ok += str[a];//將該數字轉入新的字符串
str.erase(a, 1); //在舊字符串中刪除該數字
break;//跳出for循環,從新開始遍歷
}
}
}
//舊字符串清空後,將臨時存放點的字符串依次取出放入新字符中
while (flag.size() != 0)
{
ok += *(flag.end() - 1);
flag.erase(flag.end() - 1);
}
return ok;
}字符串
int jisuan(int a, char b, int c) //根據符號取數字進行相應的計算
{
int num = 0;//計算結果
if (b == '+')
num = a + c;
else if (b == '-')
num = a - c;
else if (b == '*')
num = a * c;
else if (b == '/')
num = a / c;
else if (b == '%')
num = a % c;
else if (b == '^')
num = a ^ c;
else if (b == '&')
num = a & c;
else if (b == '|')
num = a | c;
else if (b == 'M')
num = a && c;
else if (b == 'N')
num = a || c;
return num;
}get
int getcount(string nbl)
{
vector<int>nums;
int a = 0;
int answer; //存放結果
string zhuanhuan;
while (a < nbl.size())
{
if (gettruefalse(nbl[a]))//若是爲符號
{ //從數字容器中去除倒數第二的數做爲A,最後一個數做爲B,執行該符號的運算
answer = jisuan(*(nums.end() - 2), nbl[a], *(nums.end() - 1));
nums.erase(nums.end() - 2, nums.end());
nums.push_back(answer);
a++;//遍歷下一個字符
}
else //數字時 壓人數字容器
{
zhuanhuan += nbl[a];
answer = atof(zhuanhuan.c_str());
nums.push_back(answer);
zhuanhuan.clear();
a++;
}
}
return *(nums.end() - 1); //容器最後一位數即爲結果
}原型
int main()
{
char ch[100];
cout << "輸入你要計算的字符串表達式(僅支持0-9的正整數運算):" << endl;
gets_s(ch);
cout << "字符串的原內容爲:" << ch << endl;string
string str(ch);//用於進行轉換操做的字符串
string nbl;//用於存放轉換成後綴表達式的容器
nbl = getnbl(str);//調用函數 將字符串轉爲逆波蘭字符串
cout << "轉爲逆波蘭表達式後:" << nbl << endl;
int num = getcount(nbl);
cout << "字符串:" << ch << "的結果爲:" << num << endl;
system("pause");
fflush(stdin);
return 0;
}`
徹底版(此時能夠計算正負的整數(不支持小數點),運算符也包含+ - * / % & && ^ | ||):
```
//原型: double Exper(const char * expr);
//使用: double retval = Expr("1*2+(10/4)-3^1234");
#include<iostream>
#include<string>
#include<vector>
#include<cstdio>
using namespace std;
int gettruefalse(char a) //判斷當前符號是否爲符號
{
if (a == '1' || a == '2' || a == '3' || a == '4' || a == '5' || \
a == '6' || a == '7' || a == '8' || a == '9' || a == '0')
return 2;
else if (a == '+' || a == '-' || a == '*' || a == '/' || a == '%' || \
a == '^' || a == '|' || a == '&' || a == '(' || a == ')' || a == 'M' || a == 'N')
return 1;
else
return 0;
}
int getpriority(char c) //優先級排列
{
int temp;
if (c == '(')
temp = 8;
else if (c == '*' || c == '/' || c == '%')
temp = 7;
else if (c == '+' || c == '-')
temp = 6;
else if (c == '&')
temp = 5;
else if (c == '^')
temp = 4;
else if (c == '|')
temp = 3;
else if (c == 'M') //等同於&&
temp = 2;
else if (c == 'N') //等同於||
temp = 1;
else if (c == ')') //若是爲')',則一直將符號取出放入新字符串,直到遇到'('(6)
temp = 0;
return temp;
}
void getvariant(string &str)
{
int a = 0;//用於遍歷
for (a = 0; a < str.size(); a++) //將原字符串中的-(符號)用相應的標識符替換
{
if ((a == 0) && (str[a] == '-'))
{
str[a] = '.';
}
else if ((str[a] == '-') && (gettruefalse(str[a - 1]) == 1) && (str[a - 1] != ')')) //找到-並確認當前是否爲符號
{
str[a] = '.';
}
}
for (a = 0; a < str.size(); a++) //將原字符串中的||、&&用相應的標識符替代
{
if (str[a] == '|' && str[a + 1] == '|')
{
str[a + 1] = 'N';
str.erase(a, 1);
}
if (str[a] == '&' && str[a + 1] == '&')
{
str[a + 1] = 'M';
str.erase(a, 1);
}
}
}
string getnbl(string str)
{
getvariant(str);//調用函數用標記符替換字符串中的||、&&、-(負號)
string ok;//用於存放轉換成後綴表達式的容器
vector<char>flag;//用於存放轉換時的符號容器
int a = 0;//用於做爲遍歷字符串的下標
int b = a;//!b做爲開始遍歷數字的起始點
while (a <str.length())//遍歷整個字符串
{
if ((gettruefalse(str[a])) == 1)//當前字符爲符號
{
//符號容器爲空或者當前符號優先級大於容器末尾符號優先級,或當前容器末尾爲(,壓入容器
if (flag.size() == 0 || (getpriority(str[a]) > getpriority(*(flag.end() - 1))) \
|| *(flag.end() - 1) == '(')
{
flag.push_back(str[a]);
a++;
}
else if (str[a] == ')') //若是爲) 不壓入,彈出容器符號 直到遇到(
{
while (*(flag.end() - 1) != '(')//當前符號不爲(,則一直彈出容器符號
{
ok += *(flag.end() - 1);
ok += ' '; //每一個符號以空格做爲間隔
flag.erase(flag.end() - 1);
}
flag.erase(flag.end() - 1);//刪掉容器中的(
a++;//跳過')'符號
}
else if (getpriority(str[a]) <= getpriority(*(flag.end() - 1)))//當前符號優先級小於或等於符號容器最後一個符號
{
ok += *(flag.end() - 1);//將符號容器的符號添加到新字符
ok += ' ';
flag.erase(flag.end() - 1);//將剛被添加到新字符的字符刪去
}
}
else //不爲符號,則遍歷字符串找到符號
{
b = a; //記錄當前開始遍歷的位置
while(a<str.size())
{
if ( (gettruefalse(str[a]) == 1)) //噹噹前字符爲符號
{
ok.append(str.begin() + b, str.begin() + a);//將遍歷的起始位置到發現符號的位置的全部字符拼接到新的字符串,並加上空格做爲間隔
ok += ' ';
break; //跳出for循環 從新進行判斷
}
else if ((a==(str.size()-1)) && (gettruefalse(str[a]) == 2)) //已經遍歷到最後一個字符了 且最後一個字符爲數字
{
a++;
ok.append(str.begin() + b, str.begin() + a);//將遍歷的起始位置到發現符號的位置的全部字符拼接到新的字符串,並加上空格做爲間隔
ok += ' ';
break; //跳出for循環 從新進行判斷
}
a++;
}
}
}
while (flag.size() != 0) //遍歷完原字符串後,將符號容器的符號所有彈出
{
ok += *(flag.end() - 1);
ok += ' '; //每一個符號以空格做爲間隔
flag.erase(flag.end() - 1);
}
return ok;
}
int getanswer(int a, char b, int c)
{
int num = 0;//計算結果
if (b == '+')
num = a + c;
else if (b == '-')
num = a - c;
else if (b == '*')
num = a * c;
else if (b == '/')
num = a / c;
else if (b == '%')
num = a % c;
else if (b == '^')
num = a ^ c;
else if (b == '&')
num = a & c;
else if (b == '|')
num = a | c;
else if (b == 'M')
num = a && c;
else if (b == 'N')
num = a || c;
return num;
}
int getcount(string nbl) //計算逆波蘭表達式的
{
int num=0;//結果
string zhuanhuan;
vector<int> nums;//數字容器
int a = 0;//遍歷字符串下標
int b = a;//記錄開始遍歷時的下標
while (a < nbl.size())
{
if (gettruefalse(nbl[a])==1) //當前爲符號
{
if (((nbl[a] == '/') || (nbl[a] == '%')) && (*(nums.end() - 1) == 0)) //計算除法和求餘時,若是被除數爲0,報錯
{
cout << "除數不能爲0,程序退出" << endl;
system("pause");
exit(-1);
}
num = getanswer(*(nums.end() - 2), nbl[a], *(nums.end() - 1));//彈出數字容器的2個數字 並根據符號去計算這2個數字
nums.erase(nums.end() - 2, nums.end());//計算後去掉這2個數字,並將結果從新放入容器中
nums.push_back(num);
a++;//遍歷下一個字符
}
else if (nbl[a] == ' ')
{
a++;
}
else
{
b = a;//記錄開始找空格的位置
while (a<nbl.size())
{
if (nbl[a] == ' ')//找到空格
{
if (nbl[b] == '.') //若是該數爲負數(起始處爲.)
{
nbl[b] = '-'; //將小數點轉換爲負號
}
zhuanhuan.append(nbl.begin() + b, nbl.begin() + a);
num = atof(zhuanhuan.c_str()); //將該字符串轉換爲數字 並壓入數字容器中
zhuanhuan.clear();
nums.push_back(num);
break;
}
a++;
}
}
}
num = *(nums.end() - 1);
return num;
}
int main()
{
char ch[100];
cout << "輸入你要計算的字符串表達式(僅支持整數運算):" << endl;
gets_s(ch);
string str(ch);//用於進行轉換操做的字符串
int s = 0;
while (s < str.size())//檢查用戶輸入表達式是否正確
{
if (gettruefalse(str[s]) == 0)
{
cout << "字符串表達式輸入錯誤" << endl;
system("pause");
return 0;
}
s++;
}
string nbl;//用於存放轉換成後綴表達式的容器
nbl = getnbl(str);//調用函數 將字符串轉爲逆波蘭字符串
int num;//表達式結果
num = getcount(nbl);
cout << "轉爲逆波蘭表達式後:" << nbl << ",.(-)、M(&&)、N(|| )爲標記符"<<endl;
cout << "字符串表達式:" << ch << "的結果爲:" << num << endl;
cout << "結果爲:" << num << endl;
system("pause");
fflush(stdin);
return 0;
}
```
運行結果: