双向链表(Doubly Linked List)是一种链表数据结构,其中每个节点不仅包含指向下一个节点的指针,还包含指向上一个节点的指针。与单向链表不同,双向链表可以在常数时间内从任意节点开始向前向后遍历,因此可以更加灵活的操作链表。
每个节点包含三个部分:
每个双向链表包含两个指针:
为了方便统计链表的长度,我们还可以在双向链表的结构中添加一个计数器,用于记录链表中的节点数量。
插入操作
删除操作
遍历操作
查找操作
反转操作
长度操作
// 双链表节点结构体
type Node struct {
Val int // 节点的值
Prev *Node // 指向前一个节点的指针
Next *Node // 指向下一个节点的指针
}
// 双链表结构体
type DoublyLinkedList struct {
Head *Node // 指向头节点的指针
Tail *Node // 指向尾节点的指针
}
// NewDoublyLinkedList 创建一个双链表
func NewDoublyLinkedList() *DoublyLinkedList {
return &DoublyLinkedList{}
}
// AddNodeAtHead 在链表头部添加节点
func (d *DoublyLinkedList) AddNodeAtHead(val int) {
// 创建节点
node := &Node{Val: val}
// 如果头节点为空
// 则表示当前链表为空
// 将新节点设置为头节点和尾节点
if d.Head == nil {
d.Head = node
d.Tail = node
} else {
// 头节点不为空
// 则将新节点的Next指针指向当前头节点
// 并将当前头节点的Prev指针指向新节点
// 将新节点设置为头节点
node.Next = d.Head
d.Head.Prev = node
d.Head = node
}
}
时间复杂度:O(1)
// AddNodeAtTail 在链表尾部添加节点
func (d *DoublyLinkedList) AddNodeAtTail(val int) {
// 创建节点
node := &Node{Val: val}
// 如果头节点为空
// 则表示当前链表为空
// 将新节点设置为头节点和尾节点
if d.Head == nil {
d.Head = node
d.Tail = node
} else {
// 头节点不为空
// 则将新节点的Prev指针指向当前尾节点
// 并将当前尾节点的Next指针指向新节点
// 将新节点设置为尾节点
node.Prev = d.Tail
d.Tail.Next = node
d.Tail = node
}
}
时间复杂度:O(1)
// AddNodeAtIndex 在指定位置添加节点
func (d *DoublyLinkedList) AddNodeAtIndex(index int, val int) {
// 索引必须大于等于0
if index < 0 {
return
}
// 索引等于0时,表示在头部添加节点
if index == 0 {
d.AddNodeAtHead(val)
return
}
// 创建节点
node := &Node{Val: val}
// 遍历链表找到指定位置
current := d.Head
currentIndex := 0
for current != nil {
if currentIndex == index {
node.Next = current // 将新节点的Next指针指向当前节点
node.Prev = current.Prev // 将新节点的Prev指针指向当前节点的Prev节点
current.Prev.Next = node // 将当前节点的Prev节点的Next指针指向新节点
current.Prev = node // 将当前节点的Prev指针指向新节点
break
}
current = current.Next
currentIndex++
}
}
时间复杂度:O(n)
// DeleteNodeAtHead 删除链表头部的节点
func (d *DoublyLinkedList) DeleteNodeAtHead() {
// 如果头节点为空
// 则表示当前链表为空
// 直接返回
if d.Head == nil {
return
}
// 如果头节点和尾节点相同
// 则表示当前链表只有一个节点
// 将头节点和尾节点都设置为nil
if d.Head == d.Tail {
d.Head = nil
d.Tail = nil
} else {
// 头节点和尾节点不同
// 则将头节点的Next节点的Prev指针设置为nil
// 并将头节点指向头节点的Next节点
d.Head.Next.Prev = nil
d.Head = d.Head.Next
}
}
时间复杂度:O(1)
// DeleteNodeAtTail 删除链表尾部的节点
func (d *DoublyLinkedList) DeleteNodeAtTail() {
// 如果头节点为空
// 则表示当前链表为空
// 直接返回
if d.Head == nil {
return
}
// 如果头节点和尾节点相同
// 则表示当前链表只有一个节点
// 将头节点和尾节点都设置为nil
if d.Head == d.Tail {
d.Head = nil
d.Tail = nil
} else {
// 头节点和尾节点不同
// 则将尾节点的Prev节点的Next指针设置为nil
// 并将尾节点指向尾节点的Prev节点
d.Tail.Prev.Next = nil
d.Tail = d.Tail.Prev
}
}
时间复杂度:O(1)
// DeleteNodeAtIndex 删除指定位置的节点
func (d *DoublyLinkedList) DeleteNodeAtIndex(index int) {
// 索引必须大于等于0
if index < 0 {
return
}
// 索引等于0时,表示删除头节点
if index == 0 {
d.DeleteNodeAtHead()
return
}
// 遍历链表找到指定位置
current := d.Head
currentIndex := 0
for current != nil {
if currentIndex == index {
current.Prev.Next = current.Next // 将当前节点的Prev节点的Next指针指向当前节点的Next节点
current.Next.Prev = current.Prev // 将当前节点的Next节点的Prev指针指向当前节点的Prev节点
break
}
current = current.Next
currentIndex++
}
}
时间复杂度:O(n)
// DeleteNodeByValue 删除指定值节点
func (d *DoublyLinkedList) DeleteNodeByValue(val int) {
// 遍历链表找到指定值的节点
current := d.Head
for current != nil {
if current.Val == val {
current.Prev.Next = current.Next // 将当前节点的Prev节点的Next指针指向当前节点的Next节点
current.Next.Prev = current.Prev // 将当前节点的Next节点的Prev指针指向当前节点的Prev节点
}
current = current.Next
}
}
时间复杂度:O(n)
// TraverseFromHead 从头部遍历链表
func (d *DoublyLinkedList) TraverseFromHead() {
current := d.Head
for current != nil {
fmt.Println(current.Val)
current = current.Next
}
}
时间复杂度:O(n)
// TraverseFromTail 从尾部遍历链表
func (d *DoublyLinkedList) TraverseFromTail() {
current := d.Tail
for current != nil {
fmt.Println(current.Val)
current = current.Prev
}
}
时间复杂度:O(n)
// FindNodeByIndex 查询指定位置的节点
func (d *DoublyLinkedList) FindNodeByIndex(index int) *Node {
// 索引必须大于等于0
if index < 0 {
return nil
}
// 索引等于0时,表示查询头节点
if index == 0 {
return d.Head
}
// 遍历链表找到指定位置
current := d.Head
currentIndex := 0
for current != nil {
if currentIndex == index {
return current
}
current = current.Next
currentIndex++
}
return nil
}
时间复杂度:O(n)
// FindNodeByValue 查找指定值的节点
func (d *DoublyLinkedList) FindNodeByValue(val int) []*Node {
var nodes []*Node
current := d.Head
for current != nil {
if current.Val == val {
nodes = append(nodes, current)
}
current = current.Next
}
return nodes
}
时间复杂度:O(n)