Python 新手刚学链表,做了一个“捣浆糊”版的单链表类

简介: Python 新手刚学链表,做了一个“捣浆糊”版的单链表类

链表定义


链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。


单向链表,又叫单链表、单向表,是由一个个节点组成的,每个节点是一种信息集合,包含元素本身以及下一个节点的地址。节点在内存中是非连续分布的,在程序运行期间,根据需要可以动态的创建节点,这就使得链表的长度没有逻辑上的限制,有限制的是堆的大小。


在单向链表中,每个节点中存储着下一个节点的地址。基于单向链表,在每个节点内增加一个前驱节点的地址,这就是所谓的双向链表,又叫双链表、双向表。


如单向链表的尾节点指针指向头节点,即为循环单向链表。


如单向链表的头、尾节点指针互相指,即为循环双向链表。


2021072715190876.png

指针是C/C++等语言中的概念,也就是内存地址;python中没有指针,也很少直接操作地址。

在 python 这一类没有指针的语言里,很难真正体现出链表的精髓,只能模拟出一个静态链表来意思意思。



单向表类的实现


模仿python中二叉树的节点Node类,把左右子树的left,right换成一个Next,就有点像了。因为刚学python不久功力有限,愣是用字符串和列表,伪实现了一个单向表的类:

class Node():
    def __init__(self,val=None,Next=None):
        self.val = val
        self.Next = Next
    def __repr__(self):
        return 'listNode('+str(self.val)+')'
    def __getitem__(self, slices):
        list = self.values()
        return list[slices]
    def is_empty(self):
        return self.val is None
    def value(self):
        return self.val
    def values(self):
        head = self
        t = 'head'
        r = []
        while eval(t) is not None:
            r.append(eval(t).val)
            t+='.Next'
        return r
    def size(self):
        if self.is_empty():
            return 0
        r = self.values()
        return len(r)
    def append(self, node):
        if self.val is None:
            self.val = node
            return
        head = self
        t = 'head'
        while eval(t) is not None:
            t+='.Next'
        exec(f'{t}=Node({node})')
    def pop(self):
        head = self
        if head.size() < 2:
            res = head.val
            head.val = None
            return res
        t = 'head'
        while eval(t).Next is not None:
            t+='.Next'
        res = eval(t).val
        exec(f'{t}=None')
        return res
    def pprint(self):
        r = self.values()
        r = [i.join(["'"]*2) if type(i) is str else str(i) for i in r]
        print('->'.join(r))


之所以说是“伪实现”,因为根本就是用字符串和列表模拟出来的效果。尽管这个类如此不入门,有点傻傻的,用上海咸话的讲法,称之为“捣浆糊”。但还是能完成不少功能的。呈上测试代码,如下:



1. 逐个赋值

>>> LinkedList = Node()
>>> LinkedList.is_empty()
True
>>> LinkedList.size()
0
>>> LinkedList = Node(1)
>>> LinkedList.is_empty()
False
>>> LinkedList.size()
1
>>> LL = LinkedList
>>> LL.Next = Node(2)
>>> LL
listNode(1)
>>> LL.Next
listNode(2)
>>> LL.val
1
>>> LL.Next.val
2
>>> LL.value()
1
>>> LL.Next.value()
2
>>> LL.values()
[1, 2]
>>> 
>>>
>>> LinkedList = Node()
>>> LinkedList = Node(1,Node(2))
>>> linked = Node(1,Node(2))
>>> linked.Next.Next = Node('3',Node(4))
>>> linked.pprint()
1->2->'3'->4
>>> linked.values()
[1, 2, '3', 4]
>>> 

注:此链表类允许数字、字符串混装



2.追加append()和弹出pop()

>>> single = Node(1,Node(2,Node(3,Node(4,Node(5)))))
>>> single.pprint()
1->2->3->4->5
>>> single.append(6)
>>> single.pprint()
1->2->3->4->5->6
>>> single.pop()
6
>>> single.pop()
5
>>> single.pprint()
1->2->3->4
>>> 


3. 嵌套赋值或用循环赋值

>>> single = Node(1,Node(2,Node(3,Node(4,Node(5)))))
>>> single.size()
5
>>> single.values()
[1, 2, 3, 4, 5]
>>> 
>>> 
>>> link = Node()
>>> for i in range(1,9):
  link.append(i)
>>> link.pprint()
1->2->3->4->5->6->7->8
>>> 



