【GoLang】命令行计算器(栈,逆波兰表达式)

先看效果

整体思路

输入一个式子(中缀表达式),将其传入并转换为后缀表达式,接着通过计算后缀表达式来获得结果。

知识点补充

  • 逆波兰表达式:也叫后缀表达式,所谓后缀就是指运算符写在后面。如 ( ( 1 2 + ) ( 3 4 + ) * ) 
  • 中缀表达式:就是平常使用的算式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 后缀表达式对于计算机会更加友好,所以我们要将中缀表达式转换为后缀表达式进行计算。
  • 逆波兰表达式运算法则:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。

代码实现

package main

import (
	"fmt"
	"strconv"
)

const Max_Size = 100

// Stack结构体表示栈,栈中的元素存储在data数组中
type Stack struct {
	data [Max_Size]string //一个长度最大值为Max_Size的字符串数组
	top  int              //top表示Stack栈的栈顶元素位置
}

// init方法初始化了栈的状态
func (s *Stack) init() {
	s.top = -1 //一种约定,表示栈的空状态
}

// push方式用于先将top++后,再把传参elem添加进Stack栈顶中
func (s *Stack) push(elem string) {
	if s.top == Max_Size-1 { //判断栈是否已满
		fmt.Println("Error: the stack is full")
	} else { //向栈中添加元素
		s.top++
		s.data[s.top] = elem
	}
}

// pop方法先返回栈顶元素的的值,再top--。并不会弹出栈顶元素
func (s *Stack) pop() string {
	var elem string
	if s.top < 0 {
		fmt.Println("Error:the stack is empty")
	} else {
		elem = s.data[s.top]
		s.top--
	}
	return elem
}


// Get_RPN 用于将传参src中的中缀表达式转换为后缀表达式,并将后缀表达式输出
func Get_RPN(src string) [Max_Size]string {
	var dst [Max_Size]string //创建了一个最大值为Max_Size的det数组,用于存放数字和操作符(即后缀表达式)
	var op Stack             //op是Stack结构体的实例,用于存储操作符
	op.init()
	var j int
	var t string
	//此for循环用于遍历src中的每一个字符
	for i := 0; i < len(src); { //循环体中没有迭代语句i++,但循环可照常进行
		//此if语句用于将src中的数字传入到dst
		if i < len(src) && (string(src[i]) >= "0" && string(src[i]) <= "9") { //3,5,8,12,14,17    //用于判断该字符是否为数字 //字符的比较是通过把这个字符经ASCII转换成数字之后,对这个数字进行比较
			//把前i个连续数字拼接之后放入dst数组中
			for t = ""; i < len(src) && (string(src[i]) >= "0" && string(src[i]) <= "9"); i++ {
				t = t + string(src[i])
			}
			dst[j] = t
			j++
		}

		//此if语句用于将
		if i < len(src) && string(src[i]) == "(" { //1,2,11
			op.push(string(src[i]))
			i++
		} else if i < len(src) && string(src[i]) == ")" { //6,9,15
			for op.top != -1 && op.data[op.top] != "(" {
				dst[j] = op.pop()
				j++
			}
			op.pop()
			i++
		} else if i < len(src) && op.top == -1 { //10
			op.push(string(src[i]))
			i++
		} else if i < len(src) && op.data[op.top] == "(" { //4,7,13
			op.push(string(src[i]))
			i++
		} else if i < len(src) && (string(src[i]) == "*" || string(src[i]) == "/") && (op.data[op.top] == "+" || op.data[op.top] == "-") { //16
			op.push(string(src[i]))
			i++
		} else if i < len(src) {
			dst[j] = op.pop()
			j++
		}
	}

	for op.top != -1 { //18,19
		dst[j] = op.pop()
		j++
	}

	fmt.Println(dst)
	return dst

}

//用于计算传入的后缀表达式,并输出结果
func Calculate(RPN [Max_Size]string) {
	var num Stack
	num.init()
	for i := 0; i < len(RPN); i++ {
		if RPN[i] != "" {
			if string(RPN[i]) >= "0" && string(RPN[i]) <= "9" {
				num.push(RPN[i])
			} else if RPN[i] == "+" {
				x, _ := strconv.Atoi(num.pop())
				y, _ := strconv.Atoi(num.pop())
				n := x + y
				num.push(strconv.Itoa(n))
			} else if RPN[i] == "-" {
				x, _ := strconv.Atoi(num.pop())
				y, _ := strconv.Atoi(num.pop())
				n := y - x
				num.push(strconv.Itoa(n))
			} else if RPN[i] == "*" {
				x, _ := strconv.Atoi(num.pop())
				y, _ := strconv.Atoi(num.pop())
				n := y * x
				num.push(strconv.Itoa(n))
			} else if RPN[i] == "/" {
				x, _ := strconv.Atoi(num.pop())
				y, _ := strconv.Atoi(num.pop())
				n := y / x
				num.push(strconv.Itoa(n))
			}
		}
	}
	fmt.Println(num.data[0])
}


func main() {
	fmt.Println("Input an expression like (10/2+3)*4-5")
	var expr string
	fmt.Scanln(&expr) //用于将用户输入的值传给expr的地址上,从而传给expr变量
	RPN := Get_RPN(expr)
	Calculate(RPN)
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值