双向链表实现(面向对象、魔术方法练习)
用面向对象实现LinkedList链表
双向链表实现append、pop(尾部弹出)、insert、remove(使用索引移除)、iternodes方法
为链表提供__getitem__、__iter__、__setitem__等方法
from __future__ import annotations
class ListNode:
def __init__(self, item, next: ListNode = None, prev: ListNode = None):
self.item = item
self.next = next
self.prev = prev
def __repr__(self):
return "{}<=={}==>{}".format(
self.prev.item if self.prev else None,
self.item,
self.next.item if self.next else None)
__str__ = __repr__
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self._size = 0
def append(self, item):
node = ListNode(item)
if self.head is None: # 空链表
self.head = node
else:
node.prev = self.tail
self.tail.next = node
self.tail = node
self._size += 1
return self
def pop(self): # 尾部弹出
if self.tail is None: # 没有元素
raise Exception('Empty LinkedList')
node: ListNode = self.tail
item = node.item
prev = node.prev
if self.head == self.tail: # 只有一个元素
self.head = None
self.tail = None
else:
self.tail = prev
prev.next = None
self._size -= 1
return item
def insert(self, index, item):
# if index < 0:
# raise IndexError('not support negative index')
# current = None
# for i, node in enumerate(self.iter_nodes()): # 遍历查找插入点
# if i == index:
# current = node
# break
# else:
# self.append(item)
# return
if index >= len(self): # 大于长度尾部追加
self.append(item)
return
if index < -len(self): # 相当于在头部插入
index = 0
current = self[index]
node = ListNode(item)
prev = current.prev
# next = current.next
if index == 0: # 开头插入,插入到index前面,先把插入点之前的关系修复,再统一修复插入点后面的关系
self.head = node
else:
node.prev = prev
prev.next = node
node.next = current
current.prev = node
self._size += 1
def remove(self, index):
if self.tail is None:
raise Exception('Empty')
# if index < 0:
# raise IndexError('not support negative index')
# current = None
# for i, node in enumerate(self.iter_nodes()): # 遍历查找插入点
# if i == index:
# current = node
# break
# else:
# raise IndexError('out of range')
current = self[index]
prev = current.prev
next = current.next
if prev is None and next is None: # 只有一个元素
self.head = None
self.tail = None
elif prev is None: # 多个元素,删除元素为第一个元素
self.head = next
next.prev = None
elif next is None: # 多个元素,删除元素为最后一个
prev.next = None
self.tail = prev
else: # 多个元素,删除中间元素
prev.next = next
next.prev = prev
del current
self._size -= 1
def iter_nodes(self, reverse=False):
current = self.head if not reverse else self.tail
while current:
yield current
current = current.next if not reverse else current.prev
size = property(lambda self: self._size)
# 容器化
def __len__(self):
return self._size
__iter__ = iter_nodes
def __reversed__(self):
return self.iter_nodes(True)
def __getitem__(self, index):
# if index >= 0:
# for i, node in enumerate(self.iter_nodes(False), 0):
# if index == i:
# return node # return node.item
# if index < 0:
# for i, node in enumerate(self.iter_nodes(True), 1):
# if index == -i:
# return node
if index >= len(self) or index < -len(self): # 正负超界
raise IndexError('out of index')
start = 0 if index >= 0 else 1
reverse = False if index >= 0 else True
for i, node in enumerate(self.iter_nodes(reverse), start):
if abs(index) == i:
return node
def __setitem__(self, index, value):
self[index].item = value
链表中的节点和链表(看作容器)为两个类:
- 节点(node):有prev、next、item三个属性。
- 链表(LinkedList):有head(头节点)、tail(尾节点)和大小三个属性
测试结果:
ll = LinkedList()
ll.append(1).append(2).append('x')
ll[2] = 3
for i in ll.iter_nodes():
print(i)
print('-' * 30)
print(*reversed(ll), sep='\n')
print('*' * 30)
print(ll[0])
ll.pop()
ll.insert(1, '4')
for i in ll.iter_nodes():
print(i)
print('+' * 30)
ll.remove(1)
for i in ll.iter_nodes():
print(i)


浙公网安备 33010602011771号