双向链表的核心算法:遍历与操作

在实现自定义 List 容器时,双向链表是一种高效的基础数据结构,因为它允许双向遍历(前向和后向后向),并支持快速插入、删除等操作。每个节点包含数据、指向前一个节点的指针(prev)和指向后一个节点的指针(next)。下面我将逐步解释双向链表的遍历和核心操作算法,并提供 Python 代码实现。所有实现均基于标准数据结构原理,确保真实可靠。

步骤 1: 定义节点类

双向链表的基础是节点(Node)类。每个节点存储数据、前驱指针和后继指针。

class Node:
    def __init__(self, data):
        self.data = data  # 节点存储的数据
        self.prev = None  # 指向前一个节点的指针
        self.next = None  # 指向后一个节点的指针

步骤 2: 定义双向链表类

我们创建一个 DoublyLinkedList 类,管理链表的头节点(head)和尾节点(tail)。初始化时链表为空。

class DoublyLinkedList:
    def __init__(self):
        self.head = None  # 链表头节点
        self.tail = None  # 链表尾节点

步骤 3: 遍历算法

遍历是访问每个节点的过程。双向链表支持前向遍历(从头到尾)和后向遍历(从尾到头)。时间复杂度为 $O(n)$,其中 $n$ 是节点数。

  • 前向遍历:从头节点开始,依次访问每个节点,直到 nextNone
  • 后向遍历:从尾节点开始,依次访问每个节点,直到 prevNone

DoublyLinkedList 类中添加遍历方法:

    def forward_traversal(self):
        """前向遍历:从头到尾打印节点数据"""
        current = self.head
        while current:
            print(current.data, end=" -> ")  # 打印当前节点数据
            current = current.next
        print("None")  # 表示遍历结束

    def backward_traversal(self):
        """后向遍历:从尾到头打印节点数据"""
        current = self.tail
        while current:
            print(current.data, end=" -> ")  # 打印当前节点数据
            current = current.prev
        print("None")  # 表示遍历结束

步骤 4: 核心操作算法

核心操作包括插入、删除和查找。这些操作需要处理指针的更新,确保链表完整性。时间复杂度分析:

  • 插入和删除在头部或尾部为 $O(1)$,在中间为 $O(n)$。
  • 查找为 $O(n)$。

DoublyLinkedList 类中添加操作方法:

插入操作
  • 在头部插入:创建新节点,更新头节点和相邻节点的指针。
  • 在尾部插入:创建新节点,更新尾节点和相邻节点的指针。
  • 在特定位置插入:先查找位置,再插入节点。
    def insert_at_head(self, data):
        """在链表头部插入节点"""
        new_node = Node(data)
        if self.head is None:  # 空链表时,新节点同时是头和尾
            self.head = new_node
            self.tail = new_node
        else:
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node

    def insert_at_tail(self, data):
        """在链表尾部插入节点"""
        new_node = Node(data)
        if self.tail is None:  # 空链表时,新节点同时是头和尾
            self.head = new_node
            self.tail = new_node
        else:
            new_node.prev = self.tail
            self.tail.next = new_node
            self.tail = new_node

    def insert_at_position(self, data, position):
        """在指定位置插入节点(位置从 0 开始计数)"""
        if position < 0:
            raise ValueError("位置不能为负")
        if position == 0:
            self.insert_at_head(data)
            return
        new_node = Node(data)
        current = self.head
        index = 0
        # 移动到指定位置的前一个节点
        while current and index < position - 1:
            current = current.next
            index += 1
        if current is None:  # 位置超出链表长度,插入尾部
            self.insert_at_tail(data)
        else:
            new_node.next = current.next
            new_node.prev = current
            if current.next:  # 如果当前节点不是尾节点
                current.next.prev = new_node
            current.next = new_node
            if new_node.next is None:  # 如果新节点是尾节点
                self.tail = new_node

