Python数据结构-链表
1)概念:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。
2)单向链表实现
class SingleNode:
"""节点类"""
def __init__(self,value,next=None):
self.value = value
self.next = next
def __repr__(self):
return '{}==>{}'.format(self.value,self.next.value if self.next else None)
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def append(self,value):
"""尾部追加"""
node = SingleNode(value) #头尾是谁
#当前尾部
#当前的尾部的下一个指向新的node。
#当前尾部
tail = self.tail #第一个元素加进来,问self.tail尾部是谁。
if tail is None:
self.head = node
else:
tail.next = node
self.tail = node
return self
def iternodes(self):
current = self.head
while current:
yield current
current = current.next
ll = LinkedList()
ll.append('abd').append(1).append(3).append('def')
for i in ll.iternodes():
print(i)
思路:(1)首先要定义两个类。节点类和容器类
(2)考虑到节点元素和节点元素的下一跳是谁。
(3)元素的容器内要考虑到头部和尾部。
(4)定义append方法,尾部追加元素,当前节点等于第一个节点类追加元素。
(5)考虑到如果容器内没有元素,那么当前的头部和尾部都为None,追加一个元素后,头部不变,尾部就是当前的node。
(6)如果不为空,头部不变,尾部为下一跳,最后当前的尾部为实例的尾部。
(7)定义迭代方法。利用生成器,每次取元素的当前节点,从头开始,yield当前元素,下一跳元素,当前节点等下一跳的元素。
3)#双向列表
class SingleNode:
"""节点类"""
def __init__(self,value,next=None,prev=None):
self.value = value
self.next = next
self.prev = prev
def __repr__(self):
return '{}<=={}==>{}'.format(
self.prev.value if self.prev else None,
self.value,
self.next.value if self.next else None)
class LinkedList:
"""容器类"""
def __init__(self):
self.head = None
self.tail = None
def append(self,value):
"""尾部追加"""
node = SingleNode(value) #头尾是谁
#当前尾部
#当前的尾部的下一个指向新的node。
#当前尾部
tail = self.tail #第一个元素加进来,问self.tail尾部是谁。
if tail is None: #添加第一个元素
self.head = node
else:
tail.next = node
node.prev = tail #添加新元素进来,此时尾部还未指向新节点node,当前尾部还是上一个node的尾部。
# 所以新节点的上一跳为当前的尾部。
self.tail = node
return self
def pop(self):
"""尾部弹出"""
#empty
if self.tail is None:
raise Exception('empty')
#just one
# if self.head.next is None:
# if self.tail.prev is None:
#node = self.tail
oldtail = self.tail #等价于上面
if self.head is self.tail: #just one current
self.head = None
self.tail = None
else:
# node.prev = None
# node.prev.next = None
# self.tail = node.prev #更新尾部
prev = oldtail.prev
prev.next = None
self.tail = prev #等价于上面的
oldtail.prev = None
return oldtail
def insert(self,index,value):
if index < 0:
raise IndexError('Wrong index{}'.format(index))
current = None
for i,node in enumerate(self.iternodes()):
if index == i:
current = node
break
else:
#超过当前迭代。index>length -1
self.append(value) #空链表直接尾部追加,然后返回了
return
#找到内部的插入点,非空的
#至少node一定有,不能是node
prev = current.prev
#next = current.next
node = SingleNode(value)
if index == 0:
node.next = current
current.prev = node
self.head = node
else:
prev.next = node
node.next = current
current.prev = node
node.prev = prev
def remove(self,index):
#很多元素
#两个元素
#1个元素
#0个元素
if index < 0:
raise IndexError('Wrong index{}'.format(index))
if self.tail is None: #0个元素
raise Exception('empty')
if self.head is self.tail: #一个元素
node = self.head
self.head = None
self.tail = None
del node
return 0
current = None
for i, node in enumerate(self.iternodes()):
if index == i:
current = node
break
# else:
# raise IndexError('out of boundary')
else:
# 超过当前迭代。index>length -1
self.pop() # 空链表直接尾部追加,然后返回了
return
prev = current.prev
next = current.next
if index == 0:
next.prev = None
self.head = next
#tail 处理
elif next is None: #移除尾部
prev.next = None
self.tail = prev
else:#mid处理
prev.next = next
next.prev = prev
del current
return index
# def iternodes(self):
# current = self.head
# while current:
# yield current
# current = current.next
def iternodes(self,reverse = False):
current = self.tail if reverse else self.head
while current:
yield current
current = current.prev if reverse else current.next
ll = LinkedList()
ll.append('abd').append(1).append(3).append('def')
for i in ll.iternodes():
print(i)
print('+++++++')
print(ll.pop())
print(ll.pop())
ll.insert(1000,'acd')
ll.insert(3,3)
print('-----------------')
for i in ll.iternodes(True):
print(i)
ll.remove(1000)
for i in ll.iternodes():
print(i)
思路:(1)在单向链表的基础上改进双向链表。因为是双向的所哟增加上一跳。
(2)定义pop方法,尾部弹出,考虑到链表里面只有一个元素,为空和不为空的三种情况。一、如果为空的话,直接抛出异常。二、一个元素的话,头部和尾部全部为空。三、定义旧的尾部为原来的尾部,上一跳为原来尾部的上一跳,上一跳的下一跳变为None,新的尾部为原来node的上一跳,旧的尾部的上一跳为空,返回旧尾部。
(3)Insert方法(需要索引index和值),一、首先不支持副索引,如果输入的索引为负数的,直接抛出异常。二、索引超届的的直接尾部追加。三、利用for循环来迭代链表,索引对应迭代序号,如果索引为0的情况下,对应的元素上一跳为新元素,当前元素的下一跳为对应的元素node。如果在中间插入的话,需要有四种改变,前面元素的下一跳为当前要插入的元素,后面的元素上一跳为当前这个元素。当前元素前元素的前一跳还是前一跳,前面元素的下一跳是当前元素。
else:
prev.next = node
node.next = current
current.prev = node
node.prev = prev
(4)remove要考虑四种情况:有很多元素,有两个元素,有一个元素,有0个元素。一、支持副索引。二、0个元素的话,直接抛出异常属性。三、一个元素的话,头部尾部全部为空。
4)改变成为容器;
class SingleNode:
def __init__(self,value,next = None,prev = None):
self.value = value
self.next = next
self.prev = prev
def __repr__(self):
return "{}<=={}==>{}".format(
self.prev.value if self.prev else None,
self.value,
self.next.value if self.next else None)
class LinkList:
def __init__(self):
self.head = None
self.tail = None
self.items = []
def append(self,value):
node = SingleNode(value)
tail = self.tail
if tail is None:
# self.tail = node
self.head = node
else:
tail.next = node
node.prev = tail
self.tail = node
self.items.append(node)
return self
def pop(self):
if self.tail is None: #empty
raise Exception('empty')
oldtail = self.tail
if self.head is self.tail:
self.tail = None
self.head = None
else:
prev = oldtail.prev
prev.next = None
self.tail = prev
oldtail.prev = None
self.items.pop()
return oldtail
def insert(self,index,value,):
if index < 0:
raise IndexError('wrong index{}'.format(index))
current = None
for i,conde in enumerate(self.iternodes()):
if index == i:
current = conde
break
else: ###超过当前迭代。
self.append(value)
# self.items.append(value)
return
#找到内部插入点
prev = current.prev
next = current.next
node = SingleNode(value)
if index == 0: #在头部插入
node.next = current
current.prev = node
self.head = node
else:
current.prev = node
node.next = current
prev.next = node
node.prev = prev
self.items.insert(index,node)
def remove(self,index):
if index < 0 :
raise IndexError('Wrong index{}'.format(index))
if self.tail is None: #0个元素
raise Exception('empty')
if self.head is self.tail:#一个元素
node = self.head
self.head = None
self.tail = None
del node
self.items.pop()
return 0
current = None
for i,node in enumerate(self.iternodes()):
if index == i:
current = node
break
else:
self.pop()
self.items.pop()
return
prev = current.prev
next = current.next
if index == 0:
next.prev = None
self.head = next
else: #中间的处理
prev.next = next
next.prev = prev
del current
self.items.pop(index)
return index
# def iternodes(self):
# current = self.head
# while current:
# yield current
# current = current.next
#
def iternodes(self,revese=False):
current = self.head
while current:
yield current
current =self.tail if revese else current.next
思路:改变容器化就是利用技巧和原来的保持一致就行了。
(1)容器里面设置一个属性self.items = []初始化一个列表。
(2)Append方法里面和原来的方法一致,self.items.append(node)
(3)Pop方法里面和原方法一样,也是尾部增加一个self.items.pop()尾部弹出一个元素。
(4)insert方法里面,超出索引的话,直接尾部增加元素,采用self.items.append(value).找到尾部插入点:self.items.insert(index,node)
(5)remove方法,如果是一个元素的话,也是采用尾部弹出的方法,self.items.pop().多个元素的话直接就是self.items.pop(index)
1)使用getitem查找元素
class SingleNode:
def __init__(self,value,next = None,prev = None):
self.value = value
self.next = next
self.prev = prev
def __repr__(self):
return "{}<=={}==>{}".format(
self.prev.value if self.prev else None,
self.value,
self.next.value if self.next else None)
class LinkList:
def __init__(self):
self.head = None
self.tail = None
self.items = []
def append(self,value):
node = SingleNode(value)
tail = self.tail
if tail is None:
# self.tail = node
self.head = node
else:
tail.next = node
node.prev = tail
self.tail = node
self.items.append(node)
return self
def pop(self):
if self.tail is None: #empty
raise Exception('empty')
oldtail = self.tail
if self.head is self.tail:
self.tail = None
self.head = None
else:
prev = oldtail.prev
prev.next = None
self.tail = prev
oldtail.prev = None
self.items.pop()
return oldtail
def insert(self,index,value,):
if index < 0:
raise IndexError('wrong index{}'.format(index))
current = None
for i,conde in enumerate(self.iternodes()):
if index == i:
current = conde
break
else: ###超过当前迭代。
self.append(value)
# self.items.append(value)
return
#找到内部插入点
prev = current.prev
next = current.next
node = SingleNode(value)
if index == 0: #在头部插入
node.next = current
current.prev = node
self.head = node
else:
current.prev = node
node.next = current
prev.next = node
node.prev = prev
self.items.insert(index,node)
def remove(self,index):
if index < 0 :
raise IndexError('Wrong index{}'.format(index))
if self.tail is None: #0个元素
raise Exception('empty')
if self.head is self.tail:#一个元素
node = self.head
self.head = None
self.tail = None
del node
self.items.pop()
return 0
current = None
for i,node in enumerate(self.iternodes()):
if index == i:
current = node
break
else:
self.pop()
self.items.pop()
return
prev = current.prev
next = current.next
if index == 0:
next.prev = None
self.head = next
else: #中间的处理
prev.next = next
next.prev = prev
del current
self.items.pop(index)
return index
# def iternodes(self):
# current = self.head
# while current:
# yield current
# current = current.next
#
def iternodes(self,revese=False):
current = self.head
while current:
yield current
current =self.tail if revese else current.next
# def __len__(self):
# return len()
#
# def __setitem__(self, key, value):
# self.items[key] = value
#
# def __getitem__(self, index):
# return self.items[index]
def getitem(self,index):
if index < 0:
raise Exception('wrong index{}'.format(index))
current = None
for i,node in enumerate(self.iternodes()):
if i == index:
return self.items[index]
else:
return self.items[-1]
ll = LinkList()
ll.append(2).append(3).append(4).append(5)
for i in ll.iternodes():
print(i)
print('-------------')
ll.pop()
ll.pop()
for i in ll.iternodes():
print(i)
ll.insert(5,5)
ll.insert(100,100)
for i in ll.iternodes():
print(i)
print('++++++++++')
ll.remove(1)
for i in ll.iternodes():
print(i)