Go語(yǔ)言實(shí)現(xiàn)棧與隊(duì)列基本操作學(xué)家
一、前言
go語(yǔ)言中,并沒(méi)有棧與隊(duì)列相關(guān)的數(shù)據(jù)結(jié)構(gòu),但是我們可以借助切片來(lái)實(shí)現(xiàn)棧與隊(duì)列的操作;接下來(lái)我們一起實(shí)現(xiàn)棧與隊(duì)列基本操作,并且還會(huì)實(shí)現(xiàn)用棧實(shí)現(xiàn)隊(duì)列,用隊(duì)列實(shí)現(xiàn)棧的操作。
二、實(shí)現(xiàn)棧與隊(duì)列基本操作
2.1 ?;静僮?/h3>
go語(yǔ)言實(shí)現(xiàn)棧和隊(duì)列主要用到append 和切片(用內(nèi)置數(shù)組類型進(jìn)行操作)
//創(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 隊(duì)列基本操作
//創(chuàng)建隊(duì)列 queue := make([]int, 0) //enqueue入隊(duì) queue = append(queue, 10) //dequeue出隊(duì) v := queue[0] queue = queue[1:] //檢查隊(duì)列為空 len(queue) == 0
三、用棧實(shí)現(xiàn)隊(duì)列
3.1 理論
使用棧來(lái)模式隊(duì)列的行為,如果僅僅用一個(gè)棧,是一定不行的,所以需要兩個(gè)棧一個(gè)輸入棧,一個(gè)輸出棧,這里要注意輸入棧和輸出棧的關(guān)系。
下面動(dòng)畫(huà)模擬以下隊(duì)列的執(zhí)行過(guò)程如下:
執(zhí)行語(yǔ)句:
queue.push(1); queue.push(2); queue.pop(); 注意此時(shí)的輸出棧的操作 queue.push(3); queue.push(4); queue.pop(); queue.pop();注意此時(shí)的輸出棧的操作 queue.pop(); queue.empty();

在push數(shù)據(jù)的時(shí)候,只要數(shù)據(jù)放進(jìn)輸入棧就好,但在pop的時(shí)候,操作就復(fù)雜一些,輸出棧如果為空,就把進(jìn)棧數(shù)據(jù)全部導(dǎo)入進(jìn)來(lái)(注意是全部導(dǎo)入),再?gòu)某鰲棾鰯?shù)據(jù),如果輸出棧不為空,則直接從出棧彈出數(shù)據(jù)就可以了。
最后如何判斷隊(duì)列為空呢?如果進(jìn)棧和出棧都為空的話,說(shuō)明模擬的隊(duì)列為空了。
3.2 算法題
接下來(lái)看一下LeetCode原題

