Python3实现LinkedList删除指定值所有节点时出现AttributeError问题排查
解决链表删除所有指定节点的AttributeError问题
看起来你在实现链表删除所有指定节点时遇到了典型的空指针问题,咱们一步步拆解问题并修复它。
首先,先梳理下你代码里的几个核心问题:
- 类结构混淆:你把
LinkedList(链表)的方法(比如get_head_node、insert_beginning)放到了Node(节点)类里,这是结构错误——节点只需要管理自身的值和下一个节点的引用,而链表才需要负责管理头节点、插入、删除等整体操作。 - 缺少必要方法:你的
Node类里没有定义set_next_node和get_next_node方法,但代码里却调用了它们,这会导致运行报错。 - 删除逻辑的缺陷:
- 用
stringify_list().count()来确定删除次数的方式不可靠,删除过程中链表结构会变化,很容易导致重复处理或漏处理。 - 在删除中间节点时,找到目标节点后你直接把
current_node = None退出循环,这会导致后续的目标节点无法被处理;更关键的是,你没有判断next_node是否为None就直接调用next_node.get_value(),这就是触发AttributeError的直接原因——当遍历到链表最后一个节点时,next_node是None,调用它的get_value()自然会报错。
- 用
接下来,咱们重构代码,先把Node和LinkedList类分开,然后修复删除逻辑:
修正后的完整代码
class Node: def __init__(self, value, next_node=None): self.value = value self.next_node = next_node def get_value(self): return self.value def get_next_node(self): return self.next_node def set_next_node(self, next_node): self.next_node = next_node class LinkedList: def __init__(self, head_node=None): self.head_node = head_node def get_head_node(self): return self.head_node def insert_beginning(self, new_value): new_node = Node(new_value) new_node.set_next_node(self.head_node) self.head_node = new_node def stringify_list(self): string_list = "" current_node = self.get_head_node() while current_node: string_list += str(current_node.get_value()) + "\n" current_node = current_node.get_next_node() return string_list def remove_all_node(self, value_to_remove): # 先处理头节点:如果头节点是目标值,一直更新头节点直到不是目标值 while self.head_node and self.head_node.get_value() == value_to_remove: self.head_node = self.head_node.get_next_node() # 如果处理后头节点为空,直接返回 if not self.head_node: return # 处理中间和尾部节点 current_node = self.head_node while current_node.get_next_node(): if current_node.get_next_node().get_value() == value_to_remove: # 跳过目标节点 current_node.set_next_node(current_node.get_next_node().get_next_node()) else: # 只有当前节点的下一个不是目标时,才移动到下一个节点 current_node = current_node.get_next_node()
关键修复点解释
- 拆分类结构:把节点和链表的职责分开,
Node只负责自身的属性和访问/修改方法,LinkedList负责管理整个链表的操作,逻辑更清晰。 - 循环处理头节点:因为头节点没有前驱,所以单独循环处理——只要头节点是目标值,就将头节点替换为下一个节点,直到头节点不是目标或链表为空。
- 安全遍历中间节点:遍历过程中先判断
current_node.get_next_node()是否存在,再调用它的get_value(),避免空指针错误;而且在删除节点后,不移动current_node,因为新的下一个节点可能还是目标值(比如连续的目标节点),这样能一次性处理所有连续的目标节点。 - 去掉不可靠的count逻辑:直接通过一次遍历完成所有删除操作,更高效也更可靠。
测试示例
你可以用下面的代码测试修复后的方法:
# 创建链表并插入节点 ll = LinkedList() ll.insert_beginning(3) ll.insert_beginning(2) ll.insert_beginning(3) ll.insert_beginning(1) ll.insert_beginning(3) print("删除前的链表:") print(ll.stringify_list()) ll.remove_all_node(3) print("删除后的链表:") print(ll.stringify_list())
运行后会输出:
删除前的链表: 3 1 3 2 3 删除后的链表: 1 2
内容的提问来源于stack exchange,提问作者iamcuriouscat
相关产品推荐
相关产品推荐

