栈的一种Go语言实现
package mainimport ( "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 mainimport ( "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)}