1. 程式人生 > >C資料結構之棧的應用:括號匹配和簡單計算器

C資料結構之棧的應用:括號匹配和簡單計算器

堆疊是一種資料項按序排列的資料結構,只能在其一端進行插入和刪除。括號匹配和表示式求值是堆疊的兩個典型應用。

1.找到無法匹配的左右括號,輸出原字串,失配的左括號下打&,右括號下打? 輸入包括多組資料,每組資料一行,包含一個字串,只包含左右括號和大小寫字母,字元長度不超過100.。

樣例輸入 )(rttyy())sss)(

樣例輸出 )(rttyy())sss)(

        ?            ? $

括號匹配:由於每一個右括號,必定與之前的所有未被匹配的左括號中最靠右的一個匹配。若我們從左到右遍歷字串,並將所有遇到的左括號放入堆疊等待匹配,若遍歷過程中遇到右括號,若此時堆疊為空,匹配失敗,否則棧頂左括號即為其匹配的左括號。

#include<stdio.h>
#include<stdlib.h>
#include<stack>
using namespace std;
stack<int> S;
char str[110];//儲存輸入字串
char ans[110];//儲存輸出字串
int main()
{
	while(scanf("%s",str)!=EOF)//輸入字串 
	{
		int i;
		for(i=0;str[i]!=0;i++)//從左到右遍歷字串 
		{
			if(str[i]=='(')//遇到左括號 
			{
				S.push(i);//將其陣列下標放入堆疊 
				ans[i]=' ';//對應輸出字元位置為空 
			}
			else if(str[i]==')')//若為右括號 
			{
				if(S.empty()==false)//若堆疊不為空 
				{
					S.pop();//彈出左括號,相應輸出位置為空 
					ans[i]=' ';
				}
				else
				    ans[i]='?';//堆疊為空,輸出? 
			}
			else 
			   ans[i]=' ';//若為字元,輸出為空 
		}
		while(!S.empty())//遍歷結束,堆疊不為空 
		{
			ans[S.top()]='$';//相應左括號輸出位置置為$ 
			S.pop();
		}
		ans[i]=0;//為了使輸出為字串,在最後加 0 
		puts(str);
		puts(ans);
	}
	return 0;
} 

括號匹配利用了從左往右遍歷字串時棧頂左括號離當前位置最近的特性完成工作。

2.簡單計算器:讀入一個只含+ - * /的非負整數計算表示式,計算該表示式的值
輸入:每個測試用例佔一行,每行不超過200個字元,整數和運算子之間用一個空格分隔。

當一行只有0 時,輸入結束 。1 + 2   4 + 2 * 5 - 7 / 11  0 輸出3.00 13.36

思路:

1.設立兩個堆疊,一個儲存運算子,一個儲存數字

2.在表示式首尾新增標記運算子,優先順序最低。

3.從左至右遍歷字串,若遍歷到運算子,與運算子棧頂元素比較,棧頂優先順序小於該運算子或此時運算子棧為         空,該運算子進棧。遍歷下一個元素。

4.若棧頂運算子大於該運算子,彈出棧頂元素,彈出兩個數字,進行計算,再將計算結果壓入堆疊。重複比較優          先級。

5.若遍歷到數字,直接壓入堆疊

6.若元素符棧只有兩個運算子,且棧頂元素為標記運算子,表示式求值結束。

#include <stack>
#include <stdio.h>
using namespace std;
char str[220];//儲存表示式字串 
int mat[][5]={//優先順序矩陣 ,若mat[i][j]==1,則表示i號運算子大於j號運算子的優先順序,
// + - * /分別為1 2 3 4 號運算子,人為新增在 表示式首尾的標記運算子為0號 
1,0,0,0,0,
1,0,0,0,0,
1,0,0,0,0,
1,1,1,0,0,
1,1,1,0,0,
};
stack<int> op;//運算子棧 
stack<double> shuzi;//數字棧 
void getop(bool &next,int &zhi,int &i)//獲得表示式下一個元素的函式,next為true表示是運算子,值為返回的優先順序編號 
{//若為false,則為數字,zhi為數字的大小,i表示遍歷到的字串的下標 
	if  (i==0&&op.empty()==true)
	{//若遍歷字串的第一個字元,並且運算棧為空,人為新增運算識別符號 
		next=true;
		zhi=0;
	//	printf("%d  %d\n",zhi,i);
		return;
	} 
	if (str[i]==0)
	{//若遍歷字元為空,表示字串已經遍歷結束,人為新增運算識別符號 
		next=true;
		zhi=0;
	//	printf("%d  %d\n",zhi,i);
		return;
	}
	if(str[i]>='0'&&str[i]<='9')
	{//若當前為數字,返回數字, 
		next=false;
	}
	else//否則返回相應的運算優先順序編號 
		{
			next=true;
			if (str[i]=='+')
			 {
			    zhi=1;
			 }
			else if(str[i]=='-')
			 {
			    zhi=2;
			 }
			 else if(str[i]=='*')
			{
			    zhi=3;
			}
			 else if(str[i]=='/')
			 {
			    zhi=4;
			 }
			 i+=2;//i遞增,跳過運算子和其後的空格 
		//	 printf("%d  %d\n",zhi,i);
			 return;
		}
		zhi=0;//返回結果為數字 
		for(;str[i]!=' '&&str[i]!=0;i++)
		{//若字串未被遍歷完,且下一個字元不為空,則依次遍歷其後數字,計算當前連續數字字元表示的數值 
			zhi*=10;
			zhi+=str[i]-'0';
		}
		if (str[i]==' ')
			i++;//遞增跳過該空格 
		//	printf("%d  %d\n",zhi,i);
			return;
}
int main()
{
	while(gets(str))//輸入字串 
	{
			if(str[0]=='0'&&str[1]==0) break;//若輸入只有一個0,則退出 
			bool next1;int num; int idx=0;
			while(!op.empty()) op.pop();
			while(!shuzi.empty()) shuzi.pop();//清空棧 
	   while(true)
		{//迴圈遍歷表達字串 
			
			getop(next1,num,idx);//獲取表示式中下一個元素 
			if(next1==false)
			{//若為數字,進棧 
				shuzi.push((double) num);
		//		printf("%d\n",num);
			}
			else
			{//否則 
				double temp;
				if (op.empty()==true||mat[num][op.top()]==1)
				{//如果運算棧為空 或者當前遍歷到的運算子優先順序大於棧頂運算子,壓入堆疊 
					op.push(num);
		//			printf("%d\n",num);
				}
				else//否則 
				{
					 while(mat[num][op.top()]==0)
					 {//只要當前運算子小於棧頂運算子,重複迴圈 
					 	int ret=op.top();
					 	op.pop();
					 	double b=shuzi.top();
					 	shuzi.pop();
					 	double a=shuzi.top();
					 	shuzi.pop();//從數字棧頂彈出兩個數字,依次儲存遍歷a b中 
					 	if(ret==1) temp=a+b;
					 	else if (ret==2) temp=a-b;
					 	else if (ret==3) temp=a*b;
					 	else if (ret==4) temp=a/b;
					 	shuzi.push(temp);//完成運算,壓入堆疊中 
		//			 	printf("%d\n",temp);
					 }
					op.push(num); 
		//			printf("%d\n",num);
				}
			}
		if(op.size()==2&&op.top()==0) break;//如果運算子堆疊只有兩個元素,且均為標記運算子,表示式求值結束 
		}
		printf("%.2f\n",shuzi.top());
	}
	return 0;
}