寫在開頭
距離上篇文章已經二十多天了,本來信誓旦旦的說要周更的,果然打臉了,哈哈
由於要看論文,還要兼顧實驗室項目新功能的開發和維護,還有噁心的網課和作業,更糟糕的是我最近迷上了吃雞,就把這事給耽擱了。。。。。。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
爲什麼我們跳過了雙鏈表,直接來講棧呢???
因爲棧的一種實現方式就是單鏈表(另一種是數組,後面我會給出僞代碼),因此我們在講完單鏈表的基礎上可以直接來學習棧。
什麼是棧呢?
棧(stack)又名堆棧,它是一種運算受限的線性表。限定僅在表尾進行插入和刪除操作的線性表。這一端被稱爲棧頂,相對地,把另一端稱爲棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成爲新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰的元素成爲新的棧頂元素。----來自百度百科的描述
上面的描述是不是很晦澀呢?我們應該都見過漢諾塔,就是下圖的樣子(圖片來自百度,侵權的話請聯繫刪除哦),它就是一種很經典的堆棧結構,我們最先放入的圈最後才能取出,最後放入的圈就可以直接取出來,這樣就很容易理解了吧
這樣對堆棧是不是就有了一個很清晰的認識了呢
開始步入正題!
對於go語言我們應該怎麼使用代碼描述一個棧呢?
因爲棧的操作主要就是頻繁的入棧和出棧兩部分,而在單鏈表頭部的添加和刪除節點都是O(1)的複雜度,非常方便,因此,就把棧當作一個只能在頭部進行操作的單鏈表就行了。(這一部分一定要理解)
那麼如果我們用單鏈表實現堆棧,是一種怎樣的結構呢????
我們來初始化一個棧,也就是一個單鏈表
//定義節點
type Node struct {
e interface{}
next *Node
}
//定義棧的結構
type LStack struct {
length int
top *Node
}
//初始化棧
func (s *LStack) InitLStack() *LStack{
return &LStack{
length: 0,
top: nil,
}
}
入棧操作,也就是在單鏈表的頭部插入一個節點
//判斷棧是否爲空
func (s *LStack) IsEmpty() bool{
return s.length == 0
}
//入棧
func (s *LStack) Push(e interface{}) {
node := &Node{
e ,
nil,
}
//如果棧爲空,表示第一次入棧,此時棧頂指向該node
if s.IsEmpty() {
s.top = node
} else {
node.next = s.top
s.top = node
}
s.length++ //棧的長度+1
}
出棧操作,就是刪除單鏈表的頭節點
//出棧,返回棧頂的e元素
func (s *LStack) Pop() interface{}{
if s.IsEmpty() {
return nil
}
//將棧頂的top指向top的下一個元素
curNode := s.top
s.top = curNode.next
s.length--
return curNode.e
}
輸出所有的棧中的元素
func (s *LStack) PrintLStack(){
curNode := s.top
for {
if curNode != nil {
fmt.Println(curNode.e)
curNode = curNode.next
} else {
break
}
}
}
我們來測試一下
func main() {
s := &LStack{}
s.InitLStack()
s.Push(1)
s.Push(2)
s.Push(3)
s.PrintLStack()
fmt.Println("--------------------")
s.Pop()
s.PrintLStack()
}
輸出的結果正確。
其他的功能小夥伴可以自己嘗試一下實現呢,比如查詢某個值是否在棧中,清空棧等等一系列操作。
好了,這次就到這了,不知道下次寫博客會是啥時候呢,希望小夥伴關注一下,給我點動力,哈哈
如果哪裏有問題歡迎評論區指出來,我立馬改正,一起進步嘛