4. 索引和切片

>>> lList = Node()
>>> t = [lList.append(i) for i in range(1,9)]
>>> lList.pprint()
1->2->3->4->5->6->7->8
>>> lList[:]
[1, 2, 3, 4, 5, 6, 7, 8]
>>> lList[::-1]
[8, 7, 6, 5, 4, 3, 2, 1]
>>> lList[0]
1
>>> lList[1]
2
>>> lList[7]
8
>>> lList[-1]
8
>>> lList[-2]
7
>>> lList[-8]
1
>>> lList[:5]
[1, 2, 3, 4, 5]
>>> lList[5:]
[6, 7, 8]
>>> lList[::2]
[1, 3, 5, 7]
>>> lList[1::2]
[2, 4, 6, 8]
>>> 

注:链表一般是不带索引功能的,这里用类的内置方法__getitem__(self, slices)来强加一个索引和切片的功能,完全是继承了列表的功能。



5. 删除和插入

>>> single = Node(1,Node(2,Node(3,Node(4,Node(5)))))
>>> single.pprint()
1->2->3->4->5
>>> single.Next.Next = single.Next.Next.Next
>>> single.pprint()
1->2->4->5
>>> 
>>> tmp = single.Next.Next
>>> single.Next.Next = Node(6)
>>> single.Next.Next.Next = tmp
>>> single.pprint()
1->2->6->4->5
>>> 


注:删除和插入方法没有直接写进这个类里,但也能用代码实现类似操作。

单链表真实的删除和插入操作过程,如下所示:

20210727204024308.png



6. 单链表的反转(倒序)

>>> linked = Node()
>>> assign = [linked.append(i) for i in range(1,9)]
>>> linked.pprint()
1->2->3->4->5->6->7->8
>>> tmp,linked = linked,Node()
>>> while not tmp.is_empty():
  linked.append(tmp.pop())
>>> linked.pprint()
8->7->6->5->4->3->2->1
>>> 

注:用循环反复追加append原链表的pop()返回值完成倒序操作。

 

“捣浆糊”版的链表类就到此结束吧,准备下一篇再来重写一个进阶一点的链表类   ^_^

目录
相关文章
|
12天前
|
存储 缓存 Python
深入了解python中元类和连接符的用法
【6月更文挑战第20天】本文介绍包括`type`的多重用途,内建函数的常量,模块属性,类继承的概念,元类的工作原理,可哈希对象的重要性,加权平均值的计算,以及如何找到两个列表的交集。
57 5
深入了解python中元类和连接符的用法
|
6天前
|
算法 Python
Python新式类和经典类
Python新式类和经典类
|
8天前
|
安全 测试技术 Python
Python类中的Setter与Getter:跨文件调用的艺术
Python类中的Setter与Getter:跨文件调用的艺术
13 3
|
17天前
|
Python
Python 高质量类编写指南
Python 高质量类编写指南
40 15
|
9天前
|
SQL 分布式计算 大数据
MaxCompute产品使用问题之建了一个python 的 UDF脚本,生成函数引用总是说类不存在,是什么导致的
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
13天前
|
存储 程序员 Python
Python类属性与实例属性详解
Python 中区分类属性和实例属性的设计是为了满足不同的需求和使用场景。这种区分使得代码更加灵活、清晰,并且能够提供更好的封装性和可维护性。类属性用于表示与整个类相关的数据,而实例属性则用于表示每个实例的特定信息。这样,我们可以将关注点分离开来,使得代码更易于理解、维护和扩展。在实际应用中,我们可以根据具体的情况,选择适当的属性类型来组织和管理代码。
14 1
|
14天前
|
存储 搜索推荐 Python
【随手记】python语法:类属性和实例属性
【随手记】python语法:类属性和实例属性
24 1
|
14天前
|
Java 索引 Python
深入理解 Python 类中的各种方法
在 Python 中,类不仅仅是对象的蓝图,它还提供了多种方法,使我们能够以更灵活和强大的方式编写代码。本文将详细介绍 Python 类中的各种方法,包括实例方法、类方法、静态方法、特殊方法等,并通过示例展示它们的用法和区别。
|
17天前
|
存储 Python 索引
【Python编程挑战】:单链表实现技巧与最佳实践
【Python编程挑战】:单链表实现技巧与最佳实践
|
18天前
|
算法 Java API
Python零基础入门-9类
Python零基础入门-9类