栈(stack 堆栈)
应用场景
- 子程序的调用,在跳往子程序前,会先将下一个指令的地址存到堆栈中,直到子程序执行完后再将地区取出,以回到原来的程序中
- 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中
- 表达式的转换与求值
- 二叉树的遍历
- 图形的深度优先搜索法
快速入门
package main
import (
"fmt"
"errors"
)
//使用数组模拟栈的使用
type ArrayStack struct{
MaxTop int //栈的存数容量
Top int //表示栈顶
arr [5]int //数组模拟栈
}
//入栈
func (this *ArrayStack)Push(val int)(err error){
//先判断栈是否已经满了
if this.Top == this.MaxTop-1{
fmt.Println("栈已经满了")
return errors.New("stack full")
}
this.Top++
//存入数据
this.arr[this.Top] = val
return
}
//出栈
func (this *ArrayStack)Pop()(val int,err error){
//先判断栈是否已经空了
if this.Top == -1{
fmt.Println("栈已经空了")
return 0, errors.New("stack empty")
}
//取数据
val = this.arr[this.Top]
this.Top--
return val, nil
}
//遍历栈
func (this *ArrayStack)List(){
//先判断栈是否为空
if this.Top == -1{
fmt.Println("栈空")
return
}
fmt.Println("栈的情况")
for i:=this.Top; i >=0; i--{
fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
}
}
func main(){
arrayStack := &ArrayStack{
MaxTop : 5, //表示最多存5个数到栈中
Top : -1, //当栈顶为-1 表示栈为空
}
arrayStack.Push(1)
arrayStack.Push(2)
arrayStack.Push(3)
arrayStack.Push(4)
arrayStack.Push(5)
arrayStack.List()
val, _:= arrayStack.Pop()
fmt.Println("出栈的数是:", val)
arrayStack.List()
}
使用栈实现综合计算器
- 例:计算3+2*6-2
- 思想
- 代码
package main
import (
"fmt"
"errors"
"strconv"
)
//使用数组模拟栈的使用
type ArrayStack struct{
MaxTop int //栈的存数容量
Top int //表示栈顶
arr [20]int //数组模拟栈
}
//入栈
func (this *ArrayStack)Push(val int)(err error){
//先判断栈是否已经满了
if this.Top == this.MaxTop-1{
fmt.Println("栈已经满了")
return errors.New("stack full")
}
this.Top++
//存入数据
this.arr[this.Top] = val
return
}
//出栈
func (this *ArrayStack)Pop()(val int,err error){
//先判断栈是否已经空了
if this.Top == -1{
fmt.Println("栈已经空了")
return 0, errors.New("stack empty")
}
//取数据
val = this.arr[this.Top]
this.Top--
return val, nil
}
//遍历栈
func (this *ArrayStack)List(){
//先判断栈是否为空
if this.Top == -1{
fmt.Println("栈空")
return
}
fmt.Println("栈的情况")
for i:=this.Top; i >=0; i--{
fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
}
}
//判断一个字符是不是一个 运算符,只做加(43)减(45)乘(42)除(47),直接使用ASCII码对比
func (this ArrayStack)IsOper(val int)bool{
if val == 42 || val ==43 || val ==47 ||val == 45{
return true
}else{
return false
}
}
//运算的方法
func (this *ArrayStack)Cal(num1 int, num2 int, 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
}
//编写一个方法,返回某个运算符的优先级,乘法和除法的优先级为1,加法和减法的优先级为0
func (this *ArrayStack)Priority(oper int)int{
res := 0
if oper == 42 || oper == 47{
res = 1
}else if oper == 43 || oper == 45{
res = 0
}
return res
}
func main(){
//数栈
numStack := &ArrayStack{
MaxTop: 20,
Top:-1,
}
//符号栈
operStack :=&ArrayStack{
MaxTop: 20,
Top:-1,
}
//表达式 3+2*6-2
exp := "3+2*6-2" //底层是切片
//为了配合运算,定义需要的变量
num1 := 0
num2 := 0
oper := 0
result := 0
//定义一个index 帮助扫描表达式
index := 0
for {
ch := exp[index:index+1] //返回单个字符的字符串 第一个 “3”
// 将字符转int
temp := int([]byte(ch)[0]) //就是字符对应的ASCII码
if operStack.IsOper(temp){ //说明是符号
//思路中的6
//判断是否为空栈
if operStack.Top == -1{
operStack.Push(temp)
}else{
//思路中的6的2.1
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{//思路中的6的2.2
operStack.Push(temp)
}
}
}else{ //说明是数
val,_ := strconv.ParseInt(ch, 10, 64)
numStack.Push(int(val))
}
//继续扫描
//先判断index是否已经扫描到计算表达式的最后
if index +1 == len(exp){
break
}
index++
}
//完成思路中的7
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)
}
//主函数改进
func main(){
//数栈
numStack := &ArrayStack{
MaxTop: 20,
Top:-1,
}
//符号栈
operStack :=&ArrayStack{
MaxTop: 20,
Top:-1,
}
//表达式 3+2*6-2
exp := "30+30*6-4" //底层是切片
//为了配合运算,定义需要的变量
num1 := 0
num2 := 0
oper := 0
result := 0
keepNum := ""
//定义一个index 帮助扫描表达式
index := 0
for {
//处理多位数的问题
ch := exp[index:index+1] //返回单个字符的字符串 第一个 “3”
// 将字符转int
temp := int([]byte(ch)[0]) //就是字符对应的ASCII码
if operStack.IsOper(temp){ //说明是符号
//思路中的6
//判断是否为空栈
if operStack.Top == -1{
operStack.Push(temp)
}else{
//思路中的6的2.1
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{//思路中的6的2.2
operStack.Push(temp)
}
}
}else{ //说明是数
//处理多位数思路
//1、先定义一个变量 keepNum string, 做拼接
keepNum += ch
//2、每次要先index的前面字符测试一下,看看是不是运算法,然后处理
//如果已经到表达式最后,直接拼接
if index == len(exp)-1{
val,_ := strconv.ParseInt(keepNum, 10, 64)
numStack.Push(int(val))
}else{
//向index后面探一位,看看是不是操作符
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++
}
//完成思路中的7
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)
}