算法:表达式求值

问题:表达式求值

请写一个整数计算器,支持加减乘三种运算和括号。

暂时不考虑字符串存在负数。除法和乘法处理相似,排除小数,不考虑除法。

输入:"(2*(3-4))*5"
输出:-10

思路:

使用逆波兰式,后缀表达式。

使用递归,把表达式分成所有项的+、-运算,把项分成因子的*、/运算,因子可以是个数、是个(表达式)加括号的表达式。这样就把定义递归回去了。比较复杂。

使用双栈。下面是双栈思路。

思考方向:

  • 当前运算符是否计算,要看后一个操作符是什么。
  • 当前是加法计算,后一个运算符是乘法,这个加法就不能计算。
  • 当前是乘法,后一个是(,也不能计算。
  • 所以,使用栈的思路就是思考当前和后一个操作符分别是什么,什么情况下可以计算当前的运算。

实现方法:

  • 两个栈,符号栈和数字栈。符号栈的栈顶运算符优先级较高。
  • 遍历字符串,遇到数字就进栈。
  • 遇到走"(" 进栈。
  • 遇到运算符(+ - *),查看符号栈顶元素(上一个运算符),当前运算符的优先级是否比栈顶优先级低,如果低,就取出上一个高优先级的运算符,和数字栈的两个数,进行运算,循环判断到当前优先级较大为止。最后进栈。
  • 遇到")",直接出栈到"(",并计算。因为栈顶运算符优先级高,可以直接计算。
  • 遍历完成,在出栈计算栈内剩余的表达式。

go语言代码实现

package main

import "strconv"

func solve(s string) int {
	// write code here
	shu := make([]int, 0)
	fu := make([]byte, 0)
	for i := 0; i < len(s); i++ {
		switch {
		case s[i] >= '0' && s[i] <= '9':
			j := toInt(s, i)
			a, _ := strconv.Atoi(s[i:j])
			i = j - 1
			shu = append(shu, a)
		case s[i] == '(':
			fu = append(fu, s[i])
		case s[i] == ')':
			for len(fu) > 0 && fu[len(fu)-1] != '(' {
				pro := fu[len(fu)-1]
				fu = fu[ :len(fu)-1]
				cal(&shu, pro)
			}
			fu = fu[ :len(fu)-1]
		case s[i] == '+' || s[i] == '-':	//前一个不是(,就计算。
			for len(fu) > 0 && fu[len(fu)-1] != '('{
				pro := fu[len(fu)-1]
				fu = fu[ :len(fu)-1]
				cal(&shu, pro)
			}
			fu = append(fu, s[i])
		case s[i] == '*':	//前一个是*,就计算
			for len(fu) > 0 && fu[len(fu)-1] == '*'{
				pro := fu[len(fu)-1]
				fu = fu[ :len(fu)-1]
				cal(&shu, pro)
			}
			fu = append(fu, s[i])
		}
	}
	for len(fu) > 0 {	//最后出栈计算
		pro := fu[len(fu)-1]
		fu = fu[ :len(fu)-1]
		cal(&shu, pro)
	}
	return shu[0]
}
//计算运算符p,shu栈,
func cal(shu *[]int, p byte) ( r int) {
	a := (*shu)[len(*shu)-2]
	b := (*shu)[len(*shu)-1]
	st := (*shu)[ :len(*shu)-2]
	*shu = st
	switch p {
	case '*':
		r = a * b
	case '+':
		r = a + b
	case '-':
		r = a - b
	}
	*shu = append(*shu, r)
	return
}
//字符串转化成数字
func toInt(s string, i int) int {
	for i < len(s) && s[i] >= '0' && s[i] <= '9' {
		i++
	}
	return i
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值