棧的儲存結構及相關操作

棧的儲存結構及相關操作

1.實現棧的存儲結構及相關操作:進棧、出棧、取棧頂元素等
2.使用該棧完成一個字符串的逆序輸出
3.使用該棧完成表達式的括號是否匹配?
4.對算術表達式求值

界面

主要的相關實現函數

template <class T>
class Stack{
	private:
		T* elements;//存放棧中元素的數組
		int top;//棧頂元素的指針
		int maxSize;//棧的最大容納元素個數
		//void overflowProcess();//棧的溢出處理操作
	public:
		Stack(int size=basesize)//構造函數
		{
			if(size>0){
				maxSize=size;
				top=-1;
				creatStack(size);
			}
		}
		~Stack(){delete []elements;}//析構函數,釋放棧的空間
		
		void creatStack(int n);//創建一個大小爲n的棧,併爲其動態分配空間
		
		void Push(const T& x);//元素x入棧
		
		bool Pop(T& x);//棧頂元素出棧
		
		bool isFull();//判滿函數
		
		bool isEmpty();//判空函數
		
		int getMaxsize()//得到棧的最大體積
		{return maxSize;}
		
		T getTopelements();//得到棧頂元素
		
		int getTop()//得到棧的top指針的地址,因爲是採用數組類型儲存,因此top指針可以利用數組的下標得到
		{return top;}
		
		void print(string tape);//展示各種類型的數據,控制格式
		
		bool writeToFile(string filename);//將數據寫入指定文件
		
		bool readFromFile(string filename);//將數據從指定文件讀入
};

棧的各個函數的實現

創建一個大小爲n的棧

template <class T>
inline void Stack<T>::creatStack(int n)
{
	elements = new T(n);
	
	if(elements==NULL){
		cout<<"動態分配錯誤!"<<endl;
	}
}

元素x入棧

//如果棧isFull(),則進行溢出處理,否則將其插入到棧頂
template <class T>
inline void Stack<T>::Push(const T &x)
{
	if(isFull()==true){
		//overflowProcess();//溢出處理,調整空間大小
	}
	
	else{
		elements[++top]=x;//將x入棧
	}
}
### 棧頂元素出棧,以x的引用返回

