总结
本项目开源:https://gitee.com/liwenhao12/alg
链表插入的注意事项
- 插入分为三类 插头 插尾 插中间
- 插头注意换头
- 在单链表中插尾和插中间的逻辑一致
- 插中间需要注意顺序问题,先链接后一个节点,在链接前一个节点。
链表删除的注意事项
- 删除同样分为删头 删尾 删中间
- 删头同样注意换头
- 在单链表中注意删尾和删中间逻辑一致
双链表中的注意事项
插入
- 分为三类 插头 插尾 插中间
- 插头和插尾需要换头和换尾
- 插中间一样遵循 先链接后一个节点,再链接前一个节点
删除
- 分为三类 删头 删尾 删中间
- 链表长度 0,1,2的分类
- 删头 删尾 同样注意换头换尾,但是需要注意删除是链表的个数,如果为1个,删头和删尾的逻辑都是一样,头指针和尾指针置空
- 删中间 链接顺序没有要求,因为curNode的next始终指向他的下一个节点,curNode的prev指针始终指向他的上一个节点。无论怎么链接都不会改变。
部分代码
- 单链表的增删
// InsertNode 链表的插入 头插 尾插 根据位置插
func (l *LinkedList) InsertNode(data int, position int) error {
//创建新节点
newNode := &Node{Data: data}
//判断边界条件
size := l.GetLength()
//这里size + 1的原因 支持尾插,也就是插入的位置在最后的后一个,< 1的原因是,以1开头
if position > size+1 || position < 1 {
return fmt.Errorf("插入失败: 边界错误 %d", position)
}
//判断链表是否为空
if l.Head == nil {
l.Head = newNode //链表为空,插入的节点默认为头节点
return nil
}
//判断是头插 尾插 中间插
if position == 1 {
newNode.Next = l.Head
l.Head = newNode
return nil
}
//遍历到目标位置的前一个位置
pNode := l.Head
for cur := 1; cur < position-1; cur++ {
pNode = pNode.Next
}
newNode.Next = pNode.Next
pNode.Next = newNode
return nil
}
// DeleteNode 链表的删除 删头 删尾 删中间
func (l *LinkedList) DeleteNode(position int) error {
//判断position的边界
size := l.GetLength()
if position > size || position < 1 {
return fmt.Errorf("删除失败:%d 不在范围内", position)
}
//判断链表是否为空
if l.Head == nil {
return fmt.Errorf("删除失败:链表为空")
}
//判断是头删 尾删 中间删
if position == 1 {
l.Head = l.Head.Next
return nil
}
//定位
pNode := l.Head
for cur := 1; cur < position-1; cur++ {
pNode = pNode.Next
}
pNode.Next = pNode.Next.Next
return nil
}
- 双链表的增删
// InsertFirst 头插
func (l *DoubleLinkedList) InsertFirst(data int) {
newNode := &DoubleNode{Data: data}
//判断链表是否为空
if l.isEmpty() {
l.Head = newNode
l.Tail = newNode
return
}
//链接
newNode.Next = l.Head
l.Head.Prev = newNode
//换头
l.Head = newNode
}
// InsertLast 尾插
func (l *DoubleLinkedList) InsertLast(data int) {
newNode := &DoubleNode{Data: data}
//判断链表是否为空
if l.isEmpty() {
l.Head = newNode
l.Tail = newNode
return
}
//链接
l.Tail.Next = newNode
newNode.Prev = l.Tail
//换尾
l.Tail = newNode
}
// Append 插入指定值的后面
func (l *DoubleLinkedList) Append(data int, key int) {
newNode := &DoubleNode{Data: data}
curNode := l.Head
//判断链表是否为空
if l.isEmpty() {
l.Head = newNode
l.Tail = newNode
return
}
//定位
for curNode != nil && curNode.Data != key {
curNode = curNode.Next
}
// key不存在 或者匹配到的节点已经是最后一个,直接尾插
if curNode == nil || curNode == l.Tail {
l.Tail.Next = newNode
newNode.Prev = l.Tail
l.Tail = newNode
return
}
//先链接后一个节点,再链接当前节点
newNode.Next = curNode.Next
curNode.Next.Prev = newNode
curNode.Next = newNode
newNode.Prev = curNode
}
// DeleteFirst 删头
func (l *DoubleLinkedList) DeleteFirst() error {
//判断链表是否为空
if l.isEmpty() {
return fmt.Errorf("删除失败,链表为空")
}
//如果只有一个元素
if l.Head == l.Tail {
l.Head = nil
l.Tail = nil
return nil
}
l.Head.Next.Prev = nil
l.Head = l.Head.Next
return nil
}
// DeleteLast 删尾
func (l *DoubleLinkedList) DeleteLast() error {
//判断链表是否为空
if l.isEmpty() {
return fmt.Errorf("删除失败,链表为空")
}
//如果只有一个元素
if l.Head == l.Tail {
l.Head = nil
l.Tail = nil
return nil
}
l.Tail.Prev.Next = nil
l.Tail = l.Tail.Prev
return nil
}
// DeleteKey 删除指定key的元素
func (l *DoubleLinkedList) DeleteKey(key int) error {
//判断链表是否为空
if l.isEmpty() {
return fmt.Errorf("删除失败,链表为空")
}
//定位
curNode := l.Head
for curNode != nil && curNode.Data != key {
curNode = curNode.Next
}
//没有定位到
if curNode == nil {
return fmt.Errorf("删除失败,链表中没有%d", key)
}
//定位到头
if curNode == l.Head {
return l.DeleteFirst()
}
//定位到尾
if curNode == l.Tail {
return l.DeleteLast()
}
curNode.Prev.Next = curNode.Next
curNode.Next.Prev = curNode.Prev
return nil
}