Golang 官方实现的双向链表

概述

在go语言中,官方已经替我们实现了一个双向链表,可以用来存储、查找我们的数据,数据类型支持任意类型,其中节点的定义如下:

// Element is an element of a linked list.
type Element struct {
   // Next and previous pointers in the doubly-linked list of elements.
   // To simplify the implementation, internally a list l is implemented
   // as a ring, such that &l.root is both the next element of the last
   // list element (l.Back()) and the previous element of the first list
   // element (l.Front()).
   next, prev *Element

   // The list to which this element belongs.
   list *List

   // The value stored with this element.
   Value interface{}
}

具体对节点的增删改查用法如下

初始化一个双向链表

mylist := list.New()

插入节点

插入链表尾部
PushBack(v interface{}) *Element
插入链表头部
PushFront(v interface{}) *Element
指定位置插入
InsertBefore(v interface{}, mark *Element) *Element

删除节点

Remove(e *Element) interface{}

读取节点

读取头节点
 Front() *Element 
读取末节点
 Back() *Element 

读取整张链表

for e:=mylist.Front();e!=nil;e=e.Next(){
   fmt.Printf("%s->",e.Value)
}

完整测试代码

package main

import (
	"container/list"
	"fmt"
)

func main() {
	mylist := list.New()
	mylist.PushFront("Begin")
	mylist.PushBack("End")
	mylist.InsertBefore("before end",mylist.Back())
	mylist.InsertAfter("after begin",mylist.Front())
	fmt.Println("Head node:",mylist.Front().Value)
	fmt.Println("End node:",mylist.Back().Value)
	for e:=mylist.Front();e!=nil;e=e.Next(){
	   fmt.Printf("%s->",e.Value)
	}

	//Modify the node value
	mylist.Front().Value="New Begin"
	fmt.Println("\nAfter update the head node")
	for e:=mylist.Front();e!=nil;e=e.Next(){
		fmt.Printf("%s->",e.Value)
	}

	//Delete node
	mylist.Remove(mylist.Front())
	fmt.Println("\nAfter remove the head node")
	for e:=mylist.Front();e!=nil;e=e.Next(){
		fmt.Printf("%s->",e.Value)
	}
}

测试结果

Head node: Begin
End node: End
Begin->after begin->before end->End->
After update the head node
New Begin->after begin->before end->End->
After remove the head node
after begin->before end->End->

高并发

在高并发的goroutine中,双向链表同slice,map一样,无法保证其数据安全性,在插入节点的过程中,会丢失部分节点数据。

如以下代码

func main(){
   mylist := list.New()
   wg := &sync.WaitGroup{}
   wg.Add(10000)
   for i:=0;i<10000;i++{
      go func(i int){
         defer wg.Done()
         mylist.PushBack(i)
      }(i)
   }
   wg.Wait()
   fmt.Println("link list length:",mylist.Len())
}

输出结果

link list length: 9795
解决方案

新建一个结构体,将list.List和sync.Mutex匿名嵌入进去,形成一个有锁属性的list结构体

结构体声明如下:

type listLock struct {
   list.List
   sync.Mutex
}

测试

func main(){
   mylist := listLock{}
   wg := &sync.WaitGroup{}
   wg.Add(1000)
   for i:=0;i<1000;i++{
      go func(i int){
         defer wg.Done()
          //对链表进行加锁,此时其他goroutine需等待解锁后方可进行PushBack操作
         mylist.Lock()
         mylist.PushBack(i)
          //对链表解锁
         mylist.Unlock()
      }(i)
   }
   wg.Wait()
   fmt.Println("link list length:",mylist.Len())
}

此时的结果方为正确的结果

link list length: 1000
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值