棧(stack)
-
基本介紹
棧又名堆棧,它是一種運算受限的線性表。其限制是僅允許在表的一段進行插入和刪除運算。這一端被稱為棧頂,相對的,把另一端稱為棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成為新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰元素稱為新的棧頂元素。
-
應用場景
- 子程序的調用:在跳向子程序前,會將下個指令的地址存到堆棧中,直到子程序執行完後再將地址取出,以回到原來的程序中。
- 處理遞歸調用:和子程序的調用類似,只是除了儲存下一個指令的地址外,也將參數、區域變量等數據存入堆棧中。
- 表達式的轉換與求值
- 二叉樹的遍歷
- 圖形的深度優先搜索法
-
數組模擬
//數組模擬棧 type Stack struct { MaxTop int //最大可存放的個數 Top int //表示棧頂 arr [5]int //模擬棧 } //入棧 func (this *Stack)Push(val int) (err error) { //判斷棧是否滿了 if this.Top == this.MaxTop - 1 { return errors.New("stack full") } this.Top++ this.arr[this.Top] = val return } //出棧 func (this *Stack) Pop() (val int, err error) { //判斷棧是否空 if this.Top == -1 { return -1,errors.New("stack empty") } val = this.arr[this.Top] this.Top-- return } //遍歷 func (this *Stack) List() { //棧是否為空 if this.Top == -1 { fmt.Println("stack empty") return } fmt.Println("list:") for i := this.Top; i>= 0 ; i-- { fmt.Printf("arr[%d] = %d\n",i,this.arr[i]) } } func main() { a := &Stack{ MaxTop: 5, Top:-1, } a.List() fmt.Println(a.Pop()) a.Push(10) a.List() fmt.Println(a.Push(11)) fmt.Println(a.Push(12)) fmt.Println(a.Push(13)) fmt.Println(a.Push(14)) fmt.Println(a.Push(15)) a.List() fmt.Println(a.Pop()) a.List() }
-
棧實現加減乘除
//由於計算一般是從前往後算,如果使用棧的後進先出的特性, //必須調轉表達式,如2*3-3/2-1寫成1-3/2-2*3 //也可以自己寫函數完成字符串反轉,再入棧,這樣就可以按順序計算了 //數組模擬棧 type Stack struct { MaxTop int //最大可存放的個數 Top int //表示棧頂 arr [20]int //模擬棧 } //入棧 func (this *Stack)Push(val int) (err error) { //判斷棧是否滿了 if this.Top == this.MaxTop - 1 { return errors.New("stack full") } this.Top++ this.arr[this.Top] = val return } //出棧 func (this *Stack) Pop() (val int, err error) { //判斷棧是否空 if this.Top == -1 { return -1,errors.New("stack empty") } val = this.arr[this.Top] this.Top-- return } //遍歷 func (this *Stack) List() { //棧是否為空 if this.Top == -1 { fmt.Println("stack empty") return } fmt.Println("list:") for i := this.Top; i>= 0 ; i-- { fmt.Printf("arr[%d] = %d\n",i,this.arr[i]) } } //判斷一個字符串是不是運算符 //42 = * ;43 = + ;45 = - ; 47 = / func (this *Stack) IsOper(val int) bool { if val == 42 || val == 43 || val == 45 || val == 47 { return true }else { return false } } //運算方法 func (this *Stack) Cal(num1, num2 int, oper int) int { res := 0 switch oper { case 42: res = num2*num1 case 43: res = num2+num1 case 45: res = num1-num2 case 47: res = num2/num1 default: fmt.Println("運算符錯誤") } return res } //返回運算符的優先級 func (this *Stack) Priority(oper int) int { res := 0 if oper == 42 || oper == 47 { res = 1 } if oper == 43 || oper == 45 { res = 0 } return res } func main() { //數棧 numStack := &Stack{ MaxTop: 20, Top:-1, } //符號棧 operStack := &Stack{ MaxTop:20, Top:-1, } for { var exp string fmt.Println("請輸入表達式:") fmt.Scanln(&exp) index := 0 num1 := 0 num2 := 0 oper := 0 result := 0 keepNum := "" //掃描字符串 for { //取出字符串中的各個字符 ch := exp[index:index+1] //轉換成int做判斷 chint := int([]byte(ch)[0]) if operStack.IsOper(chint) { //如果是空棧就直接入棧 if operStack.Top == -1 { operStack.Push(chint) }else { //如果發現棧頂的運算符的優先級大於等於當前準備入棧的 //優先級,就從符號棧pop出,並從數棧也pop兩個數,進行 //運算,運算後的結果再重新入棧到數棧,當前符號在入符 // 號棧 if operStack.Priority(operStack.arr[operStack.Top])> operStack.Priority(chint){ num1,_ = numStack.Pop() num2,_ = numStack.Pop() oper,_ = operStack.Pop() result = operStack.Cal(num1,num2,oper) numStack.Push(result) operStack.Push(chint) }else { operStack.Push(chint) } } }else { //定義一個變量keepNum string,用於拼接 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) fmt.Printf("%d %c %d = %d",num1,oper,num2,result) fmt.Println() numStack.Push(result) } //將結果出棧 res,_ := numStack.Pop() fmt.Printf("表達式結果為:%d",res) fmt.Println() } }