基础入门之堆栈

学习材料:《2013年王道论坛计算机考研机试指南》

文中涉及对学习材料的摘录,以及自己的理解


使用stack标准模板:
#include <stack>
定义堆栈:
stack <堆栈元素类型> S;  eg: stack <int> S;
将元素压栈:
S.push();
读取栈顶元素:
int x = S.top();
弹出栈顶元素:
S.pop();
判断堆栈是否为空:
if(S.empty==true)
   {...}

问题1: 括号匹配问题
/*
* 程序名称:括号匹配
* 输入:输入一串字符串(长度不超过100),英文字母;
* 输出:原来的字符串 + 等长标注行    无法匹配的左括号:$  无法匹配的右括号:?   其他字符:空格
* 测试输出:
  )(rttyy())sss)(
  ?            ?$
* 知识点:堆栈. 每个右括号都与它前面的,未匹配的,最靠近它的左括号匹配
* 程序思路:
  每个右括号都与
  1)输入字符串
  2)遍历字符串. 
    遇到左括号,将其字符下标号压入堆栈S;
	遇到右括号,与S栈顶元素(离它最近的,未被匹配的左括号下标)相匹配,弹出该栈顶元素; 如果堆栈S为空,说明没有左括号可以与该右括号匹配
  3)遍历完成后,如果堆栈S不为空,这些就是未被匹配的左括号下标
*/
#include 
    
    
     
     
#include 
     
     
      
      
using namespace std;

stack 
      
      
       
        S;          //定义一个堆栈,存放左括号
char instr[110];        //输入字符串
char outstr[110];       //输出字符串

int main()
{
	while(scanf("%s",instr) != EOF)
	{
		int i;
		for(i=0;instr[i]!=0;i++)
		{
			if(instr[i]=='(')          //处理左括号
			{
				S.push(i);
				outstr[i] = ' ';
			}
			else if(instr[i]==')')     //处理右括号
			{
				if(S.empty()==false)   //左括号堆栈非空,则该右括号与栈顶左括号匹配
				{
					S.pop();
					outstr[i] = ' ';
				}
				else                   //左括号堆栈空,说明该右括号找不到与之匹配的左括号
				{
					outstr[i] ='?';
				}
			}
			else                       //处理除括号之外的其他字符
				outstr[i] = ' ';
		}
		while(S.empty()==false)        //遍历完成后,如果堆栈S非空,说明有未匹配的左括号
		{
			outstr[S.top()] = '$';
			S.pop();
		}
		
		outstr[i] = '\0';              //遍历完成后i已经是字符串最后一个下标号,添加字符串结束标志
		puts(instr);                   //puts等效于printf("%s\n",s),不用再换行
		puts(outstr);
	}
	return 0;
}
      
      
     
     
    
    


问题2: +-*/ 表达式求值
/*
* 知识点:堆栈. 字符串处理
* 问题:表达式求值
* 输入:含非负数, +-x/的计算式,不超过200字符,数字和运算符之间用一个分号隔开, 没有非法表达式(不要考虑错误输入); 如果只输入1个0,结果不输出
* 输出:表达式的值, 精确到小数点后2位
* 测试用例:
  gets: 4 + 2 * 5 -7 / 11
  puts: 13.36
* 程序思路:
  1)乘除,加减2种运算优先级, 当一个表达式1+2*3先算后面两个数的乘法; 表达式1*2+3先算前面两个数的乘法; 1+2+3依次计算; 
    从前往后遍历,后面的运算优先级是未知的,所以不能依次从前往后计算.必须先把前面的表达式存下来. 
  2)遍历解析输入字符串中每个字符的含义,将数字和运算符用2个堆栈分别存储,注意空格的处理
  3)堆栈:先算栈顶两个数的运算.在遍历过程中:
    若此时解析的运算符优先级比前一个运算符(栈顶运算符)高,压栈,继续遍历后面的,                       1+2*3 最终是先算2*3 再算1+6
	若此时解析的运算符优先级与前一个运算符(栈顶运算符)一样,压栈,继续遍历后面的,                      1+2+3 最终是先算2+3 再算1+5
	若此时解析的运算符优先级比前一个运算符(栈顶运算符)低,先算该运算符前面两个数的运算, 再将此运算符压栈, 1*2+3 遍历过程中先算1*2 最终算2+3
  4)遍历完成后,循环计算; 
    结束计算条件:数字堆栈中只有1个值,就是要输出的表达式的值; 运算符堆栈中没有+-x/运算符
*/

