go 栈数据结构实践

本文介绍了一种利用栈数据结构来解析和计算包含加、减、乘、除运算的数学表达式的方法。通过两个栈分别存储数字和运算符,文章详细展示了如何处理多位数和不同运算符的优先级。

通过栈实现对包含加减乘除的表达式的计算

stack

type Stack struct {
	Cap int     // 栈容量
	Top int     // 栈顶,默认为-1
	Arr [20]int // 数组模拟栈
}

// 入栈
func (s *Stack) Push(value int) {
	// 入栈判栈满
	if s.Top == s.Cap-1 { // 因为top默认为-1,所以cap=5的栈top最高为4
		fmt.Println("stack full!")
		return
	}
	// 移动top
	s.Top++
	// 放入数据
	s.Arr[s.Top] = value
}

// 出栈
func (s *Stack) Pop() (value int) {
	// 判栈空
	if s.Top == -1 {
		fmt.Println("stack empty!")
		return
	}
	// 取值,再移动Top
	value = s.Arr[s.Top]
	s.Top--
	return value
}

func (s *Stack) Show() {
	// 判栈空
	if s.Top == -1 {
		fmt.Println("stack empty!")
		return
	}
	fmt.Println("栈的情况如下:")
	for i := s.Top; i >= 0; i-- {
		fmt.Printf("array[%d] = %v\n", i, s.Arr[i])
	}
}

// 判断一个字符是否为一个计算符
// ascll +:43 -:45 *:42 /:47
func (s *Stack) IsOper(value int) bool {
	if value == 42 || value == 43 || value == 45 || value == 47 {
		return true
	} else {
		return false
	}
}

// 计算
func (s *Stack) Calc(num1, num2 int, oper int) (ret int) {
	switch oper {
	case 42:
		ret = num2 * num1
	case 43:
		ret = num2 + num1
	case 45:
		ret = num2 - num1
	case 47:
		ret = num2 / num1
	default:
		fmt.Println("error oper!")
	}
	return ret
}

// 优先级
func (s *Stack) Prio(oper int) (prio int) {
	if oper == 42 || oper == 47 { // 乘除优先级为1
		prio = 1
	} else if oper == 43 || oper == 4 { // 加减优先级为0
		prio = 0
	}
	return prio
}

// 处理表达式
func Express(expression string) (calcRet int) {
	// 1. 创建两个栈,一个装数字,一个装符号
	numStack := &Stack{
		Cap: 20,
		Top: -1,
	}
	operStack := &Stack{
		Cap: 20,
		Top: -1,
	}

	// 2. 常量定义
	index := 0 // index,用于扫描表达式
	num1 := 0  // 用于计算
	num2 := 0
	oper := 0
	ret := 0
	keepNum := "" // 用于实现拼接多位数

	// 3. 循环扫描表达式,并处理
	for {
		// 3.1 获取表达式单个字符信息
		expSingleString := expression[index : index+1]

		// 3.2 对表达式oper的处理逻辑
		tmp := int([]byte(expSingleString)[0]) // 获取字符对应的ascll码值,字符串 --> 字符(字节切片) --> ascll(int)
		if operStack.IsOper(tmp) {             // 是否为oper
			if operStack.Top == -1 { // 空栈直接将oper压入
				operStack.Push(tmp)
			} else { // 如果不是空栈,则需要判断当前扫描到的oepr和栈顶oepr的优先级
				// 加入栈顶oper的优先级比当前扫描到的oper高,则需要先取出来计算!!!!!
				if operStack.Prio(operStack.Arr[operStack.Top]) >= operStack.Prio(tmp) {
					num1 = numStack.Pop()
					num2 = numStack.Pop()
					oper = operStack.Pop()
					ret = operStack.Calc(num1, num2, oper)
					numStack.Push(ret)  // 计算结果入栈
					operStack.Push(tmp) // 当前未处理的符号入栈
				} else { // 栈顶oper优先级低于当前扫描到的oper的优先级就直接入栈
					operStack.Push(tmp)
				}
			}

			// 3.3 对表达式num的处理逻辑
		} else {
			// 对多位数的处理
			keepNum += expSingleString      // 将expSingleString追加到keepNum中
			if index == len(expression)-1 { // 如果是最后一个,直接压入数栈
				value, _ := strconv.Atoi(keepNum)
				numStack.Push(value)
			} else {
				if operStack.IsOper(int([]byte(expression[index+1 : index+2])[0])) {
					// 如果是运算符,那么直接将keppNum入数栈,并且清空keepNum留给下次用
					value, _ := strconv.Atoi(keepNum)
					numStack.Push(value)
					keepNum = ""
				}
			}
			// 如果本次扫描没发现运算符,那就继续追加,知道发现oper为止!
		}
		// 继续往后扫描
		if index+1 == len(expression) { // 扫描到尾
			break
		}
		index++
	}

	// 3.4 表达式处理完毕,数栈和oper栈中可能还会存留数据,需要对这部分数据进行处理!
	for {
		if operStack.Top == -1 { // 符号栈中数据处理完毕,则说明就只有一个ret存在数栈中了!则退出!
			break
		}
		num1 = numStack.Pop()
		num2 = numStack.Pop()
		oper = operStack.Pop()
		ret = operStack.Calc(num1, num2, oper)
		numStack.Push(ret)
	}

	// 如果计算没问题,numStack最后的一个数就是该表达式的计算结果!
	return numStack.Pop()
}

main

func main() {
	expression := "100+2+5*6+9/3"
	ret := stack.Express(expression)
	fmt.Printf("[%v] = %v\n", expression, ret)
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值