通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

python如何删除双向链表

python如何删除双向链表

删除Python中的双向链表节点

删除双向链表中的节点有以下几种情况:删除头节点、删除尾节点、删除中间节点。 我们以删除头节点为例,详细描述其实现方法。

删除头节点时,只需要将头节点的下一个节点的 prev 指针置为 None,并更新头节点即可。下面是详细的实现代码:

class Node:

def __init__(self, data):

self.data = data

self.next = None

self.prev = None

class DoublyLinkedList:

def __init__(self):

self.head = None

def append(self, data):

new_node = Node(data)

if self.head is None:

self.head = new_node

return

last = self.head

while last.next:

last = last.next

last.next = new_node

new_node.prev = last

def delete_node(self, node):

if self.head is None or node is None:

return

if self.head == node:

self.head = node.next

if node.next:

node.next.prev = node.prev

if node.prev:

node.prev.next = node.next

def display(self):

node = self.head

while node:

print(node.data, end=' ')

node = node.next

print()

使用示例

dll = DoublyLinkedList()

dll.append(1)

dll.append(2)

dll.append(3)

dll.display() # 输出: 1 2 3

dll.delete_node(dll.head)

dll.display() # 输出: 2 3

一、双向链表的基本操作

1. 创建双向链表

创建一个双向链表需要定义节点类 Node,其中包含数据域 data,前驱指针 prev,后继指针 next。此外,还需要定义链表类 DoublyLinkedList,其中包含一个指向头节点的指针 head

class Node:

def __init__(self, data):

self.data = data

self.next = None

self.prev = None

class DoublyLinkedList:

def __init__(self):

self.head = None

2. 插入节点

双向链表可以在头部、尾部或中间插入节点。以下是三种插入节点的方法:

  • 在头部插入节点:

def insert_at_head(self, data):

new_node = Node(data)

if self.head is None:

self.head = new_node

return

new_node.next = self.head

self.head.prev = new_node

self.head = new_node

  • 在尾部插入节点:

def append(self, data):

new_node = Node(data)

if self.head is None:

self.head = new_node

return

last = self.head

while last.next:

last = last.next

last.next = new_node

new_node.prev = last

  • 在指定位置插入节点:

def insert_after(self, prev_node, data):

if prev_node is None:

print("The given previous node cannot be None")

return

new_node = Node(data)

new_node.next = prev_node.next

prev_node.next = new_node

new_node.prev = prev_node

if new_node.next:

new_node.next.prev = new_node

3. 删除节点

如开头所述,删除节点时,需要考虑不同的情况,并更新相应的指针以保证链表的完整性。

  • 删除头节点:

def delete_node(self, node):

if self.head is None or node is None:

return

if self.head == node:

self.head = node.next

if node.next:

node.next.prev = node.prev

if node.prev:

node.prev.next = node.next

  • 删除尾节点:

def delete_last_node(self):

if self.head is None:

return

if self.head.next is None:

self.head = None

return

last = self.head

while last.next:

last = last.next

last.prev.next = None

  • 删除中间节点:

def delete_middle_node(self, node):

if self.head is None or node is None:

return

if node.next:

node.next.prev = node.prev

if node.prev:

node.prev.next = node.next

二、双向链表的应用

双向链表具有前后指针,能够高效地进行插入、删除操作,广泛应用于各种场景。

1. 实现 LRU 缓存

LRU(Least Recently Used)缓存常用于内存管理,维护一个固定大小的缓存,当缓存满时,删除最久未使用的元素。双向链表和哈希表结合可以高效实现 LRU 缓存。

class LRUCache:

def __init__(self, capacity):

self.capacity = capacity

self.cache = {}

self.head = Node(0)

self.tail = Node(0)

self.head.next = self.tail

self.tail.prev = self.head

def get(self, key):

if key in self.cache:

node = self.cache[key]

self._remove(node)

self._add(node)

return node.data

return -1

def put(self, key, value):

if key in self.cache:

self._remove(self.cache[key])

node = Node(value)

self._add(node)

self.cache[key] = node

if len(self.cache) > self.capacity:

node = self.head.next

self._remove(node)

del self.cache[node.data]

def _remove(self, node):

prev = node.prev

next = node.next

prev.next = next

next.prev = prev

def _add(self, node):

prev = self.tail.prev

prev.next = node

self.tail.prev = node

node.prev = prev

node.next = self.tail

2. 双端队列

双端队列(Deque)是一种允许在两端进行插入和删除操作的数据结构。双向链表非常适合实现双端队列。

class Deque:

def __init__(self):

self.head = None

self.tail = None

def add_front(self, data):

new_node = Node(data)

if self.head is None:

self.head = self.tail = new_node

else:

new_node.next = self.head

self.head.prev = new_node

self.head = new_node

def add_rear(self, data):

new_node = Node(data)

if self.tail is None:

self.head = self.tail = new_node

else:

new_node.prev = self.tail

self.tail.next = new_node

self.tail = new_node

def remove_front(self):

if self.head is None:

return None

data = self.head.data

self.head = self.head.next

if self.head:

self.head.prev = None

else:

self.tail = None

return data

def remove_rear(self):

if self.tail is None:

return None

data = self.tail.data

self.tail = self.tail.prev

if self.tail:

self.tail.next = None

else:

self.head = None

return data

三、双向链表的性能分析

