括号匹配,实现简单计算器(加减乘除,小括号)

本文介绍了如何利用栈的数据结构实现括号匹配算法,以及设计一个能处理加减乘除和小括号的简单计算器。通过构建两个栈分别处理数字和运算符,考虑运算符的优先级,确保正确计算表达式。文章提供了详细的操作步骤和程序实现,并提出对输入字符串进行合法性判断的思考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

括号匹配算法

利用栈先进后出的特性,思路分三步:
1.遇到左括号,直接入栈,继续向后遍历;
2.遇到右括号,
(1).如果栈为空,说明无对应左括号,则返回表达式不匹配;
(2).如果栈不为为空,将栈顶元素弹出判断是否是相匹配的括号;
如果匹配,将栈顶元素弹出,继续遍历;如果不匹配,说明不是同类括号,直接返回表达式不匹配。
3.遍历到表达式末尾,如果栈中有剩余元素,说明存在多余左括号,返回表达式不匹配;如果栈为空,返回表达式匹配。
测试样例:

	//(56-20)/(4+2)
	//9 * (10 + 11 * (12 + 13)) + 14
	//(15 + 16) * (17 + 18 * (19 + 20)
	//((21 + 22) * 23 + (24 * 25)) + 26 * 27)) + 28	
	//{asdsd{ddads}sa}[]sassada[]sda{{aassaddsd[]}dsad}

完整程序实现如下:

#include<bits/stdc++.h>
using namespace std;


bool judge(char str[]){
	
	stack<char> s;
	int n = strlen(str);
	for(int i = 0; i < n; i++){
		if(str[i]=='(') s.push(str[i]);//左括号入栈 
		if(str[i]=='[') s.push(str[i]);
		if(str[i]=='{') s.push(str[i]);
		if(str[i]==')'){
			if(s.empty()) return false;//无左括号不匹配 
			else if(s.top()=='(') s.pop();//匹配 
			else return false;//不是同类括号 
		}
		if(str[i]==']'){
			if(s.empty()) return false;
			else if(s.top()=='[') s.pop();
			else return false;
		}
		if(str[i]=='}'){
			if(s.empty()) return false;
			else if(s.top()=='{') s.pop();
			else return false;
		}
	}
	return s.empty();//空匹配 非空说明存在多余左括号 
}
int main(){
	
	char str[10000];
	cin>>str; 
	//(56-20)/(4+2)
	//9 * (10 + 11 * (12 + 13)) + 14
	//(15 + 16) * (17 + 18 * (19 + 20)
	//((21 + 22) * 23 + (24 * 25)) + 26 * 27)) + 28	
	//{asdsd{ddads}sa}[]sassada[]sda{{aassaddsd[]}dsad}
	bool v = judge(str);
	if(v) cout<<"匹配"<<endl;
	else cout<<"不匹配"<<endl;
	return 0;
}
简单计算器实现:设计一个计算器,实现加减乘除和小括号的计算。

设计思路:构建两个栈,一个压入要进行计算的数字,一个压入运算符,运算符涉及到优先级问题,括号>乘除>加减。遍历要计算的字符串,数字压入栈num,运算符压入栈s:
1.如果栈s为空,直接将运算符压入栈s;
2.如果栈s不为空,且栈顶运算符优先级大于等于待入栈运算符,将栈顶运算符弹出,从栈num弹出两个数字,进行运算,将计算结果压入栈num,直至栈空或栈顶运算符优先级小于待入栈运算符,将待入栈元素入栈;
3.如果栈s不为空,且栈顶运算符优先级小于待入栈运算符,直接将待入栈运算符入栈;
4.遇到左括号直接入栈,重复2,3步骤,遇到右括号时,若栈s栈顶运算符为左括号,直接将左括号弹出;若不为左括号,将运算符依次弹出进行运算,直至栈顶运算符为左括号,将其弹出。
5.字符串遍历完成后,若栈s为空,栈num栈顶元素即运算结果;栈s不为空,将运算符依次弹出进行计算。

涉及程序时,我们先写一个函数prio来返回运算符的优先级,加减返回1,乘除返回2,小括号返回3和4。

int prio(char ch){
	
	switch(ch){
	    case '+':
	    case '-':
	        return 1;
	    case '*':
	    case '/':
	        return 2;
	    case'(':
	        return 3;
	    case ')':
	        return 4;
    }
}

再写一个运算函数:

int cal(int a,int b,char ch){
	
	switch(ch){
	    case '+':
	    	return a+b;
	    case '-':
	        return a-b;
	    case '*':
	    	return a*b;
	    case '/':
	        return a/b;
    }
}

上述5步我们慢慢拆分:
首先是遍历字符串:

for(int i=0;i<n;i++)

数字入栈:

if('0'<=str[i]&&str[i]<='9'){
	x = x*10+(str[i]-'0'); 
	v=1;
}
if(str[i]>'9'||str[i]<'0'||i==n-1){
	if(v==1){
		num.push(x);				
		//cout<<"push:"<<x<<endl;
		x=0;
	}
	v=0;
}

加v标记的原因是如果多个运算符相连,会导致压入不必要的数字0。
运算符入栈:

if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='('||str[i]==')'){

1.如果栈s为空,直接将运算符压入栈s;

if(s.empty()) s.push(str[i]);

2.如果栈s不为空,且栈顶运算符优先级大于等于待入栈运算符,将栈顶运算符弹出,从栈num弹出两个数字,进行运算,将计算结果压入栈num,直至栈空或栈顶运算符优先级小于待入栈运算符,将待入栈元素入栈;

while(!s.empty()&&prio(s.top())>=prio(str[i])&&s.top()!='('){
	int x2 = num.top();
	num.pop();
	int x1 = num.top();
	num.pop();
	char ch = s.top();
	s.pop();
	//cout<<x1<<ch<<x2<<" "<<cal(x1,x2,ch)<<endl;
	num.push(cal(x1,x2,ch));
}

3.如果栈s不为空,且栈顶运算符优先级小于待入栈运算符,直接将待入栈运算符入栈;

s.push(str[i]);

4.遇到左括号直接入栈,重复2,3步骤,遇到右括号时,若栈s栈顶运算符为左括号,直接将左括号弹出;若不为左括号,将运算符依次弹出进行运算,直至栈顶运算符为左括号,将其弹出。

if(str[i]=='('){
	s.push(str[i]);
	continue;
}
if(str[i]==')'){
	while(!s.empty()&&s.top()!='('){
		int x2 = num.top();
		num.pop();
		int x1 = num.top();
		num.pop();
		char ch = s.top();
		s.pop();
		//cout<<x1<<ch<<x2<<" "<<cal(x1,x2,ch)<<endl;
		num.push(cal(x1,x2,ch));
	}
	s.pop();
	continue;
}

5.字符串遍历完成后,若栈s为空,栈num栈顶元素即运算结果;栈s不为空,将运算符依次弹出进行计算。

while(!s.empty()){
	int x2 = num.top();
	num.pop();
	int x1 = num.top();
	num.pop();
	char ch = s.top();
	s.pop();
	//cout<<x1<<ch<<x2<<" "<<cal(x1,x2,ch)<<endl;
	num.push(cal(x1,x2,ch));
}
return num.top();

完整程序实现如下:

#include<bits/stdc++.h>
using namespace std;

int prio(char ch){
	
	switch(ch){
	    case '+':
	    case '-':
	        return 1;
	    case '*':
	    case '/':
	        return 2;
	    case'(':
	        return 3;
	    case ')':
	        return 4;
    }
}

int cal(int a,int b,char ch){
	
	switch(ch){
	    case '+':
	    	return a+b;
	    case '-':
	        return a-b;
	    case '*':
	    	return a*b;
	    case '/':
	        return a/b;
    }
}

int calculation(char str[]){
	stack<char> s;
	stack<int> num;
	int n = strlen(str);
	int x = 0;//用于提出字符串数字 
	int v = 0;//用于判断何时将数字压入栈 
	for(int i=0;i<n;i++){
		
		//cout<<str[i]<<endl;
		if('0'<=str[i]&&str[i]<='9'){
			x = x*10+(str[i]-'0'); 
			v=1;
		}
		if(str[i]>'9'||str[i]<'0'||i==n-1){
			if(v==1){
				num.push(x);				
				//cout<<"push:"<<x<<endl;
				x=0;
			}
			v=0;
		}
		if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='('||str[i]==')'){
			if(str[i]=='('){
				s.push(str[i]);
				continue;
			}
			if(str[i]==')'){
				while(!s.empty()&&s.top()!='('){
					int x2 = num.top();
					num.pop();
					int x1 = num.top();
					num.pop();
					char ch = s.top();
					s.pop();
					//cout<<x1<<ch<<x2<<" "<<cal(x1,x2,ch)<<endl;
					num.push(cal(x1,x2,ch));
				}
				s.pop();
				continue;
			}
			if(s.empty()) s.push(str[i]);
			else {
				//cout<<s.top()<<" "<<str[i]<<endl;
				while(!s.empty()&&prio(s.top())>=prio(str[i])&&s.top()!='('){
					int x2 = num.top();
					num.pop();
					int x1 = num.top();
					num.pop();
					char ch = s.top();
					s.pop();
					//cout<<x1<<ch<<x2<<" "<<cal(x1,x2,ch)<<endl;
					num.push(cal(x1,x2,ch));
				}
				s.push(str[i]);
			}
		}
	}
	while(!s.empty()){
		int x2 = num.top();
		num.pop();
		int x1 = num.top();
		num.pop();
		char ch = s.top();
		s.pop();
		//cout<<x1<<ch<<x2<<" "<<cal(x1,x2,ch)<<endl;
		num.push(cal(x1,x2,ch));
	}
	return num.top();
}

