Python实现链表

2023-11-15

由一个等号引起的思考

链表是由一个个被系统随机分配地址的结点们通过指针进行相连,以c++为例子,在写链表的时候可以使用结构体进行实现:

struct node
{
    ElemType value;
    ndoe * next;
};

*next指向下一个结点的地址,那么在Python中是怎么指向下一个结构体的地址呢?
这就不得不提到等号。在Python中,如果要交换两个变量的值,那么可以这样写:

a = 10
b = 20
a,b = b,a

问题来了:为什么在Python中可以写成a,b=b,a,而其它语言进行变量值的交换则为(以c++为例子)tmp=b,b=a,a=tmp?如果使用id查看交换前后a、b的地址话,那么会发现一个现象:地址是不变的!
这就不得不说Python的机制了:在Python中,一切皆为对象。
在这里插入图片描述
在这里插入图片描述

  • Python中定义变量不需要指明变量类型,这是因为变量为一个对象,存储该对象的内存中封装了变量的类型、地址、值。
  • Python中的=不仅仅是赋值号,也可以是指针的赋值运算(比如:指针指向一个地址,就用=进行实现,最明显的例子就是开头提的问题)。
    所以上述两点就解决了在Python中怎么指向下一个结点地址的问题。

链表

链表是线性表,满足(除头尾结点外)有唯一的一个前驱和唯一的一个后继

单链表

单链表是链表最简单的形式,每个结点有两个域,一个是值域,另一个是指针域,指针域指向下一个结点的地址,最后一个结点的指针域为空。单链表的实现有两种方法,一种是带头结点,一种是不带头结点,图中所示为不带头结点的单链表。
在这里插入图片描述
单链表中结点的定义

class SingleNode(object):
    def __init__(self,item):
        self.item = item
        self.next = None

单链表的操作
在这里插入图片描述
Python代码实现:

class Node(object):
    """结点"""
    def __init__(self, elem):
        self.elem = elem
        self.next = None


class SingleLinkList(object):
    """单链表"""
    def __init__(self, Node = None):
        self.__head = Node
    def is_empty(self):
        return self.__head == None
    def length(self):
        cur = self.__head
        cnt = 0
        while cur != None:
            cnt += 1
            cur = cur.next
        return cnt
    def travel(self):
        cur = self.__head
        while cur != None:
            print(cur.elem, end=' ')
            cur = cur.next
    def add(self, item):
        """插入头结点"""
        node = Node(item)
        node.next = self.__head
        self.__head = node
    def append(self, item):
        """插入尾节点"""
        node = Node(item)
        if self.is_empty():
            self.__head=node
        else:
            cur = self.__head

            while cur.next != None:
                cur = cur.next
            cur.next = node

    def insert(self, pose, item):
        """在指定位置插入结点"""
        if pose<=0:
            self.add(item)
        elif pose >= self.length()-1:
            self.append(item)
        else:
            node = Node(item)
            cnt = 1
            cur = self.__head
            pre = None
            while cnt != pose:
                pre = cur
                cur = cur.next
                cnt += 1
            cur = node
            cur.next = pre.next
            pre.next = cur
    def remove(self, item):
        if self.is_empty():
            print("链表为空,删除操作错误!")
        else:
            cur = self.__head
            pre = None
            while cur.elem != item:
                pre = cur
                cur = cur.next
            pre.next = cur.next0
            print("删除成功!")
            del cur
    def search(self, item):
        cur = self.__head
        while cur.elem != item:
            cur = cur.next
        print("查找成功")
        pass

if __name__ == "__main__":
    l = SingleLinkList()
    print(l.is_empty())
    print(l.length())
    l.append(1)
    print(l.is_empty())
    print(l.length())
    l.add(0)
    l.append(2)
    l.append(3)
    l.append(4)
    l.append(5)

    l.append(6)
    l.insert(255, 100)
    l.travel()

其中,从函数的实现中可以看出来各个函数的时间复杂度:

  • search(item), 查找某一个元素o(n)
  • insert(position,item), 特定位置插入元素o(n)
  • length(), 链表长度o(n)
  • append(item), 尾部插入o(1)
  • add(item), 头插入o(1)
  • remove(item), 删除元素o(n)
  • travel(), 遍历链表o(n)

