java自定义栈以及利用自定义栈实现逆波兰表达式与运算

一、java自定义栈的实现

栈是限定仅在表位进行删除和插入操作的线性表。栈的运用能很好实现很多算法。java中也有自己实现栈的类:Stack类。
1、自定义栈的实现
这个自定义栈为了方便测试,写在的main方法中,作为内部类。所以用static修饰。
注:1、栈中存储数据类型通过泛型传入
2、栈初始存储大小为10个数据,如果超过会自动扩容,扩容大小为原来的1.5倍

   //自定义一个栈 因为是在main方法中写的内部类,所以用static
	static class Mystack<E>{
		int top ;  //栈顶位置
		int maxL ; 
		Object[] strArr ;
		
		//构造方法
		public Mystack(){
			//默认长度为10
			maxL = 10 ;
			top = -1;
			strArr = new Object[maxL];
		}
		
		//进栈操作
		public void push(E str){
			//自动扩容
			if(top + 1 >= maxL){
				//如果进栈数据数量超过数组长度,自动扩容 ,扩容1.5倍
				strArr = Arrays.copyOf(strArr, maxL + (maxL >> 1) ) ;
			}
			strArr[++top] = str ;
		}
		
		//出栈操作
	    @SuppressWarnings("unchecked")
		public E pop(){
			E spop = (E) strArr[top];
			strArr[top] = null ;
			top -- ;
			return spop ;
		}
		 
		//访问栈顶元素
	    @SuppressWarnings("unchecked")
		public E peek(){
			return (E) strArr[top]; 
		}
		//栈的大小
		public int stackSize(){
			return top +1 ;
		}
		//栈是否为空
		public boolean empty(){
			return top == -1 ;
		}	
		
	}

二、逆波兰表达式转换(中缀表达式转后缀表达式)

我们用的标准四则运算表达式又叫中缀表达式,所有的符号信息在数字中间。逆波兰表达式有叫后缀表达式,符号在数字后。
中缀表达式转后缀表达式转化规则:
从左到右遍历中缀表达式的每个数字和符号。若是数字就输出,成为后缀表达式的一部分。若是符号判断当前符号与栈顶的符号比较优先级,如果当前符号优先级小于栈顶符号的优先级,则把栈里面的符号都弹出来。括号的操作除外,括号是左括号优先级最高,不管跟啥比,都是入栈;右括号是优先级最低,跟啥比都是弹出栈内符号,但只弹到跟它匹配的最近的那个左括号。
例如:9+(3-1)3+10/2 转化为后缀表达式为:931-3+102/+ (具体思路不详述了)
下面上代码:
得到的数组转变为字符串就为转化好的后缀表达式(之所以用数组作为输出是为了后面后缀表达式计算的方便)

