網(wǎng)站首頁 編程語言 正文
一、前言
go語言中,并沒有棧與隊列相關(guān)的數(shù)據(jù)結(jié)構(gòu),但是我們可以借助切片來實現(xiàn)棧與隊列的操作;接下來我們一起實現(xiàn)棧與隊列基本操作,并且還會實現(xiàn)用棧實現(xiàn)隊列,用隊列實現(xiàn)棧的操作。
二、實現(xiàn)棧與隊列基本操作
2.1 棧基本操作
go語言實現(xiàn)棧和隊列主要用到append 和切片(用內(nèi)置數(shù)組類型進行操作)
//創(chuàng)建棧 stack := make([]int, 0) //push壓入棧 stack = append(stack, 10) //pop彈出 v := stack[len(stack)-1] stack = stack[:len(stack)-1] //檢查棧空 len(stack) == 0
2.2 隊列基本操作
//創(chuàng)建隊列 queue := make([]int, 0) //enqueue入隊 queue = append(queue, 10) //dequeue出隊 v := queue[0] queue = queue[1:] //檢查隊列為空 len(queue) == 0
三、用棧實現(xiàn)隊列
3.1 理論
使用棧來模式隊列的行為,如果僅僅用一個棧,是一定不行的,所以需要兩個棧一個輸入棧,一個輸出棧,這里要注意輸入棧和輸出棧的關(guān)系。
下面動畫模擬以下隊列的執(zhí)行過程如下:
執(zhí)行語句:
queue.push(1); queue.push(2); queue.pop(); 注意此時的輸出棧的操作 queue.push(3); queue.push(4); queue.pop(); queue.pop();注意此時的輸出棧的操作 queue.pop(); queue.empty();
在push數(shù)據(jù)的時候,只要數(shù)據(jù)放進輸入棧就好,但在pop的時候,操作就復雜一些,輸出棧如果為空,就把進棧數(shù)據(jù)全部導入進來(注意是全部導入),再從出棧彈出數(shù)據(jù),如果輸出棧不為空,則直接從出棧彈出數(shù)據(jù)就可以了。
最后如何判斷隊列為空呢?如果進棧和出棧都為空的話,說明模擬的隊列為空了。
3.2 算法題
接下來看一下LeetCode原題
請你僅使用兩個棧實現(xiàn)先入先出隊列。隊列應當支持一般隊列支持的所有操作(push、pop、peek、empty):
實現(xiàn) MyQueue 類:
void push(int x) 將元素 x 推到隊列的末尾 int pop() 從隊列的開頭移除并返回元素 int peek() 返回隊列開頭的元素 boolean empty() 如果隊列為空,返回 true ;否則,返回 false 說明:
你 只能 使用標準的棧操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的語言也許不支持棧。你可以使用 list 或者 deque(雙端隊列)來模擬一個棧,只要是標準的棧操作即可。
3.3 思路
解決這個問題,需要一個輸出棧和輸入棧
先將數(shù)據(jù)放到輸入棧,再把數(shù)據(jù)從輸入棧放到輸出棧,此時輸出棧輸出數(shù)據(jù)的順序就和隊列一樣了,先入先出
3.4 代碼部分
type MyQueue struct { stackIn []int // 用來保存Push數(shù)據(jù) stackOut []int // 用來保存Pop數(shù)據(jù) } // 棧構(gòu)造器 func Constructor() MyQueue { return MyQueue{ stackIn: make([]int, 0), stackOut: make([]int, 0), } } func (this *MyQueue) Push(x int) { // 判斷stackOut中是否有元素,有的話全部放到stackIn for len(this.stackOut) != 0 { val := this.stackOut[len(this.stackOut)-1] this.stackOut = this.stackOut[:len(this.stackOut)-1] this.stackIn = append(this.stackIn, val) } // 將數(shù)據(jù)加進stackIn this.stackIn = append(this.stackIn, x) } func (this *MyQueue) Pop() int { // 判斷stackIn中是否有元素,有的話全部放到stackOut for len(this.stackIn) != 0 { val := this.stackIn[len(this.stackIn)-1] this.stackIn = this.stackIn[:len(this.stackIn)-1] this.stackOut = append(this.stackOut, val) } // stackOut為零,說明沒有元素,return 0 if len(this.stackOut) == 0 { return 0 } // stackOut Pop 元素 res := this.stackOut[len(this.stackOut)-1] this.stackOut = this.stackOut[:len(this.stackOut)-1] return res } func (this *MyQueue) Peek() int { // 調(diào)用Pop()方法 val := this.Pop() // val為零,說明沒有元素,return 0 if val == 0 { return 0 } // Pop()方法刪除了val,這里加上 this.stackOut = append(this.stackOut, val) return val } func (this *MyQueue) Empty() bool { // 兩個棧都為空,說明為空,否則不為空 return len(this.stackOut) == 0 && len(this.stackIn) == 0 }
代碼可以直接拿到力扣上運行。我已經(jīng)將細節(jié)全部用注釋解釋了,如果不懂可以私信博主。
四、用隊列實現(xiàn)棧
4.1 理論
隊列模擬棧,其實一個隊列就夠了,那么我們先說一說兩個隊列來實現(xiàn)棧的思路。
隊列是先進先出的規(guī)則,把一個隊列中的數(shù)據(jù)導入另一個隊列中,數(shù)據(jù)的順序并沒有變,并沒有變成先進后出的順序。
所以用棧實現(xiàn)隊列, 和用隊列實現(xiàn)棧的思路還是不一樣的,這取決于這兩個數(shù)據(jù)結(jié)構(gòu)的性質(zhì)。
但是依然還是要用兩個隊列來模擬棧,只不過沒有輸入和輸出的關(guān)系,而是另一個隊列完全用又來備份的!
如下面動畫所示,用兩個隊列que1和que2實現(xiàn)隊列的功能,que2其實完全就是一個備份的作用,把que1最后面的元素以外的元素都備份到que2,然后彈出最后面的元素,再把其他元素從que2導回que1。
模擬的隊列執(zhí)行語句如下:
queue.push(1); queue.push(2); queue.pop(); // 注意彈出的操作 queue.push(3); queue.push(4); queue.pop(); // 注意彈出的操作 queue.pop(); queue.pop(); queue.empty();
4.2 算法題
接下來看一下LeetCode原題
請你僅使用兩個隊列實現(xiàn)一個后入先出(LIFO)的棧,并支持普通棧的全部四種操作(push、top、pop 和 empty)。
實現(xiàn) MyStack 類:
void push(int x) 將元素 x 壓入棧頂。 int pop() 移除并返回棧頂元素。 int top() 返回棧頂元素。 boolean empty() 如果棧是空的,返回 true ;否則,返回 false 。
注意:
你只能使用隊列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 這些操作。 你所使用的語言也許不支持隊列。 你可以使用 list (列表)或者 deque(雙端隊列)來模擬一個隊列 , 只要是標準的隊列操作即可。
4.3 思路
用兩個隊列que1和que2實現(xiàn)隊列的功能,que2其實完全就是一個備份的作用,把que1最后面的元素以外的元素都備份到que2,然后彈出最后面的元素,再把其他元素從que2導回que1。
4.4 使用兩個隊列實現(xiàn)
type MyStack struct { //創(chuàng)建兩個隊列 queue1 []int queue2 []int } func Constructor() MyStack { return MyStack{ //初始化 queue1:make([]int,0), queue2:make([]int,0), } } func (this *MyStack) Push(x int) { //先將數(shù)據(jù)存在queue2中 this.queue2 = append(this.queue2,x) //將queue1中所有元素移到queue2中,再將兩個隊列進行交換 this.Move() } func (this *MyStack) Move(){ if len(this.queue1) == 0{ //交換,queue1置為queue2,queue2置為空 this.queue1,this.queue2 = this.queue2,this.queue1 }else{ //queue1元素從頭開始一個一個追加到queue2中 this.queue2 = append(this.queue2,this.queue1[0]) this.queue1 = this.queue1[1:] //去除第一個元素 this.Move() //重復 } } func (this *MyStack) Pop() int { val := this.queue1[0] this.queue1 = this.queue1[1:] //去除第一個元素 return val } func (this *MyStack) Top() int { return this.queue1[0] //直接返回 } func (this *MyStack) Empty() bool { return len(this.queue1) == 0 }
4.5 優(yōu)化
其實這道題目就是用一個隊列就夠了。
一個隊列在模擬棧彈出元素的時候只要將隊列頭部的元素(除了最后一個元素外) 重新添加到隊列尾部,此時在去彈出元素就是棧的順序了。
4.6 使用一個隊列實現(xiàn)
type MyStack struct { queue []int//創(chuàng)建一個隊列 } /** Initialize your data structure here. */ func Constructor() MyStack { return MyStack{ //初始化 queue:make([]int,0), } } /** Push element x onto stack. */ func (this *MyStack) Push(x int) { //添加元素 this.queue=append(this.queue,x) } /** Removes the element on top of the stack and returns that element. */ func (this *MyStack) Pop() int { n:=len(this.queue)-1//判斷長度 for n!=0{ //除了最后一個,其余的都重新添加到隊列里 val:=this.queue[0] this.queue=this.queue[1:] this.queue=append(this.queue,val) n-- } //彈出元素 val:=this.queue[0] this.queue=this.queue[1:] return val } /** Get the top element. */ func (this *MyStack) Top() int { //利用Pop函數(shù),彈出來的元素重新添加 val:=this.Pop() this.queue=append(this.queue,val) return val } /** Returns whether the stack is empty. */ func (this *MyStack) Empty() bool { return len(this.queue)==0 }
原文鏈接:https://juejin.cn/post/7164602338752069668
相關(guān)推薦
- 2022-06-25 Android開發(fā)實現(xiàn)圖片大小與質(zhì)量壓縮及保存_Android
- 2023-12-19 spring boot configuration annotation processor not
- 2022-12-26 python?時間處理之月份加減問題_python
- 2024-03-15 Redis中RDB和AOF
- 2022-07-08 C#獲取應用程序路徑或Web頁面目錄路徑_C#教程
- 2022-10-14 Sklearn中的二分類模型可以進行多分類的原理
- 2022-11-10 golang?常用定時任務匯總_Golang
- 2022-01-12 解決element-ui 日期選擇器提交后臺數(shù)據(jù)不準確問題
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支