双链表

双链表就是在结点中增加一个指针域,该指针域指向该结点的前驱结点。头结点没有前驱结点、尾节点没有后驱结点。
双链表的操作:

  • is_empty(),判断链表是否为空 ,o(n)
  • length(),返回链表长度,o(n)
  • travel(),遍历链表,o(n)
  • add(item),在头部添加一个结点,o(1)
  • append(item),在尾部添加一个结点,o(1)
  • insert(position,item),在指定位置添加结点,o(n)
  • remove(item),删除值为item的第一个结点,o(n)
  • search(item),查找结点是否存在,o(n)
    双链表示意图:
    在这里插入图片描述
    双链表中在指定位置插入结点:

在这里插入图片描述
注意该操作,操作4进行之前必须要进行操作3,否则会丢失数据
删除元素:
在这里插入图片描述

双链表的实现:

class Node(object):
    """双向链表节点"""
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None


class DLinkList(object):
    """双向链表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head == None

    def length(self):
        """返回链表的长度"""
        cur = self._head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历链表"""
        cur = self._head
        while cur != None:
            print cur.item,
            cur = cur.next
        print ""

    def add(self, item):
        """头部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空链表,将_head指向node
            self._head = node
        else:
            # 将node的next指向_head的头节点
            node.next = self._head
            # 将_head的头节点的prev指向node
            self._head.prev = node
            # 将_head 指向node
            self._head = node

    def append(self, item):
        """尾部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空链表,将_head指向node
            self._head = node
        else:
            # 移动到链表尾部
            cur = self._head
            while cur.next != None:
                cur = cur.next
            # 将尾节点cur的next指向node
            cur.next = node
            # 将node的prev指向cur
            node.prev = cur



    def search(self, item):
        """查找元素是否存在"""
        cur = self._head
        while cur != None:
            if cur.item == item:
                return True
            cur = cur.next
        return False

单向循环链表

当单向链表的尾节点不指向None,而是指向头结点的时候,那么就构成了一个单向循环链表。
在这里插入图片描述
单循环链表中一些操作的时间复杂度

  • is_empty(),判断链表是否为空 ,o(n)
  • length(),返回链表长度,o(n)
  • travel(),遍历链表,o(n)
  • add(item),在头部添加一个结点,o(n)
  • append(item),在尾部添加一个结点,o(1)
  • insert(position,item),在指定位置添加结点,o(n)
  • remove(item),删除值为item的第一个结点,o(n)
  • search(item),查找结点是否存在,o(n)

单循环链表代码实现:

class Node(object):
    """节点"""
    def __init__(self, item):
        self.item = item
        self.next = None


class SinCycLinkedlist(object):
    """单向循环链表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head == None

    def length(self):
        """返回链表的长度"""
        # 如果链表为空,返回长度0
        if self.is_empty():
            return 0
        count = 1
        cur = self._head
        while cur.next != self._head:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历链表"""
        if self.is_empty():
            return
        cur = self._head
        print cur.item,
        while cur.next != self._head:
            cur = cur.next
            print cur.item,
        print ""


    def add(self, item):
        """头部添加节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            #添加的节点指向_head
            node.next = self._head
            # 移到链表尾部,将尾部节点的next指向node
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            cur.next = node
            #_head指向添加node的
            self._head = node

    def append(self, item):
        """尾部添加节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            # 移到链表尾部
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            # 将尾节点指向node
            cur.next = node
            # 将node指向头节点_head
            node.next = self._head

    def insert(self, pos, item):
        """在指定位置添加节点"""
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 0
            # 移动到指定位置的前一个位置
            while count < (pos-1):
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """删除一个节点"""
        # 若链表为空,则直接返回
        if self.is_empty():
            return
        # 将cur指向头节点
        cur = self._head
        pre = None
        # 若头节点的元素就是要查找的元素item
        if cur.item == item:
            # 如果链表不止一个节点
            if cur.next != self._head:
                # 先找到尾节点,将尾节点的next指向第二个节点
                while cur.next != self._head:
                    cur = cur.next
                # cur指向了尾节点
                cur.next = self._head.next
                self._head = self._head.next
            else:
                # 链表只有一个节点
                self._head = None
        else:
            pre = self._head
            # 第一个节点不是要删除的
            while cur.next != self._head:
                # 找到了要删除的元素
                if cur.item == item:
                    # 删除
                    pre.next = cur.next
                    return
                else:
                    pre = cur
                    cur = cur.next
            # cur 指向尾节点
            if cur.item == item:
                # 尾部删除
                pre.next = cur.next

    def search(self, item):
        """查找节点是否存在"""
        if self.is_empty():
            return False
        cur = self._head
        if cur.item == item:
            return True
        while cur.next != self._head:
            cur = cur.next
            if cur.item == item:
                return True
        return False

