golang 使用栈模拟计算器

思路: 

 

// @Author sunwenbo
// 2024/4/12 16:51
package main

import (
	"errors"
	"fmt"
	"strconv"
)

// 使用数组来模拟一个栈的应用
type Stack struct {
	MaxTop int     //表示栈最大可以存放数的个数
	Top    int     //表示栈底,因为栈底是固定的,因此我们可以直接使用Top
	arr    [20]int //数组模拟栈
}

// 入栈
func (this *Stack) Push(val int) (err error) {

	// 先判断栈是否已经满了
	if this.Top == this.MaxTop-1 {
		fmt.Println("stack full")
		return errors.New("stack full")
	}
	this.Top++
	// 放入数据
	this.arr[this.Top] = val
	return
}

// 遍历栈,需要从栈顶开始遍历
func (this *Stack) List() {
	// 先判断栈是否为空
	if this.Top == -1 {
		fmt.Println("stack  empty")
		return
	}
	//curTop := this.Top
	fmt.Println("栈的情况如下:")
	for i := this.Top; i >= 0; i-- {
		fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
	}
}

// 出栈
func (this *Stack) Pop() (val int, err error) {
	// 判断栈是否为空
	if this.Top == -1 {
		fmt.Println("stack empty")
		return 0, errors.New("stack empty")
	}
	// 先取值,再this.Top--
	val = this.arr[this.Top]
	this.Top--
	return val, nil
}

// 判断一个字符是不是一个运算符 [+,-,*,/]
func (this *Stack) IsOper(val int) bool {
	if val == 42 || val == 43 || val == 45 || val == 47 {
		return true
	} else {
		return false
	}

}

// 运算的方法
func (this *Stack) Cal(num1 int, num2 int, oper int) int {
	res := 0
	switch oper {
	case 42:
		res = num2 * num1
	case 43:
		res = num2 + num1
	case 45:
		res = num2 - num1
	case 47:
		res = num2 / num1
	default:
		fmt.Println("运算符错误..")
	}
	return res
}

// 编写一个方法返回某个运算符的优先级[程序员定的]
// [* / => 1, +- = 0 ]
func (this *Stack) Priority(oper int) int {
	res := 0
	if oper == 42 || oper == 47 {
		return 1
	} else if oper == 44 || oper == 45 {
		fmt.Println("oper=", oper)
		return 0
	}
	return res
}

func main() {
	// 数栈
	numStack := &Stack{
		MaxTop: 20,
		Top:    -1}
	// 符号栈
	operStack := &Stack{
		MaxTop: 20,
		Top:    -1}

	exp := "30+3*6-4"

	// 定义一个index,帮助扫描 exp
	index := 0
	// 为了配合运算,我们定义需要的变量
	num1, num2, oper, result, keepNum := 0, 0, 0, 0, ""
	for {
		fmt.Println("numStack")
		numStack.List()
		fmt.Println("operStack")
		operStack.List()

		// 这里需要增加一个逻辑,处理多位数的问题
		ch := exp[index : index+1] // 字符串
		// ch ==> "+" ==> 43
		temp := int([]byte(ch)[0])  // 字符对应的ASCI码
		if operStack.IsOper(temp) { //说明是符号
			//如果operStack 是一个空栈,直接入栈
			if operStack.Top == -1 { // 空栈
				operStack.Push(temp)
			} else {
				// 两个逻辑
				// 1. 如果发现operStack 栈顶的运算符的优先级大于等于当前准备入栈的运算符的优先级,就从符号栈Pop出,
				//并从数栈也pop两个数,进行运算,运算后的结果再重新入栈到栈,符号再入符号栈
				if operStack.Priority(operStack.arr[operStack.Top]) >= operStack.Priority(temp) {
					num1, _ = numStack.Pop()
					num2, _ = numStack.Pop()
					oper, _ = operStack.Pop()
					result = operStack.Cal(num1, num2, oper)
					// 将计算结果重新入数栈
					numStack.Push(result)
					// 将当前的符号压入符号栈
					operStack.Push(temp)
				} else {
					operStack.Push(temp)
				}
			}
		} else { //说明是数字
			//处理多位数的思路
			// 1. 先定义一个变量keepNum string,做拼接工作
			keepNum += ch
			// 2. 每次要向index的后面字符测试一下,看看是不是运算符,然后再做处理
			// 如果到表达式的最后了,直接将keepNum 转换成整数
			if index == len(exp)-1 { // 已经到表达式最后了
				val, _ := strconv.ParseInt(keepNum, 10, 64)
				numStack.Push(int(val))
			} else {
				// index 的后一位测试一下,看看是不是运算符,如果不是运算符则继续上面的for循环,做字符串拼接
				if operStack.IsOper(int([]byte(exp[index+1 : index+2])[0])) {
					val, _ := strconv.ParseInt(keepNum, 10, 64)
					numStack.Push(int(val))
					keepNum = ""
				}
			}
			//val, _ := strconv.ParseInt(ch, 10, 64)
			//numStack.Push(int(val))
		}
		// 继续扫描,先判断index 是否已经扫描到计算表达式的最后
		if index+1 == len(exp) {
			break
		}
		index++
	}
	// 如果扫描表达式完毕,依次从符号栈取出符号,然后从数栈中取出两个数,
	// 运算后的结果,入数栈,直到符号栈为空
	for {
		if operStack.Top == -1 {
			break //退出条件
		}
		num1, _ = numStack.Pop()
		num2, _ = numStack.Pop()
		oper, _ = operStack.Pop()
		result = operStack.Cal(num1, num2, oper)
		// 将计算结果重新入数栈
		numStack.Push(result)
	}
	// 如果我们的算法没有问题,表达式也是正确的则结果就是numStack的最后一个数
	res, _ := numStack.Pop()

	fmt.Printf("表达式: %s=%v", exp, res)
}

相关推荐

  1. 使用 Lua 协程模拟 Golang 的 go defer 编程模式

    2024-04-15 08:28:03       34 阅读
  2. Golang实践录:gin框架使用自定义日志模块

    2024-04-15 08:28:03       35 阅读
  3. 使用golang发送邮件

    2024-04-15 08:28:03       71 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-15 08:28:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-15 08:28:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-15 08:28:03       87 阅读
  4. Python语言-面向对象

    2024-04-15 08:28:03       96 阅读

热门阅读

  1. 数据可视化开发教程和案例

    2024-04-15 08:28:03       40 阅读
  2. vue3+ts实现表格单元格编辑功能

    2024-04-15 08:28:03       28 阅读
  3. 关于分布式session的问题

    2024-04-15 08:28:03       23 阅读
  4. TLC3702双微功耗电压比较器

    2024-04-15 08:28:03       39 阅读
  5. HTTP 响应码

    2024-04-15 08:28:03       29 阅读
  6. Vue中key的作用和原理

    2024-04-15 08:28:03       97 阅读
  7. Node.js环境WebSocket示例

    2024-04-15 08:28:03       38 阅读