int main(){
	
	char str[10000];
	cin>>str; 
	//(56-20)/(4+2)
	//9*(10+11*(12+13))+14
	//(15+16)*(17+18*(19+20))
	//(((21+22)*23+(24*25))+26*27)+28	
	//10+11*12/12+14-1+2*3*1-5/5*5-5-5-5*5/5*5/5
	//10+11-12/12+14-1+22/2*5
	int cnt = calculation(str);
	cout<<cnt;
	return 0;
}

也有想过对输入的字符串进行一个合法性的判断,括号匹配,正确的运算符,这两个判断可以简单实现,但下面这两种

1234-1234+-34
12+231*41-

感觉判断起来有些许繁琐,但不判断程序又显得不完美,小记录一下。多给给几组测试样例,因为是整数相除,所以尽量选择整除的数:

	//(56-20)/(4+2)
	//9*(10+11*(12+13))+14
	//(15+16)*(17+18*(19+20))
	//(((21+22)*23+(24*25))+26*27)+28	
	//10+11*12/12+14-1+2*3*1-5/5*5-5-5-5*5/5*5/5
	//10+133+(4+22)/2*5
	//10+11-12/12+14-1+22/2*5

有问题敬请大家指正。

为了应付作业而编的,一个新手,请大家多多指教。/** * Title: Calculator * Description: * Copyright: Copyright (c) 2004 * Company: CUIT * Calculator.java * Created on 2004年10月13日, 下午2:35 * @author jacktom * @version 1.0*/import java.awt.*;import java.awt.event.*;import javax.swing.*;public class Calculator extends JFrame implements ActionListener{ Operator oper; String a,result; int type; boolean flag1=false; boolean flag2=false; boolean judge=true; int count=0; JTextField text; JPanel jpanel[]; JPanel jpanel1; JButton jbutton[]; String name[]={"0",".","-/+","+","=","1","2","3","-",")","4","5","6","*","(","7","8","9","/","CE"}; //Construct the JFrame public Calculator() { oper=new Operator(); setSize(250,300); setVisible(true); //Overridden so we can exit when window is closed this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { dispose(); System.exit(0); } }); Container con=getContentPane(); con.setLayout(new GridLayout(5,5)); text=new JTextField(12); text.setHorizontalAlignment(JTextField.RIGHT); jpanel1=new JPanel(); jpanel1.setLayout(new GridLayout(1,1)); jpanel1.add(text); jpanel=new JPanel[4]; for(int i=0;i<4;i++) { jpanel[i]=new JPanel(); jpanel[i].setLayout(new GridLayout(1,5)); } jbutton=new JButton[name.length]; //add button to panel for(int j=0;j=0;i--) { con.add(jpanel[i]); } } public void actionPerformed(ActionEvent e) { for(int i=0;i<10;i++) { if(e.getActionCommand().equals(String.valueOf(i))) if(flag1==false) { text.setText(String.valueOf(i)); flag1=true; } else { text.setText(text.getText()+i); } } if(e.getActionCommand().equals(".")) if(flag2==false&&count==0) { text.setText(text.getText()+"."); count++; flag1=true; } if(e.getActionCommand().equals("+")||e.getActionCommand().equals("-")||e.getActionCommand().equals("*")||e.getActionCommand().equals("/")) { if(judge) { a=text.getText(); oper.EvaluateExpression(a); } else judge=true; flag1=false; flag2=false; count=0; if(e.getActionCommand().equals("+")) { a="+"; oper.EvaluateExpression(a); } if(e.getActionCommand().equals("-")) { a="-"; oper.EvaluateExpression(a); } if(e.getActionCommand().equals("*")) { a="*"; oper.EvaluateExpression(a); } if(e.getActionCommand().equals("/")) { a="/"; oper.EvaluateExpression(a); } } if(e.getActionCommand().equals("=")) { if(judge) { a=text.getText(); oper.EvaluateExpression(a); } else judge=true; oper.EvaluateExpression("#"); text.setText(""); text.setText(String.valueOf(oper.CalculateResult())); flag1=false; flag2=false; count=0; } if(e.getSource()==jbutton[2]) { text.setText("-"+text.getText()); } if(e.getActionCommand().equals(")")) { a=text.getText(); oper.EvaluateExpression(a); oper.EvaluateExpression(")"); judge=false; } if(e.getActionCommand().equals("CE")) { text.setText(""); judge=true; count=0; flag1=false; flag2=false; oper=new Operator(); } if(e.getActionCommand().equals("(")) { oper.EvaluateExpression("("); } } /** * Main method * * @param args String[] */ public static void main(String args[]) { Calculator Cmain=new Calculator(); Cmain.pack(); }}/** * Operator.java * Description:用栈实现计算 * Created on 2004年10月13日, 下午3:35 * @author jacktom*/public class Operator{ StackY optr; //存放操作符 StackY opnd;//存放操作数 Puzhu p; boolean Mark; Operator() { p=new Puzhu(); optr=new StackY(); opnd=new StackY(); optr.push("#"); } public void EvaluateExpression(String s) { boolean mark=true; if(s=="+"||s=="-"||s=="*"||s=="/"||s=="("||s==")"||s=="#") { while(mark) { switch(p.Precede(optr.peek(),s)) { case -1: optr.push(s); mark=false; break; case 0: optr.pop(); mark=false; break; case 1: String theta=optr.pop(); String a =opnd.pop(); String b =opnd.pop(); if(a.indexOf(".",0)==-1&&b.indexOf(".",0)==-1) Mark=true; else Mark=false; double c=Double.valueOf(a).doubleValue(); double d=Double.valueOf(b).doubleValue(); double e=p.Operate(c,theta,d); String f=String.valueOf(e); if(theta=="/") Mark=false; if(Mark) opnd.push(f.substring(0,f.indexOf(".",0))); else opnd.push(f); break; } } } else opnd.push(s); } public String CalculateResult() { //double result=Double.valueOf(opnd.peek()).doubleValue(); return opnd.peek(); }}/** * Description:判断操作符的优先级并计算结果 * Created on 2004年10月13日, 下午4:00 * @author jacktom*/class Puzhu{ public Puzhu() {} public int Precede(String optr1,String optr2) { String[] A={"+","-","*","/","(",")","#"}; int[][] B={ {1,1,-1,-1,-1,1,1}, {1,1,-1,-1,-1,1,1}, {1,1,1,1,-1,1,1}, {1,1,1,1,-1,1,1}, {-1,-1,-1,-1,-1,0,2}, {1,1,1,1,2,1,1}, {-1,-1,-1,-1,-1,2,0}, }; int i=0,j=0,k; while(i<7) { if(A[i]==optr1) { break; } i++; } while(j<7) { if(A[j]==optr2) { break; } j++; } k=B[i][j]; return k; } public double Operate(double a,String oper,double b) { double c=0; if(oper=="+") c=a+b; if(oper=="-") c=b-a; if(oper=="*") c=a*b; if(oper=="/") c=b/a; return c; }}/** * StackY.java * Description:堆栈的基本操作实现 * Created on 2004年10月13日, 下午3:05 * @author jacktom*/public class StackY { private int maxSize; // size of stack array private String[] stackArray; private int top; // top of stack public StackY(int s) // constructor { maxSize = s; // set array size stackArray = new String[maxSize]; // create array top = -1; // no items yet }public StackY() // constructor { maxSize = 20; // set array size stackArray = new String[maxSize]; // create array top = -1; // no items yet } public void push(String j) // put item on top of stack { top++; stackArray[top] = j; // increment top, insert item } public String pop() // take item from top of stack { return stackArray[top--]; // access item, decrement top } public String peek() // peek at top of stack { return stackArray[top]; } public boolean isEmpty() // true if stack is empty { return (top == 0); } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fakerth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值