```cpp
//棧頂元素出棧,如果棧爲空返回false;若棧不爲空,棧頂元素出棧,top指針減一
template <class T>
inline bool Stack<T>::Pop(T& x)
{
	if(isEmpty())return false;
	
	else{
		
		x=getTopelements();
		
		top--;
		return true;
	}
}

判滿函數

//判斷棧是否滿,如果滿返回true,未滿返回false
template <class T>
inline bool Stack<T>::isFull()
{
	if(this->getTop()<this->getMaxsize()){
		return false;
	}
	else{
		return true;
	}
}

判空函數

//判斷棧是否空,如果滿返回true,未滿返回false
template <class T>
inline bool Stack<T>::isEmpty()
{
	if(this->getTop()==-1){
		return true;
	}
	else{
		return false;
	}
}

打印

template <class T>
inline void Stack<T>::print(string tape)
{
	if(isEmpty()){
		
		cout<<"This Stack is empty!"<<endl;
	}
	
			for(int i=0;i<getTop();i++)
			{
				cout<<"["<<elements[i]<<"]<-";
			}
			
			cout<<"["<<elements[getTop()]<<"]"<<endl;
		
}

得到棧頂元素

template <class T>
inline T Stack<T>::getTopelements()
{
		return elements[getTop()];
}

文件相關讀寫操作

template <class T>
inline bool Stack<T>::writeToFile(string filename)
{
	ofstream writefile(filename);
	T temp[basesize];
	T x;
	int i,count;
	count=getTop()+1;
	writefile<<count<<endl;
	for(i=0;i<count;i++){
		temp[i]=getTopelements();
		Pop(x);
	}
	for(int j=count-1;j>=0;j--)
	{
		writefile<<temp[j]<<endl;
	}
	return true;
}
template <class T>
inline bool Stack<T>::readFromFile(string filename)
{
	ifstream readfile(filename);
	int len;
	readfile>>len;
	for(int i=0;i<len;i++)
	{
		T temp;
		readfile>>temp;
		this->Push(temp);
	}
	return true;
}

利用棧實現字符串的逆序

void reverseString(char temp[])
{
	int len=strlen(temp);
	Stack<char> st;
	char x;
	char str[len+1];
	//str[len]='\0';
	for(int i=0;i<len;i++)
	{
		st.Push(temp[i]);
	}
	
	for(int i=0;i<len;i++)
	{
		str[i]=st.getTopelements();
		st.Pop(x);
	}
	str[len]='\0';
	cout<<"逆序後的字符串爲:"<<str<<endl;
}

利用棧實現括號是否匹配的判斷

void bracketMatching(char expression[])
{
	Stack<int> stack;
	int j;
	int len=strlen(expression);
	
	for(int i=1;i<=len;i++){
		if(expression[i-1]=='('){
			stack.Push(i);
		}
		
		else if(expression[i-1]==')'){
			if(stack.Pop(j)==true){
				
				cout<<"第"<<j<<"個 “(” 與第"<<i<<"個 “)” 匹配!"<<endl;
				
			}
			else{
				
				cout<<"沒有與第"<<i<<"個 “)” 匹配的 “(” !"<<endl;
				
			}
		}
	}
	
	while(stack.isEmpty()==false){
		stack.Pop(j);
		
		cout<<"沒有與第"<<j<<"個 “(” 匹配的 “)”!"<<endl;
		
	}

}

利用棧實現表達式的求值

(滿足小數,多位數,整數的計算)

其中最重要的算法實現,中綴表達式轉後綴表達式,利用容器保存各個操作數,以便實現多位數,小數的實現

//中綴表達式轉後綴表達式
vector<string> convert(string input){
	
		Stack<char> stk;//存儲操作符棧
		vector<string> temp;
		char s;
		string tmp = "";	
		int length = (int)input.length();//獲取表達式的長度
		for(int i = 0; i < length; i++){
			tmp = "";
			
			if((input[i]>='0' && input[i]<='9')){
				tmp += input[i];
				while((i+1<input.size() && input[i+1]>='0' && input[i+1]<='9')||input[i+1] == '.')
				{
						tmp += input[i+1];//若是連續數字
						++i;
				}
				temp.push_back(tmp);
			}
			else if(input[i] == '('){
				//遇到左括號直接入棧
				stk.Push(input[i]);
			}
			else if(input[i] == ')'){
				//如果遇到右括號的話,就把一直到最近的左括號之間的都彈出來加入temp中
				while(stk.getTopelements() != '('){
					tmp += stk.getTopelements();
					temp.push_back(tmp);
					stk.Pop(s);
					tmp="";
				}
				stk.Pop(s);//把左括號彈出棧
			}
			else if(isMark(input[i])){
				//如果是運算符的話,比較他們的優先級再決定是否入棧
				while( prior(input[i])<=prior(stk.getTopelements()) ){
					//如果當前的優先級小於等於棧頂操作符的話,棧頂操作符彈出,加入temp
					tmp += stk.getTopelements();
					temp.push_back(tmp);
					stk.Pop(s);
					tmp="";
				}
				//如果當前的優先級大於棧頂操作符的話,入棧
				stk.Push(input[i]);
			}
		}
		//如果已經掃描到中綴表達式的末尾,就把棧中的操作符都彈出來加入到temp中
		while(!stk.isEmpty()){
			tmp="";
			tmp += stk.getTopelements();
			temp.push_back(tmp);
			stk.Pop(s);
			tmp="";
		}
	return temp;
}

計算表達式的最終結果

//計算後綴表達式的最終數值
double calculate(vector<string> retu){
	
	int i = 0;
	Stack<double> optNum;//定義一個操作數棧
	double s;
	
	double x1,x2 = 0;
	double num;
	
	for(int i = 0;i < retu.size(); i++){//沒有遇到結束標誌#,即進行表達式的計算
	
	    string tmp = retu[i];
		if(tmp[0] >= '0'&&tmp[0] <= '9'){
			num = atof(tmp.c_str());
			optNum.Push(num);
		}
			else if(retu[i] == "+"){
			x1 = optNum.getTopelements();
			optNum.Pop(s);
			x2 = optNum.getTopelements();
			optNum.Pop(s);
			optNum.Push(x1+x2);
		}
		
		else if(retu[i] == "-"){
			x1 = optNum.getTopelements();
			optNum.Pop(s);
			x2 = optNum.getTopelements();
			optNum.Pop(s);
			optNum.Push(x2-x1);
		}
		
		else if(retu[i] == "*"){
			x1 = optNum.getTopelements();
			optNum.Pop(s);
			x2 = optNum.getTopelements();
			optNum.Pop(s);
			optNum.Push(x1*x2);
		}
		
		else if(retu[i] == "/"){
			x1 = optNum.getTopelements();
			optNum.Pop(s);
			x2 = optNum.getTopelements();
			optNum.Pop(s);
			optNum.Push(x2/x1);
		}
		else if(retu[i] == "%"){
			x1 = optNum.getTopelements();
			optNum.Pop(s);
			x2 = optNum.getTopelements();
			optNum.Pop(s);
			optNum.Push((int)x2%(int)x1);
		}
		else if(retu[i] == "^"){
			x1 = optNum.getTopelements();
			optNum.Pop(s);
			x2 = optNum.getTopelements();
			optNum.Pop(s);
			optNum.Push(pow(x2, x1));
		}
	}
	
	return optNum.getTopelements();//返回最終的計算結果
}
double result(string str){
	str = format(str);
	vector<string> bh = convert(str);
	double k = calculate(bh);
	return k;	
}

對“-”號的特殊化處理

string format(string str){
	for(int i = 0;i < str.length(); i++){
		if(str[i] == '-')
		{
			if(i == 0){
				str.insert(0,1,'0');
			}
			else if(str[i-1] == '('){
				str.insert(i,1,'0');
			}
		}
		
	}
	return str;
}

操作符的優先級

int prior(char op){//求運算符優先級
	switch (op) {
		case '#':
			return -1;
			break;
		case '(':
			return 0;
			break;
		case '+':
			return 1;
			break;
		case '-':
			return 1;
			break;
		case '*':
			return 2;
			break;
		case '/':
			return 2;
			break;
		case '%':
			return 2;
			break;
		case '^':
			return 3;
			break;
		default:
			return -1;
	}
}

完整的代碼我已經上傳到github,有需要的自行clone,有什麼錯誤的地方歡迎大家指出來,共同學習進步。希望得到大家的支持和鼓勵,加油!!!(下一篇更新利用qt,棧的表達式求值,寫一個簡易的計算器)

Stack棧實現的相關代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章