//main方法中,所以方法用static 参数为中缀表达式:9+(3-1)*3+10/2
public static String[] getHZExpression(String zz){
		List<String> list = new ArrayList<String>(); 
		//符号运算顺序
		Map<String,Integer> ExOrder = new HashMap<String,Integer>();
		ExOrder.put("+", 10);
		ExOrder.put("-", 10);
		ExOrder.put("*", 20);
		ExOrder.put("/", 20);
		//创建一个符号栈
		Mystack<String> stack_symbol = new Mystack<String>();
		
		StringBuffer sb = new StringBuffer();
		//循环得到的运算字符串
		for(int i = 0 ; i < zz.length() ; i++){
			
			//处理数字部分
			if(Character.isDigit(zz.charAt(i)) || zz.charAt(i)=='.' ){
				sb.append(String.valueOf(zz.charAt(i)));
				continue ;
			}
			//遇到符号将数字部分放入到表达式中
			if(sb != null && sb.length() != 0){
				list.add(sb.toString());
				sb.setLength(0);
			}			
			//符号信息处理
			String sy = String.valueOf(zz.charAt(i)) ;
			//如果符号栈为空,或者符号为“(”直接放入符号栈中
			if(stack_symbol.stackSize() == 0 || stack_symbol.peek().equals("(") || sy.equals("(")){
				stack_symbol.push(sy);
			}else if(sy.equals(")")){
				while(!stack_symbol.peek().equals("(")){
					list.add(stack_symbol.pop());
				}
				//遇到“(”后,将其出栈
				stack_symbol.pop();
			}else if(ExOrder.get(sy)==null){
				System.out.println("解析出现异常,四则运算格式异常,请重新核对!!~~~~");
			}else if(ExOrder.get(sy) >= ExOrder.get(stack_symbol.peek())){
				stack_symbol.push(sy);
			}else if(ExOrder.get(sy) < ExOrder.get(stack_symbol.peek())){
				while(stack_symbol.stackSize() != 0 && !stack_symbol.peek().equals("(") && ExOrder.get(sy) <= ExOrder.get(stack_symbol.peek())){
					list.add(stack_symbol.pop());
				}
				stack_symbol.push(sy);
			}else{
				System.out.println("出现其他情况信息,请处理");
			}	
						
		}
		//循环结束后,数字没有放入表达式的,放入后缀表达式中
		if(sb != null && sb.length() != 0){
			list.add(sb.toString());
			sb.setLength(0);
		}
		//循环结束后,将没有处理的元素依次出栈,放入后缀表达式中;
		while(stack_symbol.stackSize() != 0){
			list.add(stack_symbol.pop());
		}	
		//将输出的数组转化为字符串就是后缀表达式了	
		return list.toArray(new String[list.size()]);
	}

三、逆波兰表达式运算

那么我们将中缀表达式转化为逆波兰表达式了,那计算机要如何识别运算逆波兰表达式呢
逆波兰表达式运算规则:
从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算(栈顶最为减数或除数),运算结果进栈,一直到最终获得结果。
代码如下:

//后缀表达式运算
	public static Double HZOperation(String[] hzArr){
		//创建一个数字栈
		Mystack<Double> stack_number = new Mystack<Double>();
		String regex = "-[0-9]+(.[0-9]+)?|[0-9]+(.[0-9]+)?";
		for(String hz: hzArr){
			//判断,如果为数字,则入栈
			if(hz.matches(regex)){
				stack_number.push(Double.parseDouble(hz));
				continue ;
			}
			//如果为符号,从栈顶依次取两个元素进行运算。第一个取出的元素作为减数与除数,进行四则运算
			double dou = getArithmetic(stack_number.pop(),stack_number.pop(),hz);
			//将运算结果入栈
			stack_number.push(dou);			 
		}
		//将最终栈顶结果作为运算结果输出	
		return stack_number.pop();
	}
	
	//四则运算(目前只有 + - * / )
	public static double getArithmetic(double num1 , double num2 ,String fh){
		//在后缀表达式运算时,需要把栈顶的数字最为减数或除数,所有我们将参数1作为减数或除数
		//当然,你要不按照这个顺序也可以。
		//JDK版本不到1.7,没用 switch
		if("+".equals(fh)){
			return num2 + num1 ;
		}else if("-".equals(fh)){
			return num2 - num1 ;
		}else if("*".equals(fh)){
			return num2 * num1 ;
		}else if("/".equals(fh)){
			return num2 / num1 ;
		}else{
			System.out.println("运算出现异常,请检查核实!~~");
			return 0 ;
		}	
	}

四、总结与遇到的问题

总结:
1、栈的定义就是仅在结尾进行插入和删除操作的线性表。利用栈的特性可以实现很多的算法。
2、逆波兰表达式的转化和运算分别是将符号和数字入栈,进行运算。
问题:
1、在实现逆波兰算法运算中,发现了一个很大的问题,现在也没有解决。例如在运算:12/(3+3)*5的时候,得到的结果为:0.4。而我们实际正常运算的结果应该为:10(我的四则运算应该没有问题吧…),逆波兰运算在计算时将(3+3)*5先进行了计算…但如果我将乘号
的优先级调整高于除号的时候,运算结果正常…这个我也不知道咋回事,感觉我的规则理解没有问题了。如果以后发现原因,在更新吧。
如果大家有知道原因的,请给我留言,谢谢~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值