双向链表是一种线性数据结构,其中每个节点包含两个指针:一个指向前驱节点(prev),另一个指向后继节点(next)

双向链表是一种线性数据结构,其中每个节点包含两个指针:一个指向前驱节点(prev),另一个指向后继节点(next)。相比单向链表,双向链表支持双向遍历,使得插入和删除操作更加高效,尤其是在已知节点位置的情况下。

双向链表操作详解

1. 插入节点

在双向链表中插入新节点时,需调整前后节点的指针以维护链表结构。假设要在某个节点 p 之后插入新节点 new_node

def insert_after(head, p, new_node):
    new_node.next = p.next
    new_node.prev = p
    if p.next is not None:
        p.next.prev = new_node
    p.next = new_node

图 3-4(a) 展示了插入过程中各指针的变化过程:p → new_node → p.next,同时反向指针也正确连接。

2. 删除节点

删除节点时,需将其前驱和后继节点相互链接,再释放该节点内存。

def delete_node(head, node):
    if node.prev is not None:
        node.prev.next = node.next
    else:
        head = node.next  # 删除的是头节点
    if node.next is not None:
        node.next.prev = node.prev
    node.prev = node.next = None  # 清空被删节点指针

图 3-4(b) 显示了删除后相邻节点如何绕过目标节点完成连接。


栈的基础知识

栈(Stack)是限定仅在表尾(栈顶)进行插入或删除操作的线性表,遵循“后进先出”(LIFO, Last In First Out)原则。

基本操作:
  • 初始化:创建一个空栈。
  • 判空(isEmpty):判断栈是否为空。
  • 入栈(push):将元素压入栈顶。
  • 出栈(pop):移除并返回栈顶元素。
  • 取栈顶元素(peek/top):不删除地访问栈顶元素。
使用场景:
  • 函数调用堆栈
  • 表达式求值与括号匹配
  • 深度优先搜索(DFS)

栈可以用数组或链表实现;若用双向链表实现,则可更灵活地管理内存,但通常使用单向链表或顺序存储即可满足需求。


补充背景说明

《软件设计师教程》作为软考指定教材,系统讲解了上述数据结构内容,强调理论与实践结合,帮助考生掌握程序设计基础、算法分析及系统开发能力。双向链表与栈均属于数据结构章节的重点内容,常出现在选择题与综合应用题中。
使用双向链表实现栈时,可以将链表的头节点作为栈顶(也可以选择尾节点,但头部操作更高效),所有入栈和出栈操作均在头部进行。由于双向链表支持快速访问前驱和后继,插入和删除的时间复杂度均为 O(1)。

实现思路:

  • 栈顶:设为双向链表的头节点位置。
  • 入栈(push):在链表头部插入新节点。
  • 出栈(pop):删除头节点并返回其值。
  • 取栈顶(peek):返回头节点的值而不删除。

定义节点结构

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

栈的实现(基于双向链表)

class Stack:
    def __init__(self):
        self.head = None  # 指向栈顶(链表头)

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

    def pop(self):
        if self.head is None:
            raise IndexError("pop from empty stack")
        popped_data = self.head.data
        self.head = self.head.next
        if self.head is not None:
            self.head.prev = None
        return popped_data

    def peek(self):
        if self.head is None:
            return None
        return self.head.data

    def is_empty(self):
        return self.head is None

示例使用

stack = Stack()
stack.push(10)
stack.push(20)
print(stack.peek())  # 输出: 20
print(stack.pop())   # 输出: 20
print(stack.pop())   # 输出: 10
print(stack.is_empty())  # 输出: True

时间复杂度分析

操作时间复杂度说明
pushO(1)在头部插入,只需修改几个指针
popO(1)删除头节点,指针调整常数时间完成
peekO(1)直接访问头节点数据
is_emptyO(1)判断 head 是否为 None

所有核心操作都具有 O(1) 的时间复杂度,效率非常高。


优势与适用场景

  • 动态大小,避免数组扩容问题。
  • 内存利用率高,按需分配。
  • 适合频繁插入/删除的场景。
  • 在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值