反转
假设链表中元素为 1->2->3->4->5->6->7
我们假设有head:指向旧链表头节点,prev:指向新链表的头节点,next:指向旧链表的头节点的下一个节点 三个变量。
反转链表的步骤:
next = head.Next
,先记录旧链表的head,和旧链表头部的下一个节点nexthead.Next = prev
,让head.Next 指向prev,由于prev创建时是空,所以在第一轮操作时head.Next指向了空,该操作的目的是让prev这个新链表挂在head的后边prev = head
,让prev 指向 head。该操作的目的是让prev 指向 head,从而完成链表的接替。head = next
,让head指向next,head 节点指向了head后的节点- 重复以上操作,直到head为空
var prev, next *Node
for head != nil {
next = head.Next // 记录下一个节点
head.Next = prev // 将当前节点 添加到prev 头部
prev = head // prev 指向头部
head = next // 当前节点指向下一个节点
}
return prev
删除
假设链表中元素为 1->2->3->4->5->6->7
假设删除元素1。因为元素1位于链表头部,直接删了他,链表头之后的节点就失去引用了。所以,要进行换头操作:
for head != nil {
if head.Value != val {
break
}
head = head.Next
}
确保链表头是一个不被删除的元素,才能查找链表后续是否还有需要被删除的元素。
在链表的后续节点中检查并删除值
prev, cur := head, head
for cur != nil {
if cur.Value == val {
prev.Next = cur.Next
} else {
prev = cur
}
cur = cur.Next
}
分别记录上一个节点和当前节点,在第一轮时,当前节点和上一个节点一致,所以这一轮只将当前节点指向其next节点的操作是有效的。
如果当前节点的值等于要删除的值,则将上一个节点的next指针赋值当前节点的next指针。也就是让当前节点不再被引用。会在适当的时机被GC掉。
删除头节点,需要重新返回新的链表
完整源码
package main
import (
"fmt"
)
type Node struct {
Value int
Next *Node
}
func NewList(v ...int) *Node {
if len(v) <= 0 {
return nil
}
head := &Node{Value: v[0]}
p := head
for i := 1; i < len(v); i++ {
p.Next = &Node{Value: v[i]}
p = p.Next
}
return head
}
func (n *Node) Print() {
p := n
for p != nil {
fmt.Print(p.Value, " -> ")
p = p.Next
}
fmt.Println()
}
func ReverseLinkedList(head *Node) *Node {
var prev, next *Node
for head != nil {
next = head.Next // 记录下一个节点
head.Next = prev // 将当前节点 添加到prev 头部
prev = head // prev 指向头部
head = next // 当前节点指向下一个节点
}
return prev
}
func RemoveNodeValue(head *Node, val int) *Node {
// 先检查头节点
for head != nil {
if head.Value != val {
break
}
head = head.Next
}
prev, cur := head, head
for cur != nil {
if cur.Value == val {
prev.Next = cur.Next
} else {
prev = cur
}
cur = cur.Next
}
return head
}
测试
func main() {
list := NewList(1, 2, 3, 4, 5, 6, 7)
list.Print()
linkedList := ReverseLinkedList(list)
linkedList.Print()
linkedList = RemoveNodeValue(linkedList, 2)
linkedList.Print()
}