1. 什么是双向链表


(引用)

和单链表比较,双向链表的元素不但知道自己的下线,还知道自己的上线(越来越像传销组织了)。小煤车开起来,图里面可以看出,每个车厢除了一个指向后面车厢的箭头外,还有一个指向前面车厢的箭头(车头、车尾除外)。车头只有指向后面车厢的箭头,车尾只有指向前面车厢的箭头。

2. 和单向链表相比的优势

1. 插入删除不需要移动元素外,可以原地插入删除

2. 可以双向遍历



插入数据到中间



删除中间数据



3、双向链表与 Go 的对应结构

1. 节点分析



我们先把车厢分解开来。每节车厢都由煤炭、车体、拉前车厢绳索、拉后车厢绳索这 4 部分组成。车体是我们的运输工具,在 Go 语言里我们用结构提 DNode 表示;煤炭代表运的货物,用 data 变量表示;拉前车厢绳索和拉后车厢绳索我们分别用指针 prev 和 next 表示。这样一节车厢,用 Go 语言描述如下:

2、双向链表



一个运煤车队就是一个双向链表。车队要有车头、车厢、车尾,作为车队的负责人还得知道车队有多长。在 Go 语言里,车队用结构体 DList 表示,车头用 head 变量表示,车位用 tail 变量表示,车队长度就用 size 来表示,把这些表示合起来:

通过找到其中一个节点,就可以通过 prev 或 next 指向得到指向的数据。

4. Go 自定义实现链表



1. 初始化 Init

双向链表的初始化,可以理解成大卫哥准备买一个车队准备运煤。第一步,得获得国家有关部门的批准,有了批准大卫哥就可以买车厢运煤了。但是,批准下来的时候,大卫哥的车队啥都没有,没有车头、车尾,连一节车厢也没有。Go 语言代码实现:

通过自己实现链表,来更深入了解链表的结构后, 我们使用 go 的 container/list 库实现。

5.Go 库 container/list 实现链表操作

关于库的成员函数,我就不一一列举了, 看一看文档很详细,也很简单。

下面直接上案例:

6. slice 和 list 的性能比较

1. 创建、 添加元素的比较

简单的测试下,如果频繁的插入和删除建议用 list, 频繁的遍历查询选 slice。

由于 container/list 不是并发安全的,所以需要自己手动添加一层并发的包装。