栈的介绍
有些程序员也把栈称为堆栈,即栈和堆是同一个概念
栈的英文为Stack
栈是一个先入后出(FILO-First In Last Out)的有序列表
栈(Stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
根据堆栈的定义可知,最先放入栈中的元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素先删除,最先放入的元素最后删除。
栈的应用场景
1. 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
2. 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
3. 表达式的转换与求值
4. 二叉树遍历
5. 图形的深度优先(depth-first)搜索法
栈的案例
案例一:用数组模拟一个栈
package main
import (
"github.com/kataras/iris/core/errors"
"fmt"
"time"
)
//使用数组模拟栈的使用
type Stack struct {
MaxTop int //最大存放个数
Top int //栈顶
Array [5]int //数组模拟栈
}
//入栈
func (S *Stack)Push (val int)(err error){
//先判断栈是否满了
if (S.MaxTop-1) == S.Top{
return errors.New("栈满了")
}
S.Top++
S.Array[S.Top] = val
return nil
}
func (S *Stack)Pop()(val int,err error){
if S.Top == -1{
return -1, errors.New("栈空了")
}
//先取值,在--
val = S.Array[S.Top]
S.Top--
return val,nil
}
//遍历栈(从栈顶开始遍历)
func (S *Stack)List(){
if S.Top == -1{
fmt.Println("栈为空")
return
}
fmt.Println("栈的情况如下:")
for i := S.Top;i>=0;i--{
fmt.Printf("arr[%d] = %d \n",i,S.Array[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.List()
time.Sleep(time.Second*3)
res,_ := stack.Pop()
fmt.Println("res===>",res)
res1,_ :=stack.Pop()
fmt.Println("res===>",res1)
stack.List()
}
案例二:用栈实现综合计算器
使用栈来实现综合计算器–自定义优先级
请输入一个表达式:
计算式:[3+2*6-2] 点击计算
算法思路分析:
- 创建两个栈,numStack,operStack
- numStack存放数,operStack存放操作符
- index:=0
- exp计算表达式,是一个字符串
- 如果扫描发现是一个数字,则直接入numStack
- 如果发现是一个运算符:
(1)如果operStack是一个空栈,直接入栈
(2)如果operStack不是一个空栈
* 如果发现operStack栈顶的运算符的优先级大雨等于当前准备入栈的运算符的优先级,就从符号栈pop出,并从数栈也pop出两个数,进行运算,运算后的结果再重新入栈到数栈中,符号再如符号栈。
* 否则,运算符就直接入栈 - 如果扫描表达式完毕,一次从符号栈取出符号,然后从数栈取出两个数,运算后的结果入数站,直到符号为空。
代码实现
package main
import (
"github.com/kataras/iris/core/errors"
"fmt"
"strconv"
)
//使用数组模拟栈的使用
type StackCalculation struct {
MaxTop int //最大存放个数
Top int //栈顶
Array [20]int //数组模拟栈
}
//入栈
func (S *StackCalculation)Push (val int)(err error){
//先判断栈是否满了
if (S.MaxTop-1) == S.Top{
return errors.New("栈满了")
}
S.Top++
S.Array[S.Top] = val
return nil
}
func (S *StackCalculation)Pop()(val int,err error){
if S.Top == -1{
return -1, errors.New("栈空了")
}
//先取值,在--
val = S.Array[S.Top]
S.Top--
return val,nil
}
//遍历栈(从栈顶开始遍历)
func (S *StackCalculation)List(){
if S.Top == -1{
fmt.Println("栈为空")
return
}
//curTop := S.Top
fmt.Println("栈的情况如下:")
for i := S.Top;i>=0;i--{
fmt.Printf("arr[%d] = %d \n",i,S.Array[i])
}
}
//判断一个字符是不是运算符(+,-,*,/)
func(S *StackCalculation)IsOper(val int)bool{
if val == 42 || val == 43 || val == 45 || val == 47{
return true
}else{
return false
}
}
//判断运算符的优先级[* / => 1,+ = => 0]
func (S *StackCalculation)Priority (oper int)int{
res := 0
if oper == 42 || oper == 47{
res = 1
}else if oper == 43 || oper == 45{
res = 0
}
return res
}
//运算
func (S *StackCalculation)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 main() {
//数栈
numStack := &StackCalculation{
MaxTop:20,
Top:-1,
}
//符号栈
operStack := &StackCalculation{
MaxTop:20,
Top:-1,
}
exp := "50+2*8-20"
index := 0
num1 := 0
num2 := 0
oper := 0
keepNum := ""
result := 0
for{
//处理多位数的问题
ch := exp[index:index+1]//取单个字符串
//判断是否是一个数组
temp := int([]byte(ch)[0])
if operStack.IsOper(temp){//说明是符号
if operStack.Top == -1{//空
operStack.Push(temp)
}else{
if operStack.Priority(operStack.Array[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{//说明是数
//处理多位数思路
//1、定义一个变量keepNum string,做拼接
//2、每次要想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 = ""
}
}
}
//保证继续扫描
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)
}
res,_ := numStack.Pop()
fmt.Printf("表达式%s = %v",exp,res)
}