栈_逆波兰表达式_计算器实现_Golang版本

u012807459 · · 2427 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

借助栈与逆波兰表达式 实现一个计算器,编程语言用的是Golang。

逆波兰表达式可以讲复杂的计算过程转化为简单的操作过程,进而得出答案。 比如 (a+b)*(b-c) 按照逆波兰表达式的规则得到 :ab+bc-*  

然后将该表达式的字符以及符号,按照从左到右的顺序,依次入栈,一碰到符号则将栈顶前两个元素取出,做运算然后放入栈内,重复该操作,直到表达式结束。

下面将结合栈与逆波兰表达式写一个简易计算器。

运行命令如下

go run counter.go --expression=\(3-5\)*4-\(5*8\)/3+78*9

代码示例:

package main

import (
	"fmt"
	"strconv"
	"flag"
)

type StackNode struct {
	Data interface{}
	next *StackNode
}

type LinkStack struct {
	top *StackNode
	Count int
}

func (this *LinkStack) Init() {
	this.top = nil
	this.Count = 0
}

func (this *LinkStack) Push(data interface{}) {
	var node *StackNode = new(StackNode)
	node.Data = data
	node.next = this.top
	this.top = node
	this.Count++
}

func (this *LinkStack) Pop() interface{} {
	if this.top == nil {
		return nil
	}
	returnData := this.top.Data
	this.top = this.top.next
	this.Count--
	return returnData
}

//Look up the top element in the stack, but not pop.
func (this *LinkStack) LookTop() interface{} {
	if this.top == nil {
		return nil
	}
	return this.top.Data
}

var str *string = flag.String("expression", "", "")

func main() {
	flag.Parse()
	fmt.Println(*str)
	fmt.Println(Count(*str))
}

func Count(data string) float64 {
	//TODO 检查字符串输入
	var arr []string = generateRPN(data)
	return calculateRPN(arr)
}

func calculateRPN(datas []string) float64 {
	var stack LinkStack
	stack.Init()
	for i := 0; i < len(datas); i++ {
		if isNumberString(datas[i]) {
			if f, err := strconv.ParseFloat(datas[i], 64); err != nil {
				panic("operatin process go wrong.")
			} else {
				stack.Push(f)
			}
		} else {
			p1 := stack.Pop().(float64)
			p2 := stack.Pop().(float64)
			p3 := normalCalculate(p2, p1, datas[i])
			stack.Push(p3)
		}
	}
	res := stack.Pop().(float64)
	return res
}

func normalCalculate(a,b float64, operation string) float64 {
	switch operation{
	case "*":
		return a * b
	case "-":
		return a - b
	case "+":
		return a + b
	case "/":
		return a / b
	default:
		panic("invalid operator")
	}
}

func generateRPN(exp string) []string {

	var stack LinkStack
	stack.Init()

	var spiltedStr []string = convertToStrings(exp)
	var datas []string

	for i := 0; i < len(spiltedStr); i++ { // 遍历每一个字符
		tmp := spiltedStr[i] //当前字符

		if !isNumberString(tmp) { //是否是数字
			// 四种情况入栈
			// 1 左括号直接入栈
			// 2 栈内为空直接入栈
			// 3 栈顶为左括号,直接入栈
			// 4 当前元素不为右括号时,在比较栈顶元素与当前元素,如果当前元素大,直接入栈。
			if tmp == "(" ||
				stack.LookTop() == nil || stack.LookTop().(string) == "(" ||
				( compareOperator(tmp, stack.LookTop().(string)) == 1 && tmp != ")" ) {
				stack.Push(tmp)
			} else { // ) priority
				if tmp == ")" { //当前元素为右括号时,提取操作符,直到碰见左括号
					for {
						if pop := stack.Pop().(string); pop == "(" {
							break
						} else {
							datas = append(datas, pop)
						}
					}
				} else { //当前元素为操作符时,不断地与栈顶元素比较直到遇到比自己小的(或者栈空了),然后入栈。
					for {
						pop := stack.LookTop()
						if pop != nil && compareOperator(tmp, pop.(string)) != 1 {
							datas = append(datas, stack.Pop().(string))
						} else {
							stack.Push(tmp)
							break
						}
					}
				}
			}

		} else {
			datas = append(datas, tmp)
		}
	}

	//将栈内剩余的操作符全部弹出。
	for {
		if pop := stack.Pop(); pop != nil {
			datas = append(datas, pop.(string))
		} else {
			break
		}
	}
	return datas
}

// if return 1, o1 > o2.
// if return 0, o1 = 02
// if return -1, o1 < o2
func compareOperator(o1, o2 string) int {
	// + - * /
	var o1Priority int
	if o1 == "+" || o1 == "-" {
		o1Priority = 1
	} else {
		o1Priority = 2
	}
	var o2Priority int
	if o2 == "+" || o2 == "-" {
		o2Priority = 1
	} else {
		o2Priority = 2
	}
	if o1Priority > o2Priority {
		return 1
	} else if o1Priority == o2Priority {
		return 0
	} else {
		return -1
	}
}

func isNumberString(o1 string) bool {
	if o1 == "+" || o1 == "-" || o1 == "*" || o1 == "/" || o1 == "(" || o1 == ")" {
		return false
	} else {
		return true
	}
}

func convertToStrings(s string) []string {
	var strs []string
	bys := []byte(s)
	var tmp string
	for i := 0; i < len(bys); i++ {
		if !isNumber(bys[i]) {
			if tmp != "" {
				strs = append(strs, tmp)
				tmp = ""
			}
			strs = append(strs, string(bys[i]))
		} else {
			tmp = tmp+string(bys[i])
		}
	}
	strs = append(strs, tmp)
	return strs
}

func isNumber(o1 byte) bool {
	if o1 == '+' || o1 == '-' || o1 == '*' || o1 == '/' || o1 == '(' || o1 == ')' {
		return false
	} else {
		return true
	}
}


本文来自:CSDN博客

感谢作者:u012807459

查看原文:栈_逆波兰表达式_计算器实现_Golang版本

入群交流(和以上内容无关):Go中文网 QQ 交流群:729884609 或加微信入微信群:274768166 备注:入群;关注公众号:Go语言中文网

2427 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传