栈的一种Go语言实现

package main

import (
    "errors"
    "fmt"
)

type Stack struct {
    MaxTop int //栈的最大容量
    Top int //栈顶
    arr [5]int
}

func (s *Stack) Push(val int) (err error) {
    //判断栈是否已满
    if s.Top == s.MaxTop - 1 {
        fmt.Println("stack full")
        return errors.New("stack full")
    }

    s.Top++
    s.arr[s.Top] = val
    return
}

func (s *Stack) Pop() (val int, err error) {
    //判断栈是否为空
    if s.Top == -1 {
        fmt.Println("stack empty")
        return -1, errors.New("stack empty")
    }

    val = s.arr[s.Top]
    s.Top--
    return val, nil
}

func (s *Stack) List() {
    //判断栈是否为空
    if s.Top == -1 {
        fmt.Println("stack empty")
        return
    }

    //从栈顶开始遍历
    for i := s.Top; i >= 0; i-- {
        fmt.Printf("arr[%d]=%d\n", i, s.arr[i])
    }
}

func main(){
    stack := &Stack{
        MaxTop: 5,
        Top:    -1,
    }

    //入栈
    stack.Push(1)
    stack.Push(2)
    stack.Push(3)
    stack.Push(4)
    stack.Push(5)
    stack.Push(6)

    //显示
    stack.List()

    //弹出
    val, _ := stack.Pop()
    val, _ = stack.Pop()
    val, _ = stack.Pop()
    val, _ = stack.Pop()
    val, _ = stack.Pop()
    //val, _ = stack.Pop()
    fmt.Println("出栈val=", val)
    stack.List()
}

应用案例:

问题:计算一串字符串表达式

思路:

1.创建两个栈,一个是存放数字的栈,一个是存放操作符的栈,记为numStack, operStack;

2.如果扫描字符串时发现是数字,则直接入数栈;

3.如果发现是一个运算符则分为两种情况:

3.1如果操作符栈operStack是一个空栈,则直接入栈;

3.2如果操作符栈operStack不是一个空栈则按照操作符的优先级分为两种情况计算:

​ 3.2.1如果发现operStack栈顶的运算符的优先级大于等于当前准备入栈的运算符的优先级,就从符号栈pop出操作符,同时从数栈pop出两个数进行运算,将运算后的结果再重新入栈到数栈,再将当前准备入栈的符号入栈到操作符栈;

​ 3.2.2 否则,运算符直接入栈;

4.如果扫描表达式完毕,依次从符号栈取出符号,然后从数栈取出两个数,将运算后的结果再入栈,直到符号栈为空,此时数栈中的值为表达式的计算结果。

package main

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

type expStack struct {
    MaxTop int //栈的最大容量
    Top int //栈顶
    arr [20]int
}

func (s *expStack) Push(val int) (err error) {
    //判断栈是否已满
    if s.Top == s.MaxTop - 1 {
        fmt.Println("stack full")
        return errors.New("stack full")
    }

    s.Top++
    s.arr[s.Top] = val
    return
}

func (s *expStack) Pop() (val int, err error) {
    //判断栈是否为空
    if s.Top == -1 {
        fmt.Println("stack empty")
        return -1, errors.New("stack empty")
    }

    val = s.arr[s.Top]
    s.Top--
    return val, nil
}

func (s *expStack) List() {
    //判断栈是否为空
    if s.Top == -1 {
        fmt.Println("stack empty")
        return
    }

    //从栈顶开始遍历
    for i := s.Top; i >= 0; i-- {
        fmt.Printf("arr[%d]=%d\n", i, s.arr[i])
    }
}

//判断一个字符是否是运算符
func (s *expStack) IsOper(val int) bool {
    if val == 42 || val == 43 || val == 45 || val == 47 {
        return true
    }else {
        return false
    }
}

//运算方法
func (s *expStack) Cal(num1, num2, 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
}

//返回运算符的优先级,自定义
func (s *expStack) Priority(oper int) int {
    res := 0
    if oper == 42 || oper == 47 {
        res = 1 //自定义
    }else if oper == 43 || oper == 45 {
        res = 0
    }else {
        fmt.Println("其他情况")
    }
    return res
}

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

    exp := "30+20*6-2"
    index := 0
    num1, num2, oper := 0, 0, 0
    keepNum := ""

    for {
        //处理多位数问题

        ch := exp[index:index+1] //"3"
        temp := int([]byte(ch)[0]) //字符对应的ASCII码值
        if operStack.IsOper(temp) { //是符号
            //如果是空栈,直接入栈
            if operStack.Top == -1 {
                operStack.Push(temp)
            }else {
                //如果发现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 { //说明是数
            //定义一个变量keepNum 做字符串拼接处理多位数
            //每次要向index的后面字符测试一下,看看是不是运算法
            keepNum += ch

            if index == len(exp) - 1 { //如果是字符串的最后则直接入栈,防止引起空指针错误
                val, _ := strconv.ParseInt(keepNum, 10, 64)
                numStack.Push(int(val))
            }else {
                if operStack.IsOper(int([]byte(exp[index+1:index+2])[0])) { //判断下一个字符是不是运算符
                    val, _ := strconv.ParseInt(keepNum, 10, 64)
                    numStack.Push(int(val))
                    keepNum = ""
                }
            }
        }

        //判断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)
}

Yuan_sr
18 声望6 粉丝