使用Golang實現雙向環形鏈表

來源:互聯網
上載者:User
**什麼是雙向環形鏈表?**`雙向環形鏈表`屬於線性表的其中一種結構,也被稱為雙向迴圈鏈表,以下是根據個人的理解使用Golang編寫的一個`環形雙向鏈表`,通過這種資料結構能夠能夠實現大量資料記錄在記憶體中的CURD而不需要通過資料庫。雙向環形鏈表也可以解決約瑟夫問題(但一般選用單向環形鏈表解決)**實現步驟1:定義雙向鏈表結構體**```go//雙向環形鏈表資料結構package pkgimport ("fmt")//雙向環形鏈表結構體type CircleLink struct {Id int //節點索引Data interface{} //data域,用於維護資料prev *CircleLink //prev域next *CircleLink //next域}//初始化前端節點元素,前端節點的id初始化為1,擷取到的結構體執行個體就作為前端節點存在func InitHeadNode(data interface{}) *CircleLink{return &CircleLink{Id:1,Data:data,}}```**實現步驟2:實現鏈表一些基本的判斷和末尾元素擷取的相關方法**```go//重設頭元素func (head *CircleLink) ResetHeadNode(data interface{}){if head.Id == 0 {head.Id = 1}head.Data = data}//判斷當前頭部是否為空白func (head *CircleLink) IsHeadEmpty() bool{return head.next == nil && head.prev == nil}//判斷當前是否為空白鏈表func (head *CircleLink) IsEmptyLink() bool {return head.Data == nil && head.next == nil && head.prev==nil && head.Id == 0}//或者末尾元素func (head *CircleLink) GetLastNode() *CircleLink{//如果只有一個頭元素則直接返回currentNode := headif !head.IsHeadEmpty() {//如果不為空白,則遍曆到最後一個元素for{if currentNode.next == head { //表示找到了末尾break}currentNode = currentNode.next //讓當前節點前進}}return currentNode}```**實現步驟3:實現對鏈表的添加操作**```go//從前端節點按順序插入雙向鏈表節點func (head *CircleLink) AddNode(newNode *CircleLink){//如果只有一個元素則初始化next和prev指標形成雙向環形鏈表if head.IsHeadEmpty() {//前端節點則讓next指標指向newNodehead.next = newNode//前端節點則讓prev指向nilhead.prev = newNode//讓newNode的prev和next指標都指向headnewNode.prev = headnewNode.next = head return;}//如果環形已經形成則按照順序添加節點,把當前節點指向頭部currentNode := head//表示是否應該進行中間插入flag := false //預設表示添加都最後for{if currentNode == head.prev {//已經是最後一個元素則表示添加都末尾break}else if currentNode.next.Id > newNode.Id {//fmt.Println("如果當前節點的next大於newNode.id則找到了添加的位置")//如果當前節點的next大於newNode.id則找到了添加的位置flag = truebreak}else if currentNode.next.Id == newNode.Id {fmt.Println("error:id already exists")return}//當前節點繼續前進currentNode = currentNode.next }if flag {//如果在中間添加newNode.next = currentNode.next newNode.prev = currentNodecurrentNode.next.prev = newNodecurrentNode.next = newNode}else{//在末尾添加newNode.prev = currentNodenewNode.next = currentNode.next currentNode.next = newNodehead.prev = newNode}}```**實現步驟4:實現對鏈表的按照id找到節點**```go//按照id找到節點func (head *CircleLink) FindNodeById( id int ) (*CircleLink,bool){if head.IsHeadEmpty() && head.Id == id {return head,true}else if head.IsHeadEmpty() && head.Id != id{return &CircleLink{},false}//頭部非空則遍曆尋找currentNode := headflag := falsefor{if currentNode.Id == id{flag = truebreak}if currentNode == head.prev{ //找到最後,表示不存在break }currentNode = currentNode.next}if !flag{return &CircleLink{},false}return currentNode,true}```**實現步驟4:實現對鏈表刪除指定id的節點**```go//刪除指定id的節點func (head *CircleLink) DeleteNodeById( id int ) bool {if head.IsEmptyLink(){fmt.Println("無法刪除空鏈表")return false;}node,boolean := head.FindNodeById(id)if boolean{//表示刪除的頭部元素if node == head {//處理只有一個頭部元素的情況,則把頭元素進行id初始化設定並把Data設定為nilif head.IsHeadEmpty(){head.prev = nilhead.next = nilhead.Data = nilhead.Id = 0return true }//如果只有前端節點和末尾節點兩個元素if head.next.next == head{nextNode := head.nexthead.Id = nextNode.Id head.Data = nextNode.Datahead.prev = nil head.next = nilreturn true }//如果大於2個節點則移動下一個節點作為前端節點nextNodeTmp := head.nexthead.Data = nextNodeTmp.Datahead.Id = nextNodeTmp.Id head.next = nextNodeTmp.nextnextNodeTmp.next.prev = headreturn true }//刪除的元素是末尾元素if node == head.GetLastNode(){//如果只有兩個元素//fmt.Println("最後節點:",node.Id,node.Data,node.next.Data,node.prev.Data)if node.prev == head && node.next == head {//如果只有兩個元素直接在head節點中中斷連線head.prev = nil head.next = nil return true}head.prev = node.prev node.prev.next = headreturn true }//刪除的元素並非前端節點也並非末尾節點node.prev.next = node.nextnode.next.prev = node.prevreturn true}else{fmt.Println("找不到要刪除的節點")}return boolean }```**實現步驟5:根據id修改相關data資料**```go//根據id修改相關data資料func (head *CircleLink) ModifyById(id int,data interface{}) bool {node,boolean := head.FindNodeById(id)if boolean {node.Data = data }else{fmt.Println("找不到要修改的id")}return boolean }```**實現步驟6:遍曆鏈表**```go//遍曆整個環形鏈表func (head *CircleLink) FetchAll(){if head.IsEmptyLink(){fmt.Println("無法遍曆空鏈表")return;}if head.IsHeadEmpty(){//fmt.Println(head.Id,head.Data)fmt.Println( "[", head.Id, head.Data , "next:",head.next, " perv:", head.prev, "]" )return}currentNode := headfor{fmt.Println( "[", currentNode.Id, currentNode.Data , "next:",currentNode.next.Data, " perv:", currentNode.prev.Data, "]" )if currentNode == head.prev{break}currentNode = currentNode.next}}```**最後來一波測試**```go//約瑟夫問題package mainimport ("Josephus/instance""Josephus/pkg")func main(){linkNode := pkg.InitHeadNode( instance.NewPerson("張三") )node3 := &pkg.CircleLink{Id:3,Data:instance.NewPerson("李四"),}node2 := &pkg.CircleLink{Id:2,Data:instance.NewPerson("王五"),}node5 := &pkg.CircleLink{Id:5,Data:instance.NewPerson("趙六"),}node4 := &pkg.CircleLink{Id:4,Data:instance.NewPerson("劉七"),}linkNode.AddNode(node3)linkNode.AddNode(node2)linkNode.AddNode(node5)linkNode.AddNode(node4)linkNode.DeleteNodeById(4)linkNode.FetchAll()updateData := instance.NewPerson("包青天")linkNode.ModifyById(3,updateData)linkNode.FetchAll()}```**以下為完整代碼**```go//雙向環形鏈表資料結構package pkgimport ("fmt")//雙向環形鏈表結構體type CircleLink struct {Id int //節點索引Data interface{} //data域,用於維護資料prev *CircleLink //prev域next *CircleLink //next域}//初始化前端節點元素,前端節點的id初始化為1,擷取到的結構體執行個體就作為前端節點存在func InitHeadNode(data interface{}) *CircleLink{return &CircleLink{Id:1,Data:data,}}//重設頭元素func (head *CircleLink) ResetHeadNode(data interface{}){if head.Id == 0 {head.Id = 1}head.Data = data}//判斷當前頭部是否為空白func (head *CircleLink) IsHeadEmpty() bool{return head.next == nil && head.prev == nil}//判斷當前是否為空白鏈表func (head *CircleLink) IsEmptyLink() bool {return head.Data == nil && head.next == nil && head.prev==nil && head.Id == 0}//或者末尾元素func (head *CircleLink) GetLastNode() *CircleLink{//如果只有一個頭元素則直接返回currentNode := headif !head.IsHeadEmpty() {//如果不為空白,則遍曆到最後一個元素for{if currentNode.next == head { //表示找到了末尾break}currentNode = currentNode.next //讓當前節點前進}}return currentNode}//從前端節點按順序插入雙向鏈表節點func (head *CircleLink) AddNode(newNode *CircleLink){//如果只有一個元素則初始化next和prev指標形成雙向環形鏈表if head.IsHeadEmpty() {//前端節點則讓next指標指向newNodehead.next = newNode//前端節點則讓prev指向nilhead.prev = newNode//讓newNode的prev和next指標都指向headnewNode.prev = headnewNode.next = head return;}//如果環形已經形成則按照順序添加節點,把當前節點指向頭部currentNode := head//表示是否應該進行中間插入flag := false //預設表示添加都最後for{if currentNode == head.prev {//已經是最後一個元素則表示添加都末尾break}else if currentNode.next.Id > newNode.Id {//fmt.Println("如果當前節點的next大於newNode.id則找到了添加的位置")//如果當前節點的next大於newNode.id則找到了添加的位置flag = truebreak}else if currentNode.next.Id == newNode.Id {fmt.Println("error:id already exists")return}//當前節點繼續前進currentNode = currentNode.next }if flag {//如果在中間添加newNode.next = currentNode.next newNode.prev = currentNodecurrentNode.next.prev = newNodecurrentNode.next = newNode}else{//在末尾添加newNode.prev = currentNodenewNode.next = currentNode.next currentNode.next = newNodehead.prev = newNode}}//按照id找到節點func (head *CircleLink) FindNodeById( id int ) (*CircleLink,bool){if head.IsHeadEmpty() && head.Id == id {return head,true}else if head.IsHeadEmpty() && head.Id != id{return &CircleLink{},false}//頭部非空則遍曆尋找currentNode := headflag := falsefor{if currentNode.Id == id{flag = truebreak}if currentNode == head.prev{ //找到最後,表示不存在break }currentNode = currentNode.next}if !flag{return &CircleLink{},false}return currentNode,true}//刪除指定id的節點func (head *CircleLink) DeleteNodeById( id int ) bool {if head.IsEmptyLink(){fmt.Println("無法刪除空鏈表")return false;}node,boolean := head.FindNodeById(id)if boolean{//表示刪除的頭部元素if node == head {//處理只有一個頭部元素的情況,則把頭元素進行id初始化設定並把Data設定為nilif head.IsHeadEmpty(){head.prev = nilhead.next = nilhead.Data = nilhead.Id = 0return true }//如果只有前端節點和末尾節點兩個元素if head.next.next == head{nextNode := head.nexthead.Id = nextNode.Id head.Data = nextNode.Datahead.prev = nil head.next = nilreturn true }//如果大於2個節點則移動下一個節點作為前端節點nextNodeTmp := head.nexthead.Data = nextNodeTmp.Datahead.Id = nextNodeTmp.Id head.next = nextNodeTmp.nextnextNodeTmp.next.prev = headreturn true }//刪除的元素是末尾元素if node == head.GetLastNode(){//如果只有兩個元素//fmt.Println("最後節點:",node.Id,node.Data,node.next.Data,node.prev.Data)if node.prev == head && node.next == head {//如果只有兩個元素直接在head節點中中斷連線head.prev = nil head.next = nil return true}head.prev = node.prev node.prev.next = headreturn true }//刪除的元素並非前端節點也並非末尾節點node.prev.next = node.nextnode.next.prev = node.prevreturn true}else{fmt.Println("找不到要刪除的節點")}return boolean }//根據id修改相關data資料func (head *CircleLink) ModifyById(id int,data interface{}) bool {node,boolean := head.FindNodeById(id)if boolean {node.Data = data }else{fmt.Println("找不到要修改的id")}return boolean }//遍曆整個環形鏈表func (head *CircleLink) FetchAll(){if head.IsEmptyLink(){fmt.Println("無法遍曆空鏈表")return;}if head.IsHeadEmpty(){//fmt.Println(head.Id,head.Data)fmt.Println( "[", head.Id, head.Data , "next:",head.next, " perv:", head.prev, "]" )return}currentNode := headfor{fmt.Println( "[", currentNode.Id, currentNode.Data , "next:",currentNode.next.Data, " perv:", currentNode.prev.Data, "]" )if currentNode == head.prev{break}currentNode = currentNode.next}}```117 次點擊  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.