算法通关村第一关——链表青铜挑战笔记

总结

本项目开源:https://gitee.com/liwenhao12/alg

链表插入的注意事项

  1. 插入分为三类 插头 插尾 插中间
  2. 插头注意换头
  3. 在单链表中插尾和插中间的逻辑一致
  4. 插中间需要注意顺序问题,先链接后一个节点,在链接前一个节点。

链表删除的注意事项

  1. 删除同样分为删头 删尾 删中间
  2. 删头同样注意换头
  3. 在单链表中注意删尾和删中间逻辑一致

双链表中的注意事项

插入

  1. 分为三类 插头 插尾 插中间
  2. 插头和插尾需要换头和换尾
  3. 插中间一样遵循 先链接后一个节点,再链接前一个节点

删除

  1. 分为三类 删头 删尾 删中间
  2. 链表长度 0,1,2的分类
  3. 删头 删尾 同样注意换头换尾,但是需要注意删除是链表的个数,如果为1个,删头和删尾的逻辑都是一样,头指针和尾指针置空
  4. 删中间 链接顺序没有要求,因为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
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值