請(qǐng)你僅使用兩個(gè)棧實(shí)現(xiàn)先入先出隊(duì)列。隊(duì)列應(yīng)當(dāng)支持一般隊(duì)列支持的所有操作(push、pop、peek、empty):
實(shí)現(xiàn) MyQueue 類:
void push(int x) 將元素 x 推到隊(duì)列的末尾 int pop() 從隊(duì)列的開(kāi)頭移除并返回元素 int peek() 返回隊(duì)列開(kāi)頭的元素 boolean empty() 如果隊(duì)列為空,返回 true ;否則,返回 false 說(shuō)明:
你 只能 使用標(biāo)準(zhǔn)的棧操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的語(yǔ)言也許不支持棧。你可以使用 list 或者 deque(雙端隊(duì)列)來(lái)模擬一個(gè)棧,只要是標(biāo)準(zhǔn)的棧操作即可。
3.3 思路
解決這個(gè)問(wèn)題,需要一個(gè)輸出棧和輸入棧
先將數(shù)據(jù)放到輸入棧,再把數(shù)據(jù)從輸入棧放到輸出棧,此時(shí)輸出棧輸出數(shù)據(jù)的順序就和隊(duì)列一樣了,先入先出
3.4 代碼部分
type MyQueue struct {
stackIn []int // 用來(lái)保存Push數(shù)據(jù)
stackOut []int // 用來(lái)保存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ù)加進(jìn)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為零,說(shuō)明沒(méi)有元素,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為零,說(shuō)明沒(méi)有元素,return 0
if val == 0 {
return 0
}
// Pop()方法刪除了val,這里加上
this.stackOut = append(this.stackOut, val)
return val
}
func (this *MyQueue) Empty() bool {
// 兩個(gè)棧都為空,說(shuō)明為空,否則不為空
return len(this.stackOut) == 0 && len(this.stackIn) == 0
}代碼可以直接拿到力扣上運(yùn)行。我已經(jīng)將細(xì)節(jié)全部用注釋解釋了,如果不懂可以私信博主。
四、用隊(duì)列實(shí)現(xiàn)棧
4.1 理論
隊(duì)列模擬棧,其實(shí)一個(gè)隊(duì)列就夠了,那么我們先說(shuō)一說(shuō)兩個(gè)隊(duì)列來(lái)實(shí)現(xiàn)棧的思路。
隊(duì)列是先進(jìn)先出的規(guī)則,把一個(gè)隊(duì)列中的數(shù)據(jù)導(dǎo)入另一個(gè)隊(duì)列中,數(shù)據(jù)的順序并沒(méi)有變,并沒(méi)有變成先進(jìn)后出的順序。
所以用棧實(shí)現(xiàn)隊(duì)列, 和用隊(duì)列實(shí)現(xiàn)棧的思路還是不一樣的,這取決于這兩個(gè)數(shù)據(jù)結(jié)構(gòu)的性質(zhì)。
但是依然還是要用兩個(gè)隊(duì)列來(lái)模擬棧,只不過(guò)沒(méi)有輸入和輸出的關(guān)系,而是另一個(gè)隊(duì)列完全用又來(lái)備份的!
如下面動(dòng)畫(huà)所示,用兩個(gè)隊(duì)列que1和que2實(shí)現(xiàn)隊(duì)列的功能,que2其實(shí)完全就是一個(gè)備份的作用,把que1最后面的元素以外的元素都備份到que2,然后彈出最后面的元素,再把其他元素從que2導(dǎo)回que1。
模擬的隊(duì)列執(zhí)行語(yǔ)句如下:
queue.push(1); queue.push(2); queue.pop(); // 注意彈出的操作 queue.push(3); queue.push(4); queue.pop(); // 注意彈出的操作 queue.pop(); queue.pop(); queue.empty();

4.2 算法題
接下來(lái)看一下LeetCode原題

