双向链表Deque的drop_between函数Bug排查:无法删除起始位置节点
解决双向链表Deque的drop_between函数问题
我来帮你搞定这个drop_between函数的bug~先看看你现有代码里的几个核心问题,再给你一个简洁高效的修复方案。
现有代码的问题分析
你的drop_between函数主要有这几个逻辑错误:
- 索引对应完全错位:你初始化
cur_index=0,但循环里先移动curr到下一个节点,再判断cur_index,导致实际处理的节点索引和你判断的cur_index差1。比如你要删除索引1的节点时,代码里判断的是cur_index=0,自然会漏掉起始节点的删除。 - 节点链接修改错误:
last_node.next = curr.next.next和curr.next.next.prev = last_node.next这两行完全写错了——正确的双向链表删除逻辑应该是让前节点的next指向当前节点的next,同时让当前节点的next的prev指向前节点(如果存在的话),你这里直接跳过了一个节点,导致链接混乱。 - 未更新关键属性:删除节点后没有修改
self.size,也没处理tail的更新(如果删除的是末尾节点的话),会导致链表状态不一致。 - 循环条件限制:
while curr.next会漏掉最后一个节点的处理,而且逐个遍历删除的效率也不高。
修复后的解决方案
我建议先写一个辅助函数用来根据索引快速定位节点,然后直接通过修改首尾节点的链接来批量删除范围节点,这样逻辑更清晰,效率也更高:
class Node: """ Initialize empty node """ def __init__(self, data, prev = None, next = None): self.data = data self.next = next self.prev = prev class Deque: """ A double-ended queue """ def __init__(self): """ Initializes an empty Deque """ self.head = None self.tail = None self.size = 0 def __len__(self): """ Computes the number of elements in the Deque :return: The size of the Deque """ return self.size def push_front(self, e): """ Inserts an element at the front of the Deque :param e: An element to insert """ new_head = Node(data = e, next = self.head) if len(self) == 0: self.tail = new_head if self.head: self.head.prev = new_head self.head = new_head self.size += 1 def _get_node(self, index): """辅助函数:根据索引获取对应节点(内部使用)""" if index < 0 or index >= self.size: raise IndexError("Index out of range") curr = self.head for _ in range(index): curr = curr.next return curr def drop_between(self, start, end): """ Deletes elements from the Deque that within the range [start, end) :param start: indicates the first position of the range :param end: indicates the last position of the range(does not drop this element) """ # 先处理所有非法边界情况 if start < 0 or end > self.size or start >= end: raise IndexError("Invalid range for drop_between") if start == end: return # 没有节点需要删除,直接返回 # 获取要删除范围的首尾节点 start_node = self._get_node(start) # 如果end等于链表长度,end_node就是None(超出最后一个节点) end_node = self._get_node(end) if end < self.size else None # 获取要删除范围的前一个节点 prev_node = start_node.prev # 修改双向链接 if prev_node: prev_node.next = end_node else: # 如果start是0,说明要从表头开始删,更新head为end_node self.head = end_node if end_node: end_node.prev = prev_node else: # 如果end是链表长度,说明要删到表尾,更新tail为prev_node self.tail = prev_node # 更新链表长度 self.size -= (end - start) def listprint(self, node): """ Prints each element of the node front to back :param node: """ while (node is not None): print(node.data) node = node.next def main(): D = Deque() for num in range(10): D.push_front(num) print("删除前的链表:") D.listprint(D.head) print("------") D.drop_between(4,7) print("删除后的链表:") D.listprint(D.head) if __name__ == "__main__": main()
修复逻辑说明
- 辅助函数
_get_node:快速根据索引定位节点,避免重复写遍历逻辑,也让代码更易读。 - 边界处理:完善了非法范围的判断,比如
end不能超过链表长度,start不能大于等于end等。 - 批量删除逻辑:直接找到要删除范围的第一个节点
start_node和范围结束的节点end_node,然后修改start_node的前驱节点和end_node的链接,一次性断开整个范围的节点,比逐个删除高效得多。 - 关键属性更新:修改了
head、tail和size,保证链表状态始终一致。
测试你的示例:当调用drop_between(1,3)时,链表[0,1,2,3]会正确变成[0,3];主函数里调用drop_between(4,7)后,会删除索引4、5、6对应的节点(也就是数值4、5、6),输出结果是0、1、2、3、7、8、9,符合预期。
内容的提问来源于stack exchange,提问作者Dracep
相关产品推荐
相关产品推荐