#include 
    
    
     
     
#include 
     
     
      
      
using namespace std;


char instr[220];
int op_pre[4][4] = {//运算符优先级矩阵  可借鉴,利用二维数组,0\1矩阵来两两比较元素大小
	//若op_pre[i][j]==1, 表示运算符i的优先级 > 运算符j的优先级; 给运算符编号, +:0号  -:1号  *:2号  /:3号  则op_pre[2][1]=1,表示乘法比减法优先级高
	0,0,0,0,
	0,0,0,0,
	1,1,0,0,
	1,1,0,0,
};
stack 
      
      
       
        Op;     //运算符经编号后,就是int型,不再是char
stack 
       
       
        
        Num;  //计算过程中涉及浮点数

int main()
{
	while(gets(instr))
	{
		int i=0;                                  //输入字符串的字符下标
		int status=0;
		int temp = 0;                             //当前字符解析值

		if(instr[0]=='0' && instr[1]==0) break;   //处理输入只有1个0的情况  在这里处理会直接退出程序
	    while (Op.empty()==false) Op.pop();       //初始化清空运算符堆栈
		while (Num.empty()==false) Num.pop();     //初始化清空数字堆栈

		/* 1)遍历字符串,解析字符含义,并分别压栈 */
		for(;instr[i]!=0;i++)
		{
			switch(status)
			{
			case 0://初始化 或 上一个字符是空格, 当前字符只可能是数字或者运算符
               if(instr[i]>='0' && instr[i]<='9') //若当前字符为数字
			   {
					status = 1;
					temp = instr[i]-'0';
			   }
			   else                               //若当前字符为运算符
			   {
				   status = 2;
				   if(instr[i]=='+') 
					   temp = 0;
				   else if(instr[i]=='-')
					   temp = 1;
				   else if(instr[i]=='*')
					   temp = 2;
				   else if(instr[i]=='/')
					   temp = 3;
			   }
			break;

			case 1://上一个字符为数字, 当前字符只可能是数字或空格, 注意可能是字符串最后一个数字
               if(instr[i]>='0' && instr[i]<='9') //若当前字符为数字
			   {
					status = 1;
					temp *= 10;
					temp += instr[i]-'0';
					//if(instr[i+1]==0)             //若当前为字符串最后一个数字
					//	Num.push((double)temp);
			   }
			   else if(instr[i]==' ')             //若当前字符为空格 要把之前的数值压栈
			   {
				   status = 0;
				   Num.push((double)temp);
			   }
			break;

			case 2://上一个字符为运算符,当前字符只可能是空格
				status = 0;
				if(Op.empty()==true || op_pre[Op.top()][temp]==0)  //当前运算符>=栈顶运算符时,压栈
				{
					Op.push(temp);
				}
				else                                               //当前运算符
        
        <栈顶运算符时,先弹出栈顶运算符和之前的两个数值进行计算 { while(op.empty()="=false)" && op_pre[op.top()][temp]="=1)" 只要当前运算符优先级<栈顶运算符优先级 这里注意一定要判断堆栈是否为空条件 int toptemp="Op.top();" 保存栈顶运算符 op.pop(); 弹出栈顶运算符 double b="Num.top();" 取出当前运算符之前的倒数第一个数字 num.pop(); a="Num.top();" 取出当前运算符之前的倒数第二个数字 if(toptemp="=2)" num.push(a+b); else num.push(a-b); num.push(a*b); num.push(a b); } op.push(temp); 当前运算符压栈 break; default: for循环遍历结束 * 计算表达式 if(status="=" 1) 遍历到最后 应该是 1个数字 num.push((double)temp); printf("%.2f\n",num.top()); 表达式以数字结尾 才会有输出 return 0; }< code>
       
       
      
      
     
     
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值