請(qǐng)你僅使用兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)后入先出(LIFO)的棧,并支持普通棧的全部四種操作(push、top、pop 和 empty)。
實(shí)現(xiàn) MyStack 類:
void push(int x) 將元素 x 壓入棧頂。 int pop() 移除并返回棧頂元素。 int top() 返回棧頂元素。 boolean empty() 如果棧是空的,返回 true ;否則,返回 false 。
注意:
你只能使用隊(duì)列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 這些操作。 你所使用的語(yǔ)言也許不支持隊(duì)列。 你可以使用 list (列表)或者 deque(雙端隊(duì)列)來(lái)模擬一個(gè)隊(duì)列 , 只要是標(biāo)準(zhǔn)的隊(duì)列操作即可。
4.3 思路
用兩個(gè)隊(duì)列que1和que2實(shí)現(xiàn)隊(duì)列的功能,que2其實(shí)完全就是一個(gè)備份的作用,把que1最后面的元素以外的元素都備份到que2,然后彈出最后面的元素,再把其他元素從que2導(dǎo)回que1。
4.4 使用兩個(gè)隊(duì)列實(shí)現(xiàn)
type MyStack struct {
//創(chuàng)建兩個(gè)隊(duì)列
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中,再將兩個(gè)隊(duì)列進(jìn)行交換
this.Move()
}
func (this *MyStack) Move(){
if len(this.queue1) == 0{
//交換,queue1置為queue2,queue2置為空
this.queue1,this.queue2 = this.queue2,this.queue1
}else{
//queue1元素從頭開(kāi)始一個(gè)一個(gè)追加到queue2中
this.queue2 = append(this.queue2,this.queue1[0])
this.queue1 = this.queue1[1:] //去除第一個(gè)元素
this.Move() //重復(fù)
}
}
func (this *MyStack) Pop() int {
val := this.queue1[0]
this.queue1 = this.queue1[1:] //去除第一個(gè)元素
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)化
其實(shí)這道題目就是用一個(gè)隊(duì)列就夠了。
一個(gè)隊(duì)列在模擬棧彈出元素的時(shí)候只要將隊(duì)列頭部的元素(除了最后一個(gè)元素外) 重新添加到隊(duì)列尾部,此時(shí)在去彈出元素就是棧的順序了。
4.6 使用一個(gè)隊(duì)列實(shí)現(xiàn)
type MyStack struct {
queue []int//創(chuàng)建一個(gè)隊(duì)列
}
/** 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//判斷長(zhǎng)度
for n!=0{ //除了最后一個(gè),其余的都重新添加到隊(duì)列里
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ù),彈出來(lái)的元素重新添加
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
}以上就是Go語(yǔ)言實(shí)現(xiàn)棧與隊(duì)列基本操作學(xué)家的詳細(xì)內(nèi)容,更多關(guān)于Go語(yǔ)言棧 隊(duì)列的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang算法之田忌賽馬問(wèn)題實(shí)現(xiàn)方法分析
這篇文章主要介紹了Golang算法之田忌賽馬問(wèn)題實(shí)現(xiàn)方法,結(jié)合具體實(shí)例形式分析了基于Go語(yǔ)言的田忌賽馬問(wèn)題原理與算法實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-02-02
加速開(kāi)發(fā):使用Go語(yǔ)言和Gin框架構(gòu)建Web項(xiàng)目的利器
Go語(yǔ)言和Gin框架是構(gòu)建高性能Web項(xiàng)目的利器,Go語(yǔ)言的簡(jiǎn)潔性和并發(fā)性,以及Gin框架的輕量級(jí)和快速路由能力,使開(kāi)發(fā)者能夠快速構(gòu)建可靠的Web應(yīng)用程序,需要的朋友可以參考下2023-09-09
go語(yǔ)言通過(guò)結(jié)構(gòu)體生成json示例解析
這篇文章主要為大家介紹了go語(yǔ)言通過(guò)結(jié)構(gòu)體生成json示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
go?module化?import?調(diào)用本地模塊?tidy的方法
這篇文章主要介紹了go?module化?import?調(diào)用本地模塊?tidy的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09
Go項(xiàng)目在GoLand中導(dǎo)入依賴標(biāo)紅問(wèn)題的解決方案
這篇文章主要介紹了Go項(xiàng)目在GoLand中導(dǎo)入依賴標(biāo)紅問(wèn)題的解決方案,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-06-06
Gin 框架快速創(chuàng)建靜態(tài)文件下載Web服務(wù)
本文主要介紹了Gin 框架快速創(chuàng)建靜態(tài)文件下載Web服務(wù),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
Go語(yǔ)言學(xué)習(xí)之接口類型(interface)詳解
接口是用來(lái)定義行為的類型,定義的行為不由接口直接實(shí)現(xiàn),而由通過(guò)方法由定義的類型實(shí)現(xiàn),本文就來(lái)和大家詳細(xì)講講Go語(yǔ)言中接口的使用吧2023-03-03
詳解如何在Golang中監(jiān)聽(tīng)多個(gè)channel
這篇文章主要為大家詳細(xì)介紹了如何在Golang中實(shí)現(xiàn)監(jiān)聽(tīng)多個(gè)channel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
go語(yǔ)言通過(guò)反射獲取和設(shè)置結(jié)構(gòu)體字段值的方法
這篇文章主要介紹了go語(yǔ)言通過(guò)反射獲取和設(shè)置結(jié)構(gòu)體字段值的方法,實(shí)例分析了Go語(yǔ)言反射的使用技巧,需要的朋友可以參考下2015-03-03