删除操作
  • 删除头部节点:更新头节点指针。
  • 删除尾部节点:更新尾节点指针。
  • 删除特定节点:先查找节点,再更新指针。
    def delete_at_head(self):
        """删除链表头部节点"""
        if self.head is None:
            return  # 空链表,无操作
        if self.head == self.tail:  # 只有一个节点
            self.head = None
            self.tail = None
        else:
            self.head = self.head.next
            self.head.prev = None

    def delete_at_tail(self):
        """删除链表尾部节点"""
        if self.tail is None:
            return  # 空链表,无操作
        if self.head == self.tail:  # 只有一个节点
            self.head = None
            self.tail = None
        else:
            self.tail = self.tail.prev
            self.tail.next = None

    def delete_node(self, data):
        """删除指定数据的节点(只删除第一个匹配项)"""
        current = self.head
        while current:
            if current.data == data:
                if current == self.head:
                    self.delete_at_head()
                elif current == self.tail:
                    self.delete_at_tail()
                else:
                    current.prev.next = current.next
                    current.next.prev = current.prev
                return  # 删除成功,退出
            current = current.next

查找操作
  • 查找节点:遍历链表,返回第一个匹配数据的节点。
    def find(self, data):
        """查找指定数据的节点,返回节点或 None"""
        current = self.head
        while current:
            if current.data == data:
                return current
            current = current.next
        return None

步骤 5: 完整代码示例

以下是完整的双向链表实现,包括遍历和操作。使用时,可以创建链表对象并调用方法。

class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def forward_traversal(self):
        current = self.head
        while current:
            print(current.data, end=" -> ")
            current = current.next
        print("None")

    def backward_traversal(self):
        current = self.tail
        while current:
            print(current.data, end=" -> ")
            current = current.prev
        print("None")

    def insert_at_head(self, data):
        new_node = Node(data)
        if self.head is None:
            self.head = new_node
            self.tail = new_node
        else:
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node

    def insert_at_tail(self, data):
        new_node = Node(data)
        if self.tail is None:
            self.head = new_node
            self.tail = new_node
        else:
            new_node.prev = self.tail
            self.tail.next = new_node
            self.tail = new_node

    def insert_at_position(self, data, position):
        if position < 0:
            raise ValueError("位置不能为负")
        if position == 0:
            self.insert_at_head(data)
            return
        new_node = Node(data)
        current = self.head
        index = 0
        while current and index < position - 1:
            current = current.next
            index += 1
        if current is None:
            self.insert_at_tail(data)
        else:
            new_node.next = current.next
            new_node.prev = current
            if current.next:
                current.next.prev = new_node
            current.next = new_node
            if new_node.next is None:
                self.tail = new_node

    def delete_at_head(self):
        if self.head is None:
            return
        if self.head == self.tail:
            self.head = None
            self.tail = None
        else:
            self.head = self.head.next
            self.head.prev = None

    def delete_at_tail(self):
        if self.tail is None:
            return
        if self.head == self.tail:
            self.head = None
            self.tail = None
        else:
            self.tail = self.tail.prev
            self.tail.next = None

    def delete_node(self, data):
        current = self.head
        while current:
            if current.data == data:
                if current == self.head:
                    self.delete_at_head()
                elif current == self.tail:
                    self.delete_at_tail()
                else:
                    current.prev.next = current.next
                    current.next.prev = current.prev
                return
            current = current.next

    def find(self, data):
        current = self.head
        while current:
            if current.data == data:
                return current
            current = current.next
        return None

使用示例

# 创建双向链表
dll = DoublyLinkedList()
dll.insert_at_head(10)  # 头部插入
dll.insert_at_tail(20)  # 尾部插入
dll.insert_at_position(15, 1)  # 在位置1插入

print("前向遍历:")
dll.forward_traversal()  # 输出: 10 -> 15 -> 20 -> None

print("后向遍历:")
dll.backward_traversal()  # 输出: 20 -> 15 -> 10 -> None

dll.delete_node(15)  # 删除节点15
print("删除后前向遍历:")
dll.forward_traversal()  # 输出: 10 -> 20 -> None

总结

通过以上实现,双向链表的核心算法包括:

  • 遍历:前向和后向遍历均高效,时间复杂度为 $O(n)$。
  • 操作:插入和删除在头尾部为 $O(1)$,在中间为 $O(n)$;查找为 $O(n)$。
  • 优势:双向指针使得操作更灵活,适合作为 List 容器的底层结构。

您可以根据需要扩展功能,如添加长度计算或迭代器。实际应用中,注意处理边界情况(如空链表或单节点链表)以保持代码健壮性。

更多推荐