Python 链表(Link)实现

目录

  • 链表的意义
  • 基本操作
    • 初始化
    • str函数打印链表
    • 在链表尾部添加一个值(尾插法)
    • 在链表任意部位添加一个值
    • 查找链表中的值
    • 返回链表长度
    • 删除某一项
  • 尾声
  • 全部代码
  • 声明

链表的意义

链表(link) 是一种长度几乎不受限制的数据结构。不同于列表,链表各个节点的内存位置不是连续的。
比如:
你的电脑内存被病毒占满了(真是一种神奇的病毒),只有3号内存、5号内存、6号内存、21号内存、92号内存为空。而你制作的杀毒软件必须占用4个内存空间(也是一种神奇的杀毒软件),如果你不知道链表,而把所有程序装在一个列表中,那么因为列表两个值的内存是连续的,所以,杀毒软件的安装无法成功(列表最长只能占2个内存,安装在5号内存和6号内存中)。这时,链表来了:

链表: 我可以成功安装杀毒软件。
你:怎么办?
链表:在我这里,各个节点的内存位置不是连续的。
你:你是怎么做到的?
链表:首先,我每一个节点都由两部分构成:数据域和指针域。前一个指针域指向下一个值。
你:哦,让我思考思考。

终于, 在链表的帮助下,你的电脑恢复了正常。

基本操作

我相信,你一定很想知道你是怎么实现的链表,修复你的电脑——你对刚才发生的事情一无所知(画外音:那当然,刚才的事是你编的。)。因为,在python中,并不存在指针类型

初始化

我们知道,链表的各个节点的内存位置不是连续的,每个节点由数据域和指针域构成,所以,在__init__函数中,我们定义两部分

class Link:                                      # 创建一个link类
    def __init__(self, data=None, p=None):
        self.data = data                         # 添加数据域
        self.p = p                               # 添加指针域

str函数打印链表

你说:那我依然不认为这个链表各个节点的内存位置不是连续的。别急,慢慢来。
在这之后,我需要用__str__函数打印出整个链表,那么,我直接让一个节点的指针域等于下一个节点,再通过一点点递归算法,打印出链表。

    def __str__(self):                           # 返回整个链表
        return '{} -> {}'.format(self.data, self.p)

在链表尾部添加一个值(尾插法)

重头戏来了,许多人问:“作者,什么叫:‘我直接让一个节点的指针域等于下一个节点’啊?我觉得指针域就是None呀。”
作者:格局小了。
我们先来看,如何在链表尾部添加一个值。按照我“直接让一个节点的指针域等于下一个节点”的思路,添加值时,我们只要把最尾部的节点的指针域改为需要连接的链表。
Python 链表(Link)实现_第1张图片

至于如何找到最尾部的节点,我们用一个小小的递归……

    def __add__(self, other):
        tail = self.p
        if not tail:           # 链表节点的指针域为空
            self.p = other     # 把最尾部的节点的指针域改为用于连接的链表
        else:
            tail.__add__(other)                  # 递归

在链表任意部位添加一个值

在链表的操作中,我们当然不能只在尾部插入一个值,不然就快成栈了。那么,insert函数出现了。
首先,通过for循环找到插入链表位置的节点,然后,把用于插入节点的指针域设为插入链表位置节点的指针域,再把插入链表位置节点的指针域设为用于的插入节点
Python 链表(Link)实现_第2张图片

    def insert(self, other, index):
        try:                               # 尝试索引,报错时抛出索引错误
            value = self
            for cnt in range(index):
                value = value.p
            other.p = value.p
            value.p = other
        except AttributeError:
            raise IndexError('link index out of range')

查找链表中的值

此时,许多人的电脑都感染上的病毒。只可惜,你把杀毒软件的源文件删了,你必须从电脑中找到杀毒软件的第二个值,那是安装程序,那么,怎么办?
你:凉拌。
……

首先,这个好办。我们知道,链表节点由数据域和指针域构成。那么,先通过一个for循环,找到第二个节点

    def serch(self, index):
        value = self
        for cnt in range(index):
            value = value.p           #找到下一个节点

然后返回该节点的数据域

        return value.data

有一种可能:如果索引超出链表长度。这时,因为最后一个节点的指针域不在存在指针域,会抛出AttributeError错误。所以,套上一个try语句并抛出IndexError错误。··

    def serch(self, index):
        try:
            value = self
            for cnt in range(index):
                value = value.p
            return value.data
        except AttributeError:
            raise IndexError('link index out of range')

终于,其他人的电脑也恢复了正常。

返回链表长度

病毒又出现了。这次,如果不管它,病毒会在48小时内消失,如果使用了杀毒软件,病毒会在5分钟内消失。但如果内存被占满了,电脑就崩了。
然后,Tom的电脑也中了病毒,只有三个内存为空,此时,假如安装软件照常安装杀毒软件,他的电脑必死无疑。当然,病毒不会全占满电脑内存。
此时,你察觉到,必须对剩余内存和链表长度进行比较。

我们需要检查链表长度,用__len__函数即可。先得到该链表的__str__值,再用split()函数分开每一项,通过len()返回长度(因为包括了尾节点的指针域——None,需要返回长度减1)。

    def __len__(self):
        return len(str(self).split(' -> ')) - 1

删除某一项

可恶至极,病毒又来了。这次,它会抓住杀毒软件第三个值的漏洞,删除杀毒软件。你必须删掉链表第三项。
你:我不干啦!!!!!!!!!!!

非常简单,删除某个节点时,我们只要把它前一个节点的指针域指向被删除节点的指针域。
Python 链表(Link)实现_第3张图片

    def remove(self, index):
        try:
            value = self
            for cnt in range(index - 1):
                value = value.p
            value.p = value.p.p
        except AttributeError:
            raise IndexError('link index out of range')

尾声

终于,你制作了一个看似完美的杀毒软件
店小二:完了,病毒把所有内存都占满了!!!!

全部代码

下载代码源文件

class Link:                                           # 创建一个link类
    def __init__(self, data=None, p=None):
        self.data = data                              # 添加数据域
        self.p = p                                    # 添加指针域

    def __str__(self):                                # 返回整个链表
        return '{} -> {}'.format(self.data, self.p)

    def __len__(self):
        return len(str(self).split(' -> ')) - 1

    def __add__(self, other):
        tail = self.p
        if not tail                              # 链表节点的指针域为空
            self.p = other     # 把最尾部的节点的指针域改为用于连接的链表
        else:
            tail.__add__(other)                  # 递归

    def insert(self, other, index):
        try:
            value = self
            for cnt in range(index):
                value = value.p
            other.p = value.p
            value.p = other
        except AttributeError:
            raise IndexError('link index out of range')

    def serch(self, index):
        try:
            value = self
            for cnt in range(index):
                value = value.p
            return value.data
        except AttributeError:
            raise IndexError('link index out of range')


    def remove(self, index):
        try:
            value = self
            for cnt in range(index - 1):
                value = value.p
            value.p = value.p.p
        except AttributeError:
            raise IndexError('link index out of range')

声明

本文为原创,连载须注明出处。
(本故事情节虚构,如有雷同,纯属巧合)

你可能感兴趣的:(Python,链表,python,类)