双向链表
链表是实现了数据之间保持逻辑顺序,但存储空间不连续的数据结构。
相对于单向链表,双向链表多了一个指向前面一个节点的指针域。
链表查询效率较慢,因为查询的时候需要移动指针一个一个找。
双向链表新增和删除元素效率较高,因为链表会记录前一个节点和后一个节点。
class Node:
def __init__(self, item, next=None, prev=None):
self.item = item
self.next = next
self.prev = prev
def __str__(self):
return '<prev: {} <- node: {} -> next: {}>'.format(self.prev.item if self.prev else None, self.item, self.next.item if self.next else None)
def __repr__(self):
return str(self.item)
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def append(self, item):
node = Node(item)
# 如果head节点为空,表示链表为空
if self.head is None:
self.head = node
self.tail = node
else:
self.tail.next = node
node.prev = self.tail
self.tail = node
self.size += 1
return self
def index(self, item):
for i, node in enumerate(self):
if item == node.item:
return i
else:
raise ValueError('item does not exist')
def insert(self, index, item):
if index < 0:
raise IndexError
# 如果找到就将current指向对应位置的节点,继续后面的操作
# 如果没有找到(链表为空或者索引超界),则追加并立即返回,后面的操作将不会执行
for i, node in enumerate(self):
if i == index:
current = node
break
else:
self.append(item)
return
node = Node(item)
prev = current.prev
# 从头部插入
if prev is None:
node.next = current
current.prev = node
self.head = node
# 从中间插入(尾部插入即追加,上面已经实现)
else:
node.next = current
node.prev = prev
prev.next = node
current.prev = node
self.size += 1
def pop(self):
# 如果尾部为空,则表示链表为空
if self.tail is None:
raise Exception('empty')
node = self.tail
item = node.item
prev = node.prev
# 如果尾部节点没有前节点,则表示链表只有一个元素
if prev is None:
self.head = None
self.tail = None
# 剩下就是有多个节点的情况
else:
prev.next = None
self.tail = prev
self.size -= 1
return item
def remove(self, index):
if index < 0:
raise IndexError('does not support negative index')
# 如果链表为空,则抛出异常
if self.head is None:
raise Exception('empty')
# 如果找到就将current指向对应位置的节点,继续后面的操作
# 如果没有找到(链表为空或者索引超界),则抛出异常
for i, node in enumerate(self):
if i == index:
current = node
break
else:
raise IndexError('index out of range')
prev = current.prev
next = current.next
# 如果current没有前节点也没有后节点,表示只有一个节点
if prev is None and next is None:
self.head = None
self.tail = None
# 如果不止一个节点,且如果current没有前节点,表示current是head
elif prev is None:
next.prev = None
self.head = next
# 如果不止一个节点、current不是head,且如果current没有后节点,表示current是tail
elif next is None:
prev.next = None
self.tail = prev
# 剩下就是多节点从中间remove的情况
else:
prev.next = next
next.prev = prev
self.size -= 1
# def iternodes(self, reverse=False):
# current = self.head if not reverse else self.tail
# while current:
# yield current
# current = current.next if not reverse else current.head
def clear(self):
for node in self:
node.prev = None
node.tail = None
self.head = None
self.tail = None
self.size = 0
def __iter__(self):
current = self.head
while current:
yield current
current = current.next
def __reversed__(self):
current = self.tail
while current:
yield current
current = current.prev
def __len__(self):
# current = self.head
# count = 0
# while current:
# count += 1
# current = current.next
# return count
return self.size
def __getitem__(self, key):
# 支持负索引
obj = reversed(self) if key < 0 else self
start = 1 if key < 0 else 0
for i, node in enumerate(obj, start):
if abs(key) == i:
return node
else:
raise IndexError('index out of range')
def __setitem__(self, key, value):
# for i, node in enumerate(self):
# if key == i:
# node.item = value
# else:
# self.append(value)
self[key].item = value
linklist = LinkedList()
# 测试append()
for i in range(10):
linklist.append(i)
# 测试__iter__
for node in linklist:
print(node)
# 测试__reversed__
for node in reversed(linklist):
print(node)
# 测试__len__
print(len(linklist))
# 测试index()
print(linklist.index(3))
# 测试insert()
linklist.insert(0, 0)
print(list(linklist))
# 测试pop()
print(linklist.pop())
# 测试__getitem__
print(linklist[3])
# print(linklist[13])
print(linklist[-1])
# 测试__setitem__
linklist[5] = 15
print(list(linklist))
# 测试clear()
linklist.clear()
print(list(linklist))
print(len(linklist))
参考:
http://zhaochj.github.io/2016/05/12/2016-05-12-数据结构-链表/
https://blog.csdn.net/qq_26118603/article/details/79039738
http://blog.suchasplus.com/2011/03/why-python-Standard-library-does-not-implement-the-list.html
https://www.zhihu.com/question/55721190