問題還是挺多:
(1)例如輸入非運算符沒有報錯
(2)對於“(2)”這種無法運算
(3)暫時沒有加入小數,基於整型運算
-----------------------------------------------------------------
(一)用棧實現四則運算
其實每次看到棧的章節的時候都會拿四則運算做例子,這個確實是個很具體的例子,其實遞歸也是一種棧的實現,不過是編譯器幫我們做好了。
實現這個運算難度也不是很大,大家先別急着就要考慮(2+3*3)/(2^(2+1)-3) 這種蛋疼無比的計算,可先從簡單的同類運算開始:
例如:2+3+4
我們計算的時候是這麼進行
2先壓入棧,然後壓入+,再次壓入3
這時候壓入+號,我們知道這次的+號和上次+號是同個運算優先級,所以我們遵從左-》右的計算順序,
彈出3、+、2 求出Calc(2,'+',3) 返回結果,壓入棧5,以及這次+號,然後壓入4 ,運行到結尾,再次出棧4,+,5
計算Calc(5,'+',4);返回9計算完畢
再如:2+3*4+3
同理壓入2,+,3,
到達第二個符號的時候,是*號,優先級高於+號,所以繼續壓入,不彈出。
壓入*,4
這時候用遇到+號這種運算符好,我們知道*號的優先級高,所以先計算3*4
然後壓入結果棧成爲:2+12
這時候判斷之前的加號優先級和現在一樣,繼續出棧計算得棧:4
前面無符號來,加入這時候的+號和3 然後再彈出。。
其實只要遵循這種思路就能把四則運算模擬出來了,當然有人利用兩個棧,一個盛放數字,一個是符號
個人比較喜歡直接一個棧
下面我貼出三個版本,就是按照這種由簡單-->難,不斷完善
版本一看了就好,後面就細節更改,無所謂,而且比較亂。。
//============================================================================
// Name : CalcSimu.cpp
// Author : YLF
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
int CalcSimu(char *str);
int Calc(char num1,char opt,char num2);
int Level(char c);
int CalcSimu2(char *str);
int Calc2(int num1,int opt,int num2);
int Level2(char c);
int CalcSimu3(char *str);
int Calc3(int num1,int opt,int num2);
int Level3(char c);
int main() {
char a[100];
gets(a);
cout<<CalcSimu3(a);
return 0;
}
/**
* 版本一:
* 簡單加算:範圍不能超過128 否則變成負數
* 而且只針對個位數相運算
*/
int CalcSimu(char *str){
int numCount=0,optCount=0;
vector<char> stack;
int curLevel=0,preLevel=0;
while(*str != '\0'){
if(*str>'0' && *str<'9'){
numCount++;
stack.push_back(*str);
}else{
if(optCount == 0){//如果是之前沒有運算符
optCount++;
stack.push_back(*str);
//獲得運算符級別
preLevel = Level(*str);
}else{//之前已經有運算符了
curLevel = Level(*str);
if(preLevel>=curLevel){//之前的運算符優先級更高,直接計算
do{
char num2 = stack.at(stack.size()-1);
stack.pop_back();
char opt = stack.at(stack.size()-1);
stack.pop_back();
char num1 = stack.at(stack.size()-1);
stack.pop_back();
int result = Calc(num1,opt,num2);
int temp = stack.size();
if(stack.size()>1)//如果前一個運算符的優先級也還高,繼續彈出
preLevel = Level(stack.at(stack.size()-1));
stack.push_back(result);
}while(stack.size()>1 && preLevel>=curLevel);
preLevel = curLevel;
}else{//當前運算符更高級別,繼續壓入
preLevel = curLevel;
}
stack.push_back(*str);//把當前運算符壓入
}
}
str++;
}
while(stack.size()>1){
char num2 = stack.at(stack.size()-1);
stack.pop_back();
char opt = stack.at(stack.size()-1);
stack.pop_back();
char num1 = stack.at(stack.size()-1);
stack.pop_back();
int result = Calc(num1,opt,num2);
stack.push_back(result);
}
return stack.at(0);
}
int Calc(char num1,char opt,char num2){
int a = num1-'0';
int b = num2-'0';
int i =0;
int re = 1;
switch(opt){
case '+':
return a+b+'0';
case '-':
return a-b+'0';
case '*':
return a*b+'0';
case '/':
return a/b+'0';
case '%':
return a%b+'0';
case '^':
for(i=0;i<b;i++)
re *=a;
return re+'0';
default:
return 0+'0';
}
}
int Level(char c){
switch(c){
case '+':
case '-':
return 1;
case '*':
case '/':
case '%':
return 2;
case '^':
return 3;
case '(':
case ')':
return 4;
default:
return 0;
}
}
//********************************************
/**
* 改進:
* 2:多位數加入
* 3:求餘問題
*
*/
int CalcSimu2(char *str){
int num=0,optCount=0;
vector<int> stack;
int curLevel=0,preLevel=0;
while(*str != '\0'){
if(*str>='0' && *str<='9'){
do{
num=num*10+(*str-'0');
str++;
}
while(*str>='0' && *str<='9');
stack.push_back(num);//直接壓入整數;
num=0;
str--;
}else{
if(*str == '('){
optCount=0;
str++;
continue;
}
if(optCount == 0){//如果是之前沒有運算符
optCount++;
stack.push_back(*str);
//獲得運算符級別
preLevel = Level2(*str);
}else{//之前已經有運算符了
curLevel = Level2(*str);
if(preLevel>=curLevel){//之前的運算符優先級更高,直接計算
do{
int num2 = stack.at(stack.size()-1);
stack.pop_back();
int opt = stack.at(stack.size()-1);
stack.pop_back();
int num1 = stack.at(stack.size()-1);
stack.pop_back();
int result = Calc2(num1,opt,num2);
int temp = stack.size();
if(stack.size()>1){//如果前一個運算符的優先級也還高,繼續彈出
preLevel = Level2(stack.at(stack.size()-1));
}
stack.push_back(result);
}while(stack.size()>1 && preLevel>=curLevel);
preLevel = curLevel;
}else{//當前運算符更高級別,繼續壓入
preLevel = curLevel;
}
stack.push_back(*str);//把當前運算符壓入
}
}
str++;
}
while(stack.size()>1){
int num2 = stack.at(stack.size()-1);
stack.pop_back();
int opt = stack.at(stack.size()-1);
stack.pop_back();
int num1 = stack.at(stack.size()-1);
stack.pop_back();
int result = Calc2(num1,opt,num2);
stack.push_back(result);
}
return stack.at(0);
}
int Calc2(int num1,int opt,int num2){
int a = num1;
int b = num2;
int i =0;
int re = 1;
switch(opt){
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
case '/':
return a/b;
case '%':
return a%b;
case '^':
for(i=0;i<b;i++)
re *=a;
return re;
default:
return 0;
}
}
int Level2(char c){
switch(c){
case ')':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '%':
return 3;
case '^':
return 4;
case '(':
return 5;
default:
return -1;
}
}
//********************************************
/**
* 改進:
* 1:括號問題
* 2:float類型
*/
int CalcSimu3(char *str){
int num=0,optCount=0;
vector<int> stack;
int curLevel=0,preLevel=0;
while(*str != '\0'){
if(*str>='0' && *str<='9'){
do{
num=num*10+(*str-'0');
str++;
}
while(*str>='0' && *str<='9');
stack.push_back(num);//直接壓入整數;
num=0;
str--;
}else{
if(*str == '('){//如果出現左括號,則當成新的一次計算,因爲它的優先級最高了
optCount=0;
stack.push_back(*str);
str++;
continue;
}
if(optCount == 0){//如果是之前沒有運算符
optCount++;
stack.push_back(*str);
//獲得運算符級別
preLevel = Level3(*str);
}else{//之前已經有運算符了
curLevel = Level3(*str);
if(preLevel>=curLevel){//之前的運算符優先級更高,直接計算
do{
int num1,num2,result,opt;
if(stack.size()>=3){
num2 = stack.at(stack.size()-1);
stack.pop_back();
opt = stack.at(stack.size()-1);
stack.pop_back();
num1 = stack.at(stack.size()-1);
stack.pop_back();
result = Calc3(num1,opt,num2);
}
if(stack.size()>=1){//如果前一個運算符的優先級也還高,繼續彈出
opt = stack.at(stack.size()-1);//取出前一個運算符
if(opt == '(' && *str == ')'){
stack.pop_back();//彈出這個左括號
str++;
if(*str != '\0')
curLevel=Level3(*str);
else{
stack.push_back(result);
break;
}
if(stack.size()!=0)//如果這時候退到起始點了
opt = stack.at(stack.size()-1);
}
else if(opt == '('){
optCount=1;
stack.push_back(result);//左括號不用彈出,因爲還沒有遇見右括號
break;
}
if(stack.size()!=0)
preLevel = Level3(opt);
else
optCount=0;
}
stack.push_back(result);
}while(stack.size()>1 && preLevel>=curLevel);
if(*str == '\0')
break;
preLevel = curLevel;
}else{//當前運算符更高級別,繼續壓入
preLevel = curLevel;
}
stack.push_back(*str);//把當前運算符壓入
}
}
str++;
}
while(stack.size()>1){
int num2 = stack.at(stack.size()-1);
stack.pop_back();
int opt = stack.at(stack.size()-1);
stack.pop_back();
int num1 = stack.at(stack.size()-1);
stack.pop_back();
int result = Calc3(num1,opt,num2);
stack.push_back(result);
}
return stack.at(0);
}
int Calc3(int num1,int opt,int num2){
int a = num1;
int b = num2;
int i =0;
int re = 1;
switch(opt){
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
case '/':
return a/b;
case '%':
return a%b;
case '^':
for(i=0;i<b;i++)
re *=a;
return re;
default:
return 0;
}
}
int Level3(char c){
switch(c){
case ')':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '%':
return 3;
case '^':
return 4;
case '(':
return 5;
default:
return -1;
}
}
(2+3*3)/(2^(2+1)-3)
2
(2+4*3)/(2^2-1)
4
(2+3)+2
(二)用二叉樹實現四則運算
二叉樹實現的結構似乎看起來更清晰:
只要遵循優先級高的在下層,低的在上層即可,每次更新root
見Calc類的實現 主要是Add函數
void Add(int value){
Node* p = new Node();
p->value = value;
p->p = NULL;
p->left = NULL;
p->right = NULL;
//讀入數字
if(isNum(value)){
if(root == NULL)
root = p;
else{
root->right = p;
p->p = root;
}
}else{//讀入的是運算符號
while(root->p!=NULL && Level(root->value)>=Level(value))
root = root->p;
if(Level(root->value)>=Level(value)){
p->left = root;
root->p = p;
root = p;
}else{//高優先級放在數的下方,即越底層,運算優先級越大
p->left = root->right;
root->right->p = p;
root->right = p;
p->p = root;
root = p;
}
}
}
我這裏如果是數字,則正常加入,如果是符號,先根據優先級找到插入位置,然後插入!
//============================================================================
// Name : CalcBTree.cpp
// Author : YLF
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
using namespace std;
/*
* 四則運算,數據結構採用二叉樹
*/
struct Node{
int value;
Node* p;
Node* left;
Node* right;
};
class Calc{
private:
Node* root;
private:
void InVisit(Node* p){
if(p==NULL)
return;
InVisit(p->left);
Visit(p->value);
InVisit(p->right);
}
void Visit(int value){
if(value>='0' && value<='9')
cout<<value-'0';
else{
cout<<(char)value;
}
}
bool isNum(int value){
if(value>='0' && value<='9')
return true;
return false;
}
bool isOpt(int value){
return false;
}
int Cal(int a, int opt, int b){
a = a-'0';
b=b-'0';
int i = 0;
int re = 1;
switch(opt){
case '+':re = a+b;break;
case '-':re = a-b;break;
case '*':re = a*b;break;
case '/':re = a/b;break;
case '^':
for(i=0;i<b;i++)
re *= a;
break;
case '%':re =a%b;break;
default:
cerr<<"opt error!";
return -1;
}
return re+'0';
}
void getResult(Node* p){
if(isNum(p->left->value) && isNum(p->right->value)){
int value = Cal(p->left->value,p->value,p->right->value);
p->value = value;
delete p->left;
delete p->right;
p->left = NULL;
p->right = NULL;
return;
}
if(!isNum(p->left->value))
getResult(p->left);
if(!isNum(p->right->value))
getResult(p->right);
if(isNum(p->left->value) && isNum(p->right->value)){
int value = Cal(p->left->value,p->value,p->right->value);
p->value = value;
delete p->left;
delete p->right;
p->left = NULL;
p->right = NULL;
return;
}
}
int Level(int c){
switch(c){
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
default:
return 100;
}
}
public:
Calc(){
root = NULL;
}
~Calc(){}
void Add(int value){
Node* p = new Node();
p->value = value;
p->p = NULL;
p->left = NULL;
p->right = NULL;
//讀入數字
if(isNum(value)){
if(root == NULL)
root = p;
else{
root->right = p;
p->p = root;
}
}else{//讀入的是運算符號
while(root->p!=NULL && Level(root->value)>=Level(value))
root = root->p;
if(Level(root->value)>=Level(value)){
p->left = root;
root->p = p;
root = p;
}else{//高優先級放在數的下方,即越底層,運算優先級越大
p->left = root->right;
root->right->p = p;
root->right = p;
p->p = root;
root = p;
}
}
}
int getResult(){
getResult(root);
return root->value-'0';
}
void Print(){
while(root->p != NULL)
root = root->p;
InVisit(root);
}
};
int main() {
Calc c;
char in=0;
// c.Add('3');
// c.Add('+');
// c.Add('3');
while(true){
cin>>in;
if(in != '='){
c.Add(in);
}else
break;
}
c.Print();
cout<<"="<<c.getResult();
return 0;
}
這裏我侷限在個位數運算,不能超過十位數。。。。因爲isNum()只判斷來0-9
8/2+1-3+2^2=
8/2+1-3+2^2=6
就是給個思路罷了。。。