if __name__ == "__main__":
    ll = SinCycLinkedlist()
    ll.add(1)
    ll.add(2)
    ll.append(3)
    ll.insert(2, 4)
    ll.insert(4, 5)
    ll.insert(0, 6)
    print "length:",ll.length()
    ll.travel()
    print ll.search(3)
    print ll.search(7)
    ll.remove(1)
    print "length:",ll.length()
    ll.travel()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python实现链表 的相关文章

  • 第19章:python自动化——ChromeOptions与WebUI实操

    目录 一 ChromeOptions设置项 二 WebUI实操 一 ChromeOptions设置项 浏览器在启动之初 如果需要对浏览器进行一些特定内容的定义 可以直接通过浏览器的options类来实现相对应的配置内容 不同的浏览器有不同的
  • Vue中如何配置自定义路径别名

    Vue中如何配置自定义路径别名 在我们日常开发中 常常会导入一些模块或者组件 如果采用相对路径的方式 import uEditor from components tools 会显得臃肿 多余 如果引用稍有差错就会出现 404的报错 不优雅

随机推荐

  • A Survey on Large Language Model based Autonomous Agents

    本文是LLM系列的文章 针对 A Survey on Large Language Model based Autonomous Agents 的翻译 基于大模型的自动agents综述 摘要 1 引言 2 基于LLM的自动代理构建 3 基于
  • 学网络安全都是一群什么人?

    大家好呀 我是知了姐 又是一期学员故事栏目 3月下旬知了堂信安方向开新班 知了姐跟着去采访 了解到新学员们的求学故事 嘿你别说 虽然大家出身专业不同 经历背景不同 如今却在同一个地点相遇 加入到知了堂这个大家庭 不同专业 年龄的他们 为什么
  • 格式工厂5.10.0版本安装

    目前格式工厂有很多 大多都可以进行视频转换 之前遇到一个用ffmpeg拉流保存的MP4在vlc和迅雷都无法正常播放的问题 发现视频长度不对 声音也不对 最后换到了格式工厂的格式播放器是可以正常播放的 格式工厂下载之家的地址 https ww
  • OSG for Android新手教程系列(二)——项目配置

    在上一篇教程中 主要介绍了如何把OSG源代码编译成为能够在Android项目下使用的函数库 在这一篇教程中 我将针对如何在自己的Android项目中配置OSG函数库进行详细讲解 现阶段网上关于OSGfor Android的配置方式教程有很多
  • 用户登录的详细流程(二)JWT生成token登录

    JWT生成token登录 1 jwt的构成 1 header 2 payload 3 signature 2 token的登陆原理 3 在实际中如何应用token 1 设置token的生成代码 2 如何从token中获取有用的信息 3 验证
  • 汇编程序设计与计算机体系结构软件工程师教程笔记:总结

    汇编程序设计与计算机体系结构 软件工程师教程 这本书是由Brain R Hall和Kevin J Slonka著 由爱飞翔译 中文版是2019年出版的 个人感觉这本书真不错 书中介绍了三种汇编器GAS NASM MASM异同 全部示例代码都
  • EC11旋转编码器、stm32f103驱动程序

    1 EC11手册的要点 注意 旋转的速度 RC滤波 手册中推荐的电路 已含有RC滤波 输出波形特点 2 硬件电路 加上RC滤波电路 做法是两个端点都采用10pF电容接地 10K 电阻接VCC 实测100pF电容也行 用示波器看看波形有无噪声
  • 无向图的遍历-BFS与DFS

    一 理论部分 无向图的遍历可用深度搜索 DFS 与广度搜索 BFS 深度搜索的基本方式是由图的一个节点1出发然后随机选一个与其相邻的节点2 接着在选择一个与其相邻的节点3 当一条路遍历完后再选择最近一个遍历过的 且相邻节点有未遍历过的节点
  • Unhandled kernel unaligned access问题记录

    调试新驱动出现如下打印 内核未对齐访问 765 810527 Unhandled kernel unaligned access 1 765 815483 CPU 0 PID 120 Comm insmod Tainted G O 3 10
  • 实习需求-sessionStorage实现对话框只弹出一次

    文章目录 背景 实现思路 实现代码 背景 某功能页面下线 需要提供一个弹窗来提示用户该功能已下线 要求 弹窗只是在进入该页面的时候显示 切换其他的页面再回到该页面 弹窗不显示 即弹窗只在第一次点击该功能页面出现 实现思路 弹窗 elemen
  • QT实战——LCDNumber计数器

    需求 通过LCDNumber进行计数 间隔时间1s 可以重置 暂停 widget h ifndef WIDGET H define WIDGET H include
  • python自动点击小程序

    猜你感兴趣 使用Pyqt5玩转ChatGpt 内网文件共享服务 快速搭建私有pip镜像源 python设计模式 创建型模式 docker搭建私有git服务器 项目备份和迁移 redis持久化方案 被测点击界面 新建counter html添
  • 获取电商网站主图和详情图的浏览器插件

    介绍 搞图宝 专门获取各大电商平台详情页面主图和详情图的浏览器插件 现已支持京东 京东国际 淘宝 天猫 coupang 1688 naver gmarket alibaba 兰亭集势 谷歌浏览器下载地址 Google Chrome 网络浏览
  • SPI Flash芯片W25Q32英文版数据手册解读(一)---------引脚功能,工作模式

    W25Q32芯片是一个可以通过SPI 串行外围设备接口 操作的flash存储器 这篇文章备忘和总结一下英文版数据手册的一些解读 有关时序及具体用STC单片机编写程序的内容等下一篇文章 一 芯片引脚功能 我买的是8引脚 SOIC封装的芯片 如
  • MyBatis框架从入门到精通(一)MyBatis概述

    mybatis做为目前国内最为流行的开源orm框架 我们平时在使用时会感受到其带来的诸多便利 但是很少去深入分析 mybatis源码代码量不多 功能丰富 是一个很好的学习样例 本系列文章就和大家一起来学习mybatis框架 本系列笔记根据动
  • PSM+DID

    PSM DID 模型是由倾向得分匹配模型 Propensity Score Matching 以下简称 PSM 和双重差分模型 Differences in Differences 以下简称 DID 结合而成 其中 PSM 负责为受处理的个
  • python求解数字的平均值、方差、中位数

    定义数字输入函数 def getNum nums iNumStr input 请输入数字 回车退出 while iNumStr 当输入为空时 跳出循环 nums append eval iNumStr 在nums列表后加入输入的数字 iNu
  • 微信小程序审核代码提示wx.getLocation暂未配置在app.json中教你如何解决

    今天上传微信小程序代码时遇到的问题 解决方法 在app json里面进行配置 requiredPrivateInfos getLocation 查找官方API接口 原来是这样 我们再去微信公众平台官网 扫码进入我们的小程序服务 找到开发管理
  • 项目代码中参数的管理:mmcv中的Config包&argparse导入参数

    Config 当我们项目的超参数很多时 在文中设定和修改并不方便 这时我们需要项目中所有参数放入一个文件夹中 方便管理和修改 例如 config config py中包含了我们模型需要的所有参数 然后我们使用mmcv包中的Config函数对
  • Python实现链表

    文章目录 由一个等号引起的思考 链表 单链表 双链表 单向循环链表 由一个等号引起的思考 链表是由一个个被系统随机分配地址的结点们通过指针进行相连 以c 为例子 在写链表的时候可以使用结构体进行实现 struct node ElemType