
有上图可知,其实在《触“类”旁通》系列之前的四篇中,所操作的对象其实一直是节点和节点组成的链式结构,不能算是真正的链表。为此,我们有请单向链表的“主咖”出场:
链表类
class List():
def __init__(self, node=None):
self.head = node
为了展示和操作方便,需要节点类以及几个最基本的方法协助:
class Node():
def __init__(self, value=None, Next=None):
self.val = value
self.next = Next
if (type(self.next)==Node and self.next.val==None
or type(self.next)!=Node and self.next!=None):
self.next = None
def __repr__(self):
return f'{self.val}->{self.next}'
@property
def values(self):
ret,ptr = [],self
while ptr is not None:
ret.append(ptr.val)
ptr = ptr.next
return ret
def build(*data, split=True):
'''把数据转换成节点链表'''
lst,ret = [],Node()
for val in data:
if type(val) is str:
if not split:
lst.append(val)
continue
if str=='':
continue
try:
num = int(val)
lst.extend([int(_) for _ in val])
except:
lst.extend([_ for _ in val])
elif hasattr(val,'__iter__'):
lst.extend([_ for _ in val])
elif type(val) is Node:
if val is not None:
lst.extend(val.values)
elif type(val) is List:
if val.head is not None:
lst.extend(val.head.values)
else:
lst.append(val)
ret = Node()
for i in lst[::-1]:
ret = Node(i, ret)
return ret
class List():
def __init__(self, *node):
self.head = Node.build(*node)
def __repr__(self):
return f'[{self.head}]'
创建链表
操作链表总得新建一个链表吧,不管是怎样去实现的(方法很原始),总之这样新建链表就是非常方便,并且和内置的顺序列表作个对比,创建和返回值都有几分神似:
>>> List(1,2,3,4,5)
[1->2->3->4->5->None]
>>> List(range(1,11,2))
[1->3->5->7->9->None]>>> list((1,2,3,4,5))
[1, 2, 3, 4, 5]
>>> list(range(1,11,2))
[1, 3, 5, 7, 9]
>>>
以下所有代码都要放在class List()里,由此开始对单链表“主咖”的探索:
链表长度、判断是否为空
def __len__(self):
return self.size()
@property
def length(self):
return self.size()
def is_empty(self):
if self.head.val==None:
return True
else:
return False
def size(self):
ret,ptr = 0,self.head
if ptr.val==None: return 0
while ptr:
ptr = ptr.next
ret += 1
return ret
>>> list1 = List()
>>> list1.is_empty()
True
>>> list1.size()
0
>>> len(list1)
0
>>>
>>> list2 = List(1,2,3,4,5)
>>> list2.is_empty()
False
>>> list2.size()
5
>>> len(list2)
5
>>>
单链表的尾结点
@property
def tail(self):
ptr = self.head
while ptr.next:
ptr = ptr.next
return ptr
# 方法.tail修饰成只读属性,返回尾节点
# 而.head头指针是可修改,因为指向头节点,一般就代表整个单链表
>>> list1 = List()
>>> list1.tail
None->None
>>> list1.head
None->None
>>> list1
[None->None]
>>>
>>> list2 = List(1,2,3,4,5)
>>> list2.tail
5->None
>>> list2.head
1->2->3->4->5->None
>>> list2
[1->2->3->4->5->None]
>>>
创建链表副本
def copy(self):
return List(self.head)
>>> list1 = List(1,2,3)
>>> list2 = list1.copy()
>>> list2.head.val = 0
>>> list2
[0->2->3->None]
>>> list1
[1->2->3->None]
>>> list3 = list1 # 直接赋值相当于只是设置一个指针
>>> list3.head.val = 0
>>> list3
[0->2->3->None]
>>> list1
[0->2->3->None]
>>>
遍历和生成器
@property
def values(self):
if self.is_empty(): return []
ret,ptr = [],self.head
while ptr:
ret.append(ptr.val)
ptr = ptr.next
return ret
def __iter__(self):
ptr = self.head
while ptr:
yield ptr.val
ptr = ptr.next
@property
def items(self):
yield from self.values
yield 语法糖:
yield form iterable object (python 3.3+)
等价于:
for item in iterable:
yield item
>>> list1 = List(range(9))
>>> list1.items
<generator object List.items at 0x0000000002F95270>
>>> lstgen = list1.items
>>> next(lstgen)
0
>>> next(lstgen)
1
>>> next(lstgen)
2
>>> next(lstgen)
3
>>> [i for i in lstgen]
[4, 5, 6, 7, 8]
>>> list1.values
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>>
头部插入
def push(self, data):
if not isinstance(data, List):
data = List(data)
if self.is_empty():
self.head = data.head
else:
ret = data.head
ret.next,self.head = self.head,ret
return self
>>> list1 = List()
>>> list1.push(3)
[3->None]
>>> list1
[3->None]
>>> list1.push(Node(2))
[2->3->None]
>>> list1
[2->3->None]
>>> list1.push(List(1,2,3))
[1->2->3->None]
>>> list1.push(range(5))
[0->1->2->3->None]
>>> list1
[0->1->2->3->None]
>>>
>>> # 只增加一个节点
前插合并
def add(self, *data):
data = List(*data)
if self.is_empty():
self.head = data.head
else:
ptr = data.head
while ptr.next:
ptr = ptr.next
ptr.next,self.head = self.head,data.head
return self
>>> list1 = List()
>>> list1.add(3,4,5)
[3->4->5->None]
>>> list1.add(1,2)
[1->2->3->4->5->None]
>>> list1
[1->2->3->4->5->None]>>> list1 = List(3,4)
>>> list2 = List(1,2)
>>> list1.add(list2)
[1->2->3->4->None]
>>> list1
[1->2->3->4->None]
>>> list2
[1->2->None]
>>>
尾部追加
def append(self, data):
if not isinstance(data, List):
data = List(data)
if self.is_empty():
self.head = data.head
else:
ptr = self.head
while ptr.next:
ptr = ptr.next
ptr.next = data.head
return self
>>> list1 = List(1,2,3)
>>> list1.append(4)
[1->2->3->4->None]
>>> list1.append(5)
[1->2->3->4->5->None]
>>> list1
[1->2->3->4->5->None]
>>>
>>> list2 = List()
>>> list2.append(1)
[1->None]
>>> list2.append(2)
[1->2->None]
>>> list2.append(Node(3,Node(4)))
[1->2->3->4->None]
>>> list2
[1->2->3->4->None]
>>> list1.append(list2)
[1->2->3->4->5->1->2->3->4->None]
>>> list1
[1->2->3->4->5->1->2->3->4->None]
>>>
追加合并
def cat(self, *data):
for val in data:
self.append(val)
return self
>>> list1 = List(1,2,3)
>>> list1.cat(4,5,6,7)
[1->2->3->4->5->6->7->None]
>>> list1
[1->2->3->4->5->6->7->None]
>>> list2 = List()
>>> list2.cat(1,2)
[1->2->None]
>>> list2
[1->2->None]
>>> list2.cat(3,[4,5],range(6,9),List(9,10))
[1->2->3->4->5->6->7->8->9->10->None]
>>> list2
[1->2->3->4->5->6->7->8->9->10->None]
>>>
链表加法
def __add__(self, *data):
self.cat(*data)
return self
def __radd__(self, *data):
self.add(*data)
return self
>>> List()+1+2+3
[1->2->3->None]
>>> (1,2,3)+List()
[1->2->3->None]
>>> list0 = List()
>>> list0 = 0 + list1 + 1 + 2
>>> list0
[0->1->2->None]
>>> list1 = List(1,2,3)
>>> list1 = 0 + list1 + 4 + 5
>>> list1
[0->1->2->3->4->5->None]
>>> list2 = List()
>>> for i in range(6):
list2 += i>>> list2
[0->1->2->3->4->5->None]
>>>
反转链表
def __reversed__(self):
ptr,ret = self.head,List()
while ptr:
ret = ptr.val + ret
ptr = ptr.next
return ret
def reverse(self):
ptr,ret = self.head,List()
while ptr:
ret.push(ptr.val)
ptr = ptr.next
self.head = ret.head
return self
>>> list1 = List(1,2,3)
>>> reversed(list1)
[3->2->1->None]
>>> list1
[1->2->3->None]
>>> list1.reverse()
[3->2->1->None]
>>> list1
[3->2->1->None]>>> list2 = List()
>>> reversed(list2)
[None->None]
>>> list2.reverse()
[None->None]
>>> list2
[None->None]
>>>
数据域的最大(小)值
def nlargest(self):
if self.is_empty():
return None
ptr,ret = self.head,self.head.val
while ptr:
ret = max(ret, ptr.val)
ptr = ptr.next
return ret
def nsmallest(self):
if self.is_empty():
return None
ptr,ret = self.head,self.head.val
while ptr:
ret = min(ret, ptr.val)
ptr = ptr.next
return ret
>>> list1 = List(1,2,3)
>>> list1.nlargest()
3
>>> list1.nsmallest()
1
>>> list2 = List(1,0,2,5,3)
>>> list2.nlargest()
5
>>> list2.nsmallest()
0
>>>
指定数值的节点索引
返回数据域等于指定目标值num的第一个节点的索引号,头节点为0;找到返回索引号,若找不到 find() 返回 -1, index() 报错。
def find(self, num):
if self.is_empty():
return -1
ptr,ret = self.head,-1
while ptr:
ret += 1
if ptr.val == num: break
ptr = ptr.next
else:
ret = -1
return ret
def index(self, num):
error = lambda i:ValueError(f'{i} is not in List')
if self.is_empty():
raise error(num)
ptr,ret = self.head,-1
while ptr:
ret += 1
if ptr.val == num: break
ptr = ptr.next
else:
raise error(num)
return ret
>>> list1 = List(range(1,5))
>>> list1.find(1)
0
>>> list1.find(2)
1
>>> list1.find(5)
-1
>>> list1.find(0)
-1>>> list2 = List(range(6))
>>> list2.index(0)
0
>>> list2.index(5)
5
>>> list2.index(6)
Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
list2.index(9)
File "D:\List0821.py", line 202, in index
raise error(num)
ValueError: 9 is not in List
>>>
指定数值的节点个数
def count(self, value):
if self.is_empty():
return 0
ptr,ret = self.head,0
while ptr:
if ptr.val==value: ret += 1
ptr = ptr.next
return ret
>>> list1 = List(0,1,2,1,0,2,0,3,0,2)
>>> list1.count(0)
4
>>> list1.count(1)
2
>>> list1.count(2)
3
>>> list1.count(3)
1
>>> list1.count(4)
0
>>>
包含和等于
def __contains__(self, data):
if self.is_empty():
return False
if isinstance(data,List):
data = data.head
if isinstance(data,Node):
count = self.find(data.val)+1
if count==0: return False
ptr1,ptr2 = self.head,data
for _ in range(1,count):
ptr1 = ptr1.next
if ptr1 is None: return False
while ptr2:
if ptr1 is None or ptr1.val!=ptr2.val:
return False
ptr1,ptr2 = ptr1.next,ptr2.next
return True
else:
return bool(1 + self.find(data))
def __eq__(self, data):
if not isinstance(data,List):
return False
if data.is_empty():
if self.is_empty(): return True
else: return False
return data in self and self in data
>>> list1 = List(range(1,4));
>>> list2 = List(range(6))
>>> list1 in list2
True
>>> list2 in list1
False
>>> 2 in list1
True
>>> 2 in list2
True
>>> None in list1
False
>>> Node() in list1
False
>>> List() in list1
False
>>> Node(1) in list1
True
>>> List(2) in list1
True
>>> Node(2,Node(3)) in list1
True
>>> List(2,3,4) in list2
True>>> list3 = List(1, 2, 3)
>>> list1 == list2
False
>>> list1 == list3
True
>>> list1 != list2
True
>>> list1 != list3
False
>>> List() == List(1)
False
>>> List() == List()
True
>>> List() == None
False
>>> List() != 1
True
>>>
链表排序
python没提供重载__sorted__()方法,所有暂不支持内建函数sorted(),可能需要重载切片方法后变相来实现它。以下方法.sort()直接交换节点数据域实现,.sorted()排序但不改变自身:
def sort(self):
length = self.size()
for i in range(1, length):
ptr = self.head
for j in range(length - i):
if ptr.val>ptr.next.val:
ptr.val,ptr.next.val = ptr.next.val,ptr.val
ptr = ptr.next
return self
def sorted(self):
if self.size()<2: return self
return List(self.head).sort()
>>> list1 = List(2,1,0,3,4,5,3)
>>> list1.sorted()
[0->1->2->3->3->4->5->None]
>>> list1
[2->1->0->3->4->5->3->None]
>>> list1.sort()
[0->1->2->3->3->4->5->None]
>>> list1
[0->1->2->3->3->4->5->None]
重载链表索引
def __getitem__(self, item):
return self.values[item]
def __setitem__(self, idx, value):
length = self.size()
if idx<0: idx += length
if self.is_empty() or idx+1>length or idx<0:
raise IndexError('List() index out of range.')
if isinstance(value,Node) or isinstance(value,List):
raise TypeError('value type Error')
ptr = self.head
for i in range(idx):
ptr = ptr.next
ptr.val = value
>>> list1 = List(range(1,6))
>>> list1
[1->2->3->4->5->None]
>>> list1[0],list1[2],list1[4]
(1, 3, 5)
>>> list1[-1],list1[-3],list1[-5]
(5, 3, 1)
>>> list1[1] *= 5
>>> list1[3] += 6
>>> list1
[1->10->3->10->5->None]
>>> list1[-1] = 0
>>> list1[-5] = -1
>>> list1
[-1->10->3->10->0->None]
>>> list1[5], list1[-6]
Traceback (most recent call last):
File "<pyshell#62>", line 1, in <module>
list1[5],list1[-6]
File "D:/Python/List0823.py", line 103, in __getitem__
return self.values[item]
IndexError: list index out of range>>> # 上节排序中预计的:有了切片功能就支持sorted()函数,但返回的是普通列表
>>> list2 = List(2,1,0,3,4,5,3)
>>> sorted(list2)
[0, 1, 2, 3, 3, 4, 5]
>>> List(sorted(list2))
[0->1->2->3->3->4->5->None]
>>> list2
[2->1->0->3->4->5->3->None]
>>>
删除头节点或尾节点
def pop(self):
if self.is_empty():
raise IndexError('pop from empty List.')
if self.head.next is None:
ret,self.head = self.head.val,Node()
return ret
ptr = self.head
while ptr.next.next:
ptr = ptr.next
ret,ptr.next = ptr.next.val,None
self = List(self.head)
return ret
def popfront(self):
if self.is_empty():
raise IndexError('pop from empty List.')
ret,ptr = self.head.val,self.head.next
if ptr is None: self.head = Node()
else: self.head = self.head.next
return ret
>>> list1 = List(1,2,3)
>>> list1.pop()
3
>>> list1.pop()
2
>>> list1.pop()
1
>>> list1.pop()
Traceback (most recent call last):
File "<pyshell#84>", line 1, in <module>
list1.pop()
File "D:\List0821.py", line 249, in pop
raise IndexError('pop from empty List.')
IndexError: pop from empty List.
>>> list1 = List(1,2,3)
>>> list1.popfront()
1
>>> list1.popfront()
2
>>> list1.popfront()
3
>>> list1.popfront()
Traceback (most recent call last):
File "<pyshell#89>", line 1, in <module>
list1.popfront()
File "D:\List0821.py", line 262, in popfront
raise IndexError('pop from empty List.')
IndexError: pop from empty List.
>>>
重载索引删除的功能
删除指定索引的节点
def __delitem__(self, index):
length = self.size()
if index<0: index += length
if self.is_empty() or index+1>length or index<0:
raise IndexError('List() index out of range.')
ptr = self.head
if index>0:
for i in range(index-1):
ptr = ptr.next
ptr.next = ptr.next.next
else:
if ptr.next is None: self.head = Node()
else: self.head = self.head.next
return self
delete = __delitem__
>>> list1 = List(1,2,3,4)
>>> list1.delete(-5)
Traceback (most recent call last):
File "<pyshell#115>", line 1, in <module>
list1.delete(4)
File "D:\List0821.py", line 272, in delete
raise IndexError('List() index out of range.')
IndexError: List() index out of range.
>>> list1.delete(0)
[2->3->4->None]
>>> list1.delete(1)
[2->4->None]
>>> list1.delete(-2)
[4->None]
>>> list1.delete(-1)
[None->None]>>> list2 = List(1,2,3,4)
>>> del list2[0]
>>> list2
[2->3->4->None]
>>> del list2[1]
>>> list2
[2->4->None]
>>> del list2
>>> list2
Traceback (most recent call last):
File "<pyshell#113>", line 1, in <module>
list2
NameError: name 'list2' is not defined
>>>
删除指定数值的节点
def remove(self, value):
index = self.find(value)
if index==-1:
raise ValueError('List.remove(x): x not in List')
self.delete(index)
return self
>>> list1 = List(0,1,2,3)
>>> list1.remove(1)
[0->2->3->None]
>>> list1.remove(0)
[2->3->None]
>>> list1.remove(3)
[2->None]
>>> list1.remove(3)
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
list1.remove(3)
File "D:\Python\List0823.py", line 169, in remove
raise ValueError('List.remove(x): x not in List')
ValueError: List.remove(x): x not in List
>>> list1.remove(2)
[None->None]
点个赞再走!谢啦!!
相关文章链接:
本文详细介绍了Python中单链表的实现,包括初始化、遍历、操作(如插入、删除、查找、反转)、排序、计数、包含和比较等功能。通过自定义`classList`类和`Node`类,展示了如何创建、操作和操作单链表,并提供了丰富的示例。文章还涉及了链表的加法、复制、长度计算、头尾节点获取等操作,以及重载了一些内置方法,如`__add__`、`__radd__`、`__contains__`和`__eq__`等。
1606





