go 命令行计算器:接受用户输入的算数表达式,并输出结果
示例
请输入算数表达式:99*(99+6)-77/2-3.5
99*(99+6)-77/2-3.5 的值为:10353.000000
思路:
使用栈先入后出的特点和计算符的优先级,把获取的字符串转为后缀表达式,并同时使用栈来计算结果
1.定义符号优先级(使用map映射绑定)
2.定义栈
3.中缀表达式转后缀表达式函数
4.计算后缀表达式
5.后缀表达式计算函数
各部分代码
1.定义符号优先级(使用map映射绑定)
var priority = map[rune]int{
'+': 1,
'-': 1,
'*': 2,
'/': 2,
'(': 0,
}
2.定义栈结构
// 实现栈结构
type SliceStack struct {
dataStack []interface{}
}
// 创建一个新的初始栈
func NewSliceStack() *SliceStack {
return &SliceStack{}
}
// 在栈顶放入数据
func (s *SliceStack) Push(data interface{}) {
s.dataStack = append(s.dataStack, data)
//append函数:在原切片的末尾添加元素
}
// 栈最上面的数据出栈
func (s *SliceStack) Pop() interface{} {
if len(s.dataStack) == 0 {
return nil
}
slice := s.dataStack[len(s.dataStack)-1]
s.dataStack = s.dataStack[:len(s.dataStack)-1]
//把栈顶下移一位
return slice
}
// 查看栈顶第一个元素
func (s *SliceStack) Peek() interface{} {
if len(s.dataStack) == 0 {
return nil
}
return s.dataStack[len(s.dataStack)-1]
}
// 判断栈是否空
func (s *SliceStack) IsEmpty() bool {
return len(s.dataStack) == 0
}
3.中缀表达式转后缀表达式函数
// 中缀表达式转缀表达式
func convert(shuru string) []interface{} {
//定义一个存放处理后的字符的切片
var inter []interface{}
//创建一个栈,用于存放运算符
houzhui := NewSliceStack()
for i := 0; i < len(shuru); i++ {
//转换输入的字段为rune类型方便值的判断
char := rune(shuru[i])
//字符为空格时,跳过此次循环
if char == ' ' {
continue
}
//使用unicode函数判断char是否为十进制字符
if unicode.IsDigit(char) || char == '.' {
num := ""
//把连着的数字符号整合在一起
for i < len(shuru) && (unicode.IsDigit(rune(shuru[i])) || rune(shuru[i]) == '.') {
num += string(shuru[i])
i++
}
i-- //回退一部,因为外层也有一个 i++
//将字符转化为浮点型
value, _ := strconv.ParseFloat(num, 64)
//将处理过后的数据放入inter切片中存放
inter = append(inter, value)
//在符号为"("的情况下直接放入字符栈中
} else if char == '(' {
houzhui.Push(char)
} else if char == ')' {
//在存放运算符的栈不为空,并且栈顶字符不为"("的情况下
for !houzhui.IsEmpty() && houzhui.Peek().(rune) != '(' {
//把运算符栈中的运算符取出放进inter中
inter = append(inter, houzhui.Pop())
}
//取出栈中"("
houzhui.Pop()
} else {
//处理运算符优先级
//在栈不为空,并且新的运算符优先级比栈顶的小的情况下
for !houzhui.IsEmpty() && priority[houzhui.Peek().(rune)] >= priority[char] {
//把运算符放入inter中
inter = append(inter, houzhui.Pop())
}
houzhui.Push(char)
}
}
//把剩余的操作符全部放入inter切片中
for !houzhui.IsEmpty() {
inter = append(inter, houzhui.Pop())
}
//返回切片
return inter
}
计算后缀表达式
// 计算后缀表达式
func computeDpostfixExpression(inter []interface{}) float64 {
//创建一个用存放数值
stored := NewSliceStack()
//遍历数值
for _, value := range inter {
//判断遍历数值的类型
switch value.(type) {
case float64:
//当类型为float64时,把值压入栈中
stored.Push(value)
case rune:
//当值为rune时判定为计算符,调用计算函数
calculatingFunction(stored, value.(rune))
}
}
//返回栈低最后一个值作为结果
return stored.Pop().(float64)
}
计算函数
// 计算函数
func calculatingFunction(stored *SliceStack, operator rune) {
//取出两个操作数
num1 := stored.Pop().(float64)
num2 := stored.Pop().(float64)
var result float64
switch operator {
case '+':
result = num2 + num1
case '-':
result = num2 - num1
case '*':
result = num2 * num1
case '/'://除法注意先后顺续不要错
result = num2 / num1
}
//将结果压回栈
stored.Push(result)
}
完整代码
package main
import (
"fmt"
"strconv"
"unicode"
)
// 1.定义符号优先级
// 2.定义栈
// 3.中缀转后缀表达式
// 4.计算后缀表达式
// 5.计算函数
// map映射绑定字符优先级
var priority = map[rune]int{
'+': 1,
'-': 1,
'*': 2,
'/': 2,
'(': 0,
}
// 实现栈结构
type SliceStack struct {
dataStack []interface{}
}
// 创建一个新的初始栈
func NewSliceStack() *SliceStack {
return &SliceStack{}
}
// 在栈顶放入数据
func (s *SliceStack) Push(data interface{}) {
s.dataStack = append(s.dataStack, data)
//append函数:在原切片的末尾添加元素
}
// 栈最上面的数据出栈
func (s *SliceStack) Pop() interface{} {
if len(s.dataStack) == 0 {
return nil
}
slice := s.dataStack[len(s.dataStack)-1]
s.dataStack = s.dataStack[:len(s.dataStack)-1]
//把栈顶下移一位
return slice
}
// 查看栈顶第一个元素
func (s *SliceStack) Peek() interface{} {
if len(s.dataStack) == 0 {
return nil
}
return s.dataStack[len(s.dataStack)-1]
}
// 判断栈是否空
func (s *SliceStack) IsEmpty() bool {
return len(s.dataStack) == 0
}
// 中缀表达式转缀表达式
func convert(shuru string) []interface{} {
//定义一个存放处理后的字符的切片
var inter []interface{}
//创建一个栈,用于存放运算符
houzhui := NewSliceStack()
for i := 0; i < len(shuru); i++ {
//转换输入的字段为rune类型方便值的判断
char := rune(shuru[i])
//字符为空格时,跳过此次循环
if char == ' ' {
continue
}
//使用unicode函数判断char是否为十进制字符
if unicode.IsDigit(char) || char == '.' {
num := ""
//把连着的数字符号整合在一起
for i < len(shuru) && (unicode.IsDigit(rune(shuru[i])) || rune(shuru[i]) == '.') {
num += string(shuru[i])
i++
}
i-- //回退一部,因为外层也有一个 i++
//将字符转化为浮点型
value, _ := strconv.ParseFloat(num, 64)
//将处理过后的数据放入inter切片中存放
inter = append(inter, value)
//在符号为"("的情况下直接放入字符栈中
} else if char == '(' {
houzhui.Push(char)
} else if char == ')' {
//在存放运算符的栈不为空,并且栈顶字符不为"("的情况下
for !houzhui.IsEmpty() && houzhui.Peek().(rune) != '(' {
//把运算符栈中的运算符取出放进inter中
inter = append(inter, houzhui.Pop())
}
//取出栈中"("
houzhui.Pop()
} else {
//处理运算符优先级
//在栈不为空,并且新的运算符优先级比栈顶的小的情况下
for !houzhui.IsEmpty() && priority[houzhui.Peek().(rune)] >= priority[char] {
//把运算符放入inter中
inter = append(inter, houzhui.Pop())
}
houzhui.Push(char)
}
}
//把剩余的操作符全部放入inter切片中
for !houzhui.IsEmpty() {
inter = append(inter, houzhui.Pop())
}
//返回切片
return inter
}
// 计算后缀表达式
func computeDpostfixExpression(inter []interface{}) float64 {
//创建一个用存放数值
stored := NewSliceStack()
//遍历数值
for _, value := range inter {
//判断遍历数值的类型
switch value.(type) {
case float64:
//当类型为float64时,把值压入栈中
stored.Push(value)
case rune:
//当值为rune时判定为计算符,调用计算函数
calculatingFunction(stored, value.(rune))
}
}
//返回栈低最后一个值作为结果
return stored.Pop().(float64)
}
// 计算函数
func calculatingFunction(stored *SliceStack, operator rune) {
//取出两个操作数
num1 := stored.Pop().(float64)
num2 := stored.Pop().(float64)
var result float64
switch operator {
case '+':
result = num2 + num1
case '-':
result = num2 - num1
case '*':
result = num2 * num1
case '/': //除法注意先后顺续不要错
result = num2 / num1
}
//将结果压回栈
stored.Push(result)
}
func main() {
var shuru string
fmt.Print("请输入算数表达式:")
_, err := fmt.Scanln(&shuru)
if err != nil {
fmt.Println("输入错误!", err)
return
}
postfix := convert(shuru)
result := computeDpostfixExpression(postfix)
fmt.Printf(" %s 的值为:%f\n", shuru, result)
}