下面这副图是我们单链表运煤车队。
每节运煤车就是单链表里的元素,每节车厢里的煤炭就是元素中保存的数据。前后车通过锁链相连,作为单链表运煤车,从1号车厢开始,每节车厢都知道后面拉着哪一节车厢,却不知道前面是哪节车厢拉的自己。第一节车厢没有任何车厢拉它,我们就叫它车头,第五节车厢后面拉其他车厢,我们称为车尾。
作为单链表它最大的特点就是能随意增加车队的长度,也能随意减少车队的长度。这是比数组公交车最大的优点。
二、Go语言实现讲解
1、节点
每节车厢都由车体、绳索和煤炭构成。在Go语言中表示这种自定义组合体的类型就是结构,当然为了通用性,我们这里要把车厢转换成节点也就是元素,煤炭转换成数据,绳索转换成指针。 type Node struct { data Object next *Node }
用张图来描述这种对应关系。
这里结构体Node表示车厢,data表示煤炭用Object类型,next是牵着下节车厢的绳索,用指针表示。
对于车厢来说,除了放煤炭外,还能放瓜果、衣物、饭菜等等,所以这里data的类型必须通用,当然Go里是没有Java里的Object类型的,所以我们就自己定义了一个。
type Object interface{}2、链表
光有车厢还不够,我们还要描述车厢组成的车队。每个单链表车队都有车头、车尾和车厢数量,我们同样以结构来表现。
type List struct {
size uint64 // 车辆数量
head Node // 车头
tail Node // 车尾
}
3、方法
(1)初始化
第一步就是组装单链表车队,这就是初始化。不过开始的时候车队是个空壳,一个车厢没有。
func (list *List) Init() { (*list).size = 0 // 此时链表是空的 (*list).head = nil // 没有车头 (*list).tail = nil // 没有车尾 }(2)添加元素
当前的单链表是空的,所以我们要向里面添加元素。
func (list *List) Append(node *Node) { (*list).head = node // 这是单链表的第一个元素,也是链表的头部 (*list).tail = node // 同时是单链表的尾部 (*list).size = 1 // 单链表有了第一个元素 }现在单链表有了第一个元素,我还想再添加一个元素,当然是添加到单链表尾部。
func (list *List) Append(node *Node) { if (*list).size == 0 { // 无元素的时候添加 (*list).head = node // 这是单链表的第一个元素,也是链表的头部 (*list).tail = node // 同时是单链表的尾部 (*list).size = 1 // 单链表有了第一个元素 } else { // 有元素了再添加 oldTail := (*list).tail (*oldTail).next = node // node放到尾部元素后面 (*list).tail = node // node成为新的尾部 (*list).size++ // 元素数量增加 } }分析上面的代码存在3处疑点,元芳你怎么看?属下认为
第一,node如果为空,则添加无任何意义;
第二,代码中存在重复的地方;
这第三么,卑职如何才能知道新增结果?
下面大卫哥顺着元芳的思路改进下代码。
(3)插入元素
一天领导让大卫哥把他小舅子安排到第一个,于是大卫哥为了拍好领导马屁。绞尽脑汁弄了一个方法。
**func (list List) Insert(node Node) bool {
if node == nil {
return false
}
}**
来托关系插队的人越来越多,领导的关系户不能动,只能插后面人的队了。于是大卫哥又修改了代码,增加了位置参数。
func (list *List) Insert(i uint,node *Node) bool { // 空的节点、索引超出范围和空链表都无法做插入操作 if node == nil || i > (*list).size || (*list).size == 0 { return false } if i == 0 { // 直接排第一,也就领导小舅子才可以 (*node).next = (*list).head (*list).head = node } else { // 找到前一个元素 preItem := (*list).head for j := 1 ; j < i; j++ { // 数前面i个元素 preItem = (*preItem).next } // 原来元素放到新元素后面,新元素放到前一个元素后面 (*node).next = (*preItem).next (*preItem).next = preItem } (*list).size++ return true }(4)删除元素