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;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值