Python 触“类”旁通5|链表类才是单链表的主咖

简介: Python 触“类”旁通5|链表类才是单链表的主咖

20210817204340750.png

有上图可知,其实在《触“类”旁通》系列之前的四篇中,所操作的对象其实一直是节点和节点组成的链式结构,不能算是真正的链表。为此,我们有请单向链表的“主咖”出场:



链表类

1. class List():
2.  def __init__(self, node=None):
3.    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]
>>>   




创建链表副本

1. def copy(self):
2. 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]
>>> 



追加合并

1.     def cat(self, *data):
2.   for val in data:
3.       self.append(val)
4.   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]

点个赞再走!谢啦!!

目录
相关文章
|
1月前
|
索引 Python
python-类属性操作
【10月更文挑战第11天】 python类属性操作列举
17 1
|
1月前
|
Java C++ Python
Python基础---类
【10月更文挑战第10天】Python类的定义
21 2
|
1月前
|
设计模式 开发者 Python
Python类里引用其他类
Python类里引用其他类
|
1月前
|
设计模式 开发者 Python
Python 类中引用其他类的实现详解
Python 类中引用其他类的实现详解
36 1
WK
|
1月前
|
Python
Python类命名
在Python编程中,类命名至关重要,影响代码的可读性和维护性。建议使用大写驼峰命名法(如Employee),确保名称简洁且具描述性,避免使用内置类型名及单字母或数字开头,遵循PEP 8风格指南,保持项目内命名风格一致。
WK
13 0
|
1月前
|
程序员 开发者 Python
深度解析Python中的元编程:从装饰器到自定义类创建工具
【10月更文挑战第5天】在现代软件开发中,元编程是一种高级技术,它允许程序员编写能够生成或修改其他程序的代码。这使得开发者可以更灵活地控制和扩展他们的应用逻辑。Python作为一种动态类型语言,提供了丰富的元编程特性,如装饰器、元类以及动态函数和类的创建等。本文将深入探讨这些特性,并通过具体的代码示例来展示如何有效地利用它们。
37 0
|
1月前
|
Python
Python中的类(一)
Python中的类(一)
|
1月前
|
Python
Python中的类(一)
Python中的类(一)
|
1月前
|
Python
Python中的类(二)
Python中的类(二)
|
1月前
|
开发者 Python
Python类和子类的小示例:建模农场
Python类和子类的小示例:建模农场