1. 程式人生 > >c++棧實現簡單計算器

c++棧實現簡單計算器

/* 棧實現計算器,主要思路就是設定一個符號棧和一個數字棧,在字串首尾各加一個'#',然後掃描字串,
 * 如果是數字進數字棧,如果是運算子號先判斷符號優先順序,若棧外符號優先順序大於棧內符號優先順序則進棧,
 * 小於棧內優先順序則符號棧出棧一位,數字棧出棧兩位進行計算,結果重新存進數字棧,直到棧外優先順序大於棧內,
 */
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath> 
using namespace std;
const int MAX = 30;
const int DONE = 1;

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//棧定義 
template <class T>
class Stack{
public:
	Stack(int MaxStackSize=10);
	~Stack() { delete [] stack;}
	bool IsEmpty() const {return top==-1;}
	bool IsFull() const {return top==MaxTop;}
	T Top() const;
	Stack<T>& Add(const T& x);
	Stack<T>& Del(T& x);
	void MakeEmpty(){top=-1;} //清空棧
	void print(){
		for(int i; i < top + 1; i ++){
			cout<<stack[i]<<'\t';
		}
		cout<<endl;
	}
private:
	int top;//棧頂
	int MaxTop;//最大的棧頂值
	T *stack;//堆疊元素陣列
};
template<class T>
Stack<T>::Stack(int MaxStackSize){
	MaxTop=MaxStackSize-1;
	stack=new T[MaxStackSize];
	top=-1;
}
template<class T>
Stack<T>& Stack<T>::Add(const T& x){
	if(IsFull())
	{cout<<"no memory;"<<endl;return *this;}
	top=top+1;
	stack[top]=x;
	return *this;    
}
template<class T>
Stack<T>& Stack<T>::Del(T& x){
	if(IsEmpty())
	{cout<<"no element"<<endl;return *this;}
	x=stack[top];
	top=top-1;
	return *this;
}
template<class T>
T Stack<T>::Top() const{
	return stack[top];
}

//判斷一個字元是否為數字
bool isNum(char c){
	if((c > '0'||c == '0')&&(c < '9'||c == '9'))
		return true;
	else
		return false;
}

//刪除字串中的空格 
void deleteBlank(string &s){
	string::iterator i = s.begin();
	while ((i=find(i, s.end(), ' '))!=s.end())
        s.erase(i);
} 

//計算器
class Calculator{
public:
	Calculator(string s);
	~Calculator();
	int outPriority(char);      //返回棧外優先順序
	int inPriority(char);       //返回棧內優先順序 
	bool judgePri(char, char);  //判斷優先順序 前一個為棧外符號,後一個為棧內符號 若前大於後返回1,否則返回0 
	int judgePri(char);         //判斷運算子  若是'#'返回 -1,若是')'返回 0,否則返回 1 
	void dealNum(); 	    //處理資料	
	int calculate();            //計算 
	void setString(string const s){
		this->s = '#' + s + '#';
		deleteBlank(this->s);   //刪除字串中的空格 
	}
private:
	Stack<char> *s_sym;         //符號棧 
	Stack<int> *s_num;          //資料棧 
	string s;
};
Calculator::Calculator(string s){
	this->s = '#' + s + '#';
	deleteBlank(this->s);
	s_sym = new Stack<char>(MAX);
	s_num = new Stack<int>(MAX);
} 
Calculator::~Calculator(){
	delete s_sym;
	delete s_num;
}
int Calculator::outPriority(char symble){
	switch(symble){
		case '#':
			return 0;
		case '(':
			return 8;
		case '+':
			return 2;
		case '-':
			return 2;
		case '*':
			return 4;
		case '/':
			return 4;
		case '%':
			return 4;
		case '^':
			return 6;
		case ')':
			return 1;
		default:
			throw 1;
	}
}
int Calculator::inPriority(char symble){
	switch(symble){
		case '#':
			return 0;
		case '(':
			return 1;
		case '+':
			return 3;
		case '-':
			return 3;
		case '*':
			return 5;
		case '/':
			return 5;
		case '%':
			return 5;
		case '^':
			return 7;
		case ')':
			return 8;
		default:
			throw 1;
	}
}
bool Calculator::judgePri(char out, char in){
	if(outPriority(out) > inPriority(in))
		return true;
	else 
		return false;
} 
int Calculator::judgePri(char symble){
	if(symble == '#')
		return -1;
	else if(symble == ')')
		return 0;
	else
		return 1;
}
void Calculator::dealNum(){
	//將資料棧中的前兩個彈出進行計算,結果放回資料棧,符號棧彈出頂部元素 
	char _temp = 0; 
	int dtemp1 = 0;
	int dtemp2 = 0; 
	s_sym->Del(_temp);
	s_num->Del(dtemp1);
	s_num->Del(dtemp2); 
	switch(_temp){
		case '+':
			dtemp2 += dtemp1;
			break;
		case '-':
			dtemp2 = dtemp2 - dtemp1;
			break;
		case '*':
			dtemp2 = dtemp2 * dtemp1;
			break;
		case '/':
			if(dtemp1 == 0)
				throw 0;
			else
				dtemp2 = dtemp2 / dtemp1;
			break;
		case '%':
			dtemp2 = dtemp2 % dtemp1;
			break;
		case '^':
			dtemp2 = pow(dtemp2,dtemp1);
			break;
		default:
			throw 1;
	}
	s_num->Add(dtemp2);
}
int Calculator::calculate(){  
	for(int i = 0; i < s.size(); i ++){   //遍歷字串 
		if(isNum(s[i])){
			int temp = (int)(s[i]) - 48;  //char強制型別轉換為int ascii 碼數值,減 48 轉換為對應整數值 
			int _temp = 0;
			if(i > 0 && isNum(s[i - 1])){
				s_num->Del(_temp);
				temp = _temp * 10 + temp;
			}
			s_num->Add(temp);
		}else{ 
			char temp = s[i];
			if(s_sym->IsEmpty()){
				s_sym->Add(temp);
			}else{
				if(judgePri(temp, s_sym->Top())){
					s_sym->Add(temp);  
				}else   if(judgePri(temp) == 1){          //棧外優先順序小於棧內優先順序,且不為 '#' 和 ')' 
					while(!judgePri(temp, s_sym->Top())){ //當棧外優先順序比棧內優先順序低時,執行棧內符號運算 
						dealNum();
					}
					s_sym->Add(temp);
				
				}else if (judgePri(temp) == -1){
					while(s_sym->Top() != '#'){
						dealNum();
					}
					int result = s_num->Top();
					s_sym->MakeEmpty();
					s_num->MakeEmpty();
					return result;
				}
				else if(judgePri(temp) == 0){
					while(s_sym->Top() != '('){
						dealNum();
					}
					s_sym->Del(temp);
				}
			}
		}
	}
}

int main(int argc, char** argv) {
	try{
		string s = "";
		Calculator c(s);
		while(DONE){
			s = "";
			cout<<"請輸入一個表示式"<<endl;
			getline(cin, s);   
			c.setString(s);
			int result = 0;
		    result = c.calculate();
	    	cout<<c.calculate()<<endl;
	    	system("pause");
	    	system("cls");
		}
	}
    catch(int i){
    	if(i == 0)
    		cout<<"除數不能為0!";
    	else if(i == 1)
    		cout<<"存在無法識別的符號!"<<endl;
	} 
	return 0;
}