双向链表由于具有前后指针,能够高效地进行插入和删除操作。然而,其缺点也显而易见,链表中的每个节点都需要额外的存储空间来存储前后指针,且在进行查找操作时,时间复杂度为 O(n)。

1. 空间复杂度

双向链表的空间复杂度为 O(n),其中 n 为链表中节点的个数。每个节点除了存储数据外,还需要存储前后指针,因此空间开销较大。

2. 时间复杂度

  • 插入操作: 在头部或尾部插入节点的时间复杂度为 O(1),在中间插入节点的时间复杂度为 O(n)。
  • 删除操作: 删除头节点或尾节点的时间复杂度为 O(1),删除中间节点的时间复杂度为 O(n)。
  • 查找操作: 查找节点的时间复杂度为 O(n)。

四、双向链表的改进与优化

虽然双向链表在插入和删除操作上具有一定的优势,但其在查找操作上的劣势也不可忽视。为了解决这一问题,可以结合其他数据结构进行改进与优化。

1. 跳表(Skip List)

跳表是一种可以进行快速查找、插入和删除操作的数据结构。跳表在链表的基础上增加了多级索引,使得查找操作的时间复杂度降低到 O(log n)。

import random

class SkipNode:

def __init__(self, value, level):

self.value = value

self.forward = [None] * (level + 1)

class SkipList:

def __init__(self, max_level):

self.max_level = max_level

self.head = SkipNode(-1, max_level)

self.level = 0

def random_level(self):

level = 0

while random.random() < 0.5 and level < self.max_level:

level += 1

return level

def insert(self, value):

update = [None] * (self.max_level + 1)

current = self.head

for i in range(self.level, -1, -1):

while current.forward[i] and current.forward[i].value < value:

current = current.forward[i]

update[i] = current

level = self.random_level()

if level > self.level:

for i in range(self.level + 1, level + 1):

update[i] = self.head

self.level = level

node = SkipNode(value, level)

for i in range(level + 1):

node.forward[i] = update[i].forward[i]

update[i].forward[i] = node

def search(self, value):

current = self.head

for i in range(self.level, -1, -1):

while current.forward[i] and current.forward[i].value < value:

current = current.forward[i]

current = current.forward[0]

if current and current.value == value:

return current

return None

def delete(self, value):

update = [None] * (self.max_level + 1)

current = self.head

for i in range(self.level, -1, -1):

while current.forward[i] and current.forward[i].value < value:

current = current.forward[i]

update[i] = current

current = current.forward[0]

if current and current.value == value:

for i in range(self.level + 1):

if update[i].forward[i] != current:

break

update[i].forward[i] = current.forward[i]

while self.level > 0 and self.head.forward[self.level] is None:

self.level -= 1

2. 自适应链表

自适应链表是一种结合了链表和数组优点的数据结构,能够在一定程度上提高查找效率。自适应链表将链表分为多个块,每个块中存储一定数量的元素,并维护一个索引数组来快速定位块。

class Block:

def __init__(self, capacity):

self.capacity = capacity

self.size = 0

self.data = [None] * capacity

self.next = None

class AdaptiveList:

def __init__(self, block_capacity):

self.block_capacity = block_capacity

self.head = Block(block_capacity)

def insert(self, value):

current = self.head

while current.size == current.capacity:

if current.next is None:

current.next = Block(self.block_capacity)

current = current.next

current.data[current.size] = value

current.size += 1

def search(self, value):

current = self.head

while current:

for i in range(current.size):

if current.data[i] == value:

return current.data[i]

current = current.next

return None

def delete(self, value):

current = self.head

while current:

for i in range(current.size):

if current.data[i] == value:

current.data[i] = current.data[current.size - 1]

current.size -= 1

return

current = current.next

五、总结

双向链表是一种基本的数据结构,具有前后指针,能够高效地进行插入和删除操作。然而,其在查找操作上的时间复杂度较高,空间复杂度较大。在实际应用中,可以结合其他数据结构,如跳表、自适应链表等,进行优化与改进。

综上所述,双向链表在实现删除操作时,需要根据具体情况更新相应的指针,以保证链表的完整性。同时,双向链表在插入、删除操作上具有一定的优势,但在查找操作上存在劣势,可以结合其他数据结构进行优化。

相关问答FAQs:

双向链表的删除操作如何实现?
在Python中,删除双向链表中的节点通常涉及到更新节点的前后指针。首先,需要找到要删除的节点,然后通过调整该节点的前后节点指针来移除它。具体步骤包括:将目标节点的前节点的next指针指向目标节点的后节点,同时将后节点的prev指针指向目标节点的前节点。最后,确保清理目标节点的引用以帮助垃圾回收。

删除双向链表时,如何处理头尾节点?
在双向链表中,头节点和尾节点的删除操作稍有不同。当删除头节点时,需要将头指针指向新的头节点,并将新头节点的prev指针设为None。若删除尾节点,则需要将尾指针指向新的尾节点,并将新尾节点的next指针设为None。在这两种情况下,还需检查链表是否为空,以避免引用错误。

在删除节点后,如何确保链表的完整性?
在执行删除操作后,确保链表的完整性是非常重要的。可以通过遍历链表来验证所有节点的前后指针是否正确连接。此外,检查链表的长度是否准确也是一个好方法。建议在删除节点后进行一次完整的遍历,并在过程中确认每个节点的prevnext指针是否符合预期,以避免潜在的逻辑错误或数据丢失。

相关文章