Go_栈及应用

栈(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
  • 思想Go_栈及应用_第1张图片
  • 代码
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)
}

你可能感兴趣的:(Golang学习,golang,算法,数据结构)