10.Python修炼之路【14-链表】2018.05.11

2023-05-16

关键字:单链表、双链表、循环单链表、循环双链表

一、链表

1.为什么需要链表

        顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。

        链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。

2.链表的定义

        链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。

        链表的节点的结构如下:

        


二、单向链表

        单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。


  • 表元素域elem用来存放具体的数据。
  • 链接域next用来存放下一个节点的位置(python中的标识)
  • 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

节点实现

class SingleNode(object):
    """单链表的结点"""
    def __init__(self,item):
        # _item存放数据元素
        self.item = item
        # _next是下一个节点的标识
        self.next = None

单链表的操作

  • is_empty() 链表是否为空
  • length() 链表长度(列表当中有多少个节点)
  • travel() 遍历整个链表
  • add(item) 链表头部添加元素
  • append(item) 链表尾部添加元素
  • insert(pos, item) 指定位置添加元素
  • remove(item) 删除节点
  • search(item) 查找节点是否存在

单链表的实现

class SingleLinkList(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                        # cur初始时指向头节点,相当于游标,用来移动遍历节点
        cur = self._head        # 初始化count为0        count = 0
        # 当前节点不为None时
        while cur != None:
            count += 1
            # 将cur后移一个节点
            cur = cur.next
        return count
        """第二种求链表长度的写法"""
     def length(self):
        """链表长度"""
         # 判断特殊情况,链表是否为空         # 若为空,返回长度为0         if self.is_empty():            return 0         # cur初始时指向头结点,相当于游标,用来移动遍历节点         cur =sel._head
         # 初始化count为1         count = 1        # 当前节点的下一个节点不为None时         while cur.next != None:            count += 1            cur = cur.next        return countdef travel(self):
        """遍历整个链表"""
        # cur初始时指向头结点,相当于游标,用来移动遍历节点                cur = self._head
        while cur != None:
            print (cur.item,end=" ")# end 表示不换行
            cur = cur.next
        print ""

头部添加元素

    def add(self, item):
        """头部添加元素"""
        # 先创建一个保存item值的节点
        node = SingleNode(item)
        # 将新节点的链接域next指向头节点,即_head指向的位置
        node.next = self._head
        # 将链表的头_head指向新节点
        self._head = node

尾部添加元素

    
def append(self, item):
        """尾部添加元素"""
        node = SingleNode(item)
        # 先判断链表是否为空,若是空链表,则将_head指向新节点
        if self.is_empty():另一种写法 if self._head == None:
            self._head = node
        # 若不为空,则找到尾部,将尾节点的next指向新节点
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node
指定位置添加元素

    # pos在指定位置插入新节点,item为新插入的节点    def insert(self, pos, item):        """指定位置添加元素"""
        # 若指定位置pos为第一个元素之前,则执行头部插入
        if pos <= 0:
            self.add(item)
        # 若指定位置超过链表尾部,则执行尾部插入
        elif pos > (self.length()-1):
            self.append(item)
        # 找到指定位置
        else:
            node = SingleNode(item)
            count = 0
            # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
            pre = self._head
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 先将新节点node的next指向插入位置的节点
            node.next = pre.next
            # 将插入位置的前一个节点的next指向新节点
            pre.next = node

删除节点

    def remove(self,item):
        """删除节点"""
        # cur指向头结点head        cur = self._head
        # 前驱结点pre初始化为None,不让pre指向任何节点        pre = None
        while cur != None:
            # 找到了指定元素
            if cur.item == item:
                # 先判断此节点是否是头结点
                if cur == self._head: # 或者写成if not pre:
                    # 将头指针指向头节点的后一个节点
                    self._head = cur.next
                else:
                    # 将删除位置前一个节点的next指向删除位置的后一个节点
                    pre.next = cur.next # 这段代码也符合要删除的节点是尾节点的情况
                break #跳出while循环
            else:
                # 继续按链表后移节点
                pre = cur
                cur = cur.next

查找节点是否存在

    def search(self,item):
        """链表查找节点是否存在,并返回True或者False"""
        cur = self._head
        while cur != None:#为什么不写cur.next != None,因为这样会丢失最后一个节点,导致其无法参与比较
            if cur.item == item:
                return True
            else:                cur = cur.next
        return False

测试

if __name__ == "__main__":
    ll = SingleLinkList()    print(ll.is_empty())    print(ll.length())
    ll.add(1)
    ll.add(2)
    ll.append(3)
    ll.insert(2, 4)
    print "length:",ll.length()
    ll.travel()
    print ll.search(3)
    print ll.search(5)
    ll.remove(1)
    print "length:",ll.length()
    ll.travel()

链表与顺序表的对比

          链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。

          链表与顺序表的各种操作复杂度如下所示:

操作链表顺序表
访问元素O(n)                O(1)
在头部插入/删除O(1)                O(n)
在尾部插入/删除O(n)                O(1)
在中间插入/删除

                    O(n)

(n是要遍历的元素个数)

                O(n)

(n是顺序表要挪多少个位置元素)

         注意虽然表面看起来复杂度都是 O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。

         顺序表查找很快,主要耗时的操作是拷贝覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

10.Python修炼之路【14-链表】2018.05.11 的相关文章

  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 如何在算术表达式的结果上添加 SQLAlchemy 标签?

    我如何将这样的东西翻译成 SQLAlchemy select x y as difference 我知道该怎么做 x label foo 但我不确定在哪里放置下面的 label 方法调用 select table c x table c y
  • 将 Django 表单中的所有 CharField 表单字段输入转换为小写

    我使用 Django 表单进行用户注册 用户可以在其中输入优惠券代码 我希望在优惠券代码字段中输入的所有字符都转换为小写 我尝试过在保存方法 自定义清理方法和自定义验证器中使用 lower 但这些方法没有运气 下面是我的代码 class S
  • 返回不包括指定键的字典副本

    我想创建一个函数 返回字典的副本 不包括列表中指定的键 考虑这本词典 my dict keyA 1 keyB 2 keyC 3 致电without keys my dict keyB keyC 应该返回 keyA 1 我想用一行简洁的字典理
  • multiprocessing.freeze_support()

    为什么多处理模块需要调用特定的function http docs python org dev library multiprocessing html multiprocessing freeze support在被 冻结 以生成 Wi
  • 如何在 openpyxl 中设置或更改表格的默认高度

    我想通过openpyxl更改表格高度 并且我希望首先默认一个更大的高度值 然后我可以设置自动换行以使我的表格更漂亮 但我不知道如何更改默认高度 唯一的到目前为止 我知道更改表格高度的方法是设置 row dimension idx heigh
  • 使用 Python 抓取维基百科数据

    我正在尝试从以下内容中检索 3 列 NFL 球队 球员姓名 大学球队 维基百科页面 http en wikipedia org wiki 2008 NFL draft 我是 python 新手 一直在尝试使用 beautifulsoup 来
  • 一起使用 Argparse 和 Json

    我是 Python 初学者 我想知道 Argparse 和 JSON 是否可以一起使用 说 我有变量p q r 我可以将它们添加到 argparse 中 parser add argument p param1 help x variabl
  • 使用 Python 解析 XML,解析外部 ENTITY 引用

    在我的 S1000D xml 中 它指定了一个带有对公共 URL 的引用的 DOCTYPE 该 URL 包含对包含所有有效字符实体的许多其他文件的引用 我使用 xml etree ElementTree 和 lxml 尝试解析它并得到解析错
  • 如何像在浏览器中一样检索准确的 HTML

    我正在使用 Python 脚本来呈现网页并检索其 HTML 它适用于大多数页面 但对于其中一些页面 检索到的 HTML 不完整 我不太明白为什么 这是我用来废弃此页面的脚本 由于某种原因 每个产品的链接不在 HTML 中 Link http
  • 如何将同步函数包装在异步协程中?

    我在用着aiohttp https github com aio libs aiohttp构建一个 API 服务器 将 TCP 请求发送到单独的服务器 发送 TCP 请求的模块是同步的 对于我来说是一个黑匣子 所以我的问题是这些请求阻塞了整
  • Pandas,按最大返回值进行分组 AssertionError:

    熊猫有问题 我想听听你的意见 我有这个数据框 我需要在其中获取最大值 代码就在下面 df stack pd DataFrame 1 0 2016 0 NonResidential Hotel 98101 0 DOWNTOWN 47 6122
  • 从 python 中的缩进文本文件创建树/深度嵌套字典

    基本上 我想迭代一个文件并将每行的内容放入一个深层嵌套的字典中 其结构由每行开头的空格数量定义 本质上 目标是采取这样的事情 a b c d e 并将其变成这样的东西 a b c d e Or this apple colours red
  • 如何将reportlab与Google应用程序引擎一起使用

    我无法在谷歌应用程序引擎下正确导入reportlab 根据以下guide http blog notdot net 2010 04 Generating PDFs on App Engine Python and introducing M
  • Docker 日志中的 Python 异常标记为流:stdout

    我想解析和处理来自 docker 容器的所有错误 但当我期望 stderr 时 Python 异常标记为 stdout 举个简单的例子app py raise Exception 然后我在 docker 容器中运行这个文件 但在 var l
  • 与函数复合 UniqueConstraint

    一个快速的 SQLAlchemy 问题 我有一个 文档 类 其属性为 数字 和 日期 我需要确保没有重复的号码同年 是 有没有办法对 数字 年份 日期 进行UniqueConstraint 我应该使用唯一索引吗 我如何声明功能部分 SQLA
  • django如何将字符串转换为模块?

    我试图了解 django 的另一个神奇之处 它可以将字符串转换为模块 In settings py INSTALLED APPS声明如下 INSTALLED APPS django contrib auth django contrib c
  • python csv按列转换为字典

    是否可以将 csv 文件中的数据读取到字典中 使得列的第一行是键 同一列的其余行构成列表的值 例如 我有一个 csv 文件 strings numbers colors string1 1 blue string2 2 red string
  • 使用Python重命名目录中的多个文件

    我正在尝试使用以下 Python 脚本重命名目录中的多个文件 import os path Users myName Desktop directory files os listdir path i 1 for file in files
  • Python 中的迭代器 (iter()) 函数。 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 对于字典 我可以使用iter 用于迭代字典的键 y x 10 y 20 for val in iter y print val 当

随机推荐

  • 「leetcode」C++题解:239. 滑动窗口最大值,单调队列的经典题目

    更多精彩文章持续更新 xff0c 微信搜索 代码随想录 第一时间围观 xff0c 本文https github com youngyangyang04 TechCPP 已经收录 xff0c 里面有更多干货等着你 xff0c 欢迎Star x
  • BAT程序员总结的力扣刷题指南,已经在Github了!!刷题顺序,优质题解一网打尽!

    相信很多小伙伴刷题的时候面对力扣上近两千道题目 xff0c 感觉无从下手 xff01 我花费半年时间整理了Github学习项目 力扣刷题攻略 xff1a https github com youngyangyang04 leetcode m
  • 扩展卡尔曼滤波EKF与多传感器融合

    Extended Kalman Filter xff08 扩展卡尔曼滤波 xff09 是卡尔曼滤波的非线性版本 在状态转移方程确定的情况下 xff0c EKF已经成为了非线性系统状态估计的事实标准 本文将简要介绍EKF xff0c 并介绍其
  • 我把年终总结写成了年度回忆录(1)

    写在前面 这大概是我第一次正儿八经的写个年终总结 xff0c 其实 xff0c 更像是一篇很有意思的回忆录 去年元旦的情景我已经记不起来了 但这一年里 xff0c 却是有很多事情让我难以忘记 从去年寒假自己在出租屋里苦学的时光 xff0c
  • .mat文件后缀名消失

    情况说明 xff1a 下载了 mat文件后 xff0c 打开文件发现文件的后缀名缺失了 xff0c 并且文件类型变为Microsoft Access Table Shortcut类型 具体原因 xff1a 这是由于MATLAB和Access
  • lsusb命令

    在 Linux 中我们可以使用 lsusb 来列出 USB 设备和它的属性 xff0c lsusb 会显示驱动和内部连接到你系统的设备 直接在控制台输入 lsusb 即可 如果无法运行 lsusb xff0c 使用以下命令安装 xff08
  • 现代控制理论基础——卡尔曼滤波(kalman filtering)

    现代控制理论基础 卡尔曼滤波 xff08 kalman filtering xff09 什么是卡尔曼滤波 xff1f 在任何含有不确定信息的动态系统中使用卡尔曼滤波 xff0c 对系统下一步的走向做出有根据的预测 xff0c 对系统状态进行
  • C/C++中的'\0'

    在C C 43 43 语言中 xff0c 字符是按其所对应的ASCII码来存储的 xff0c 一个字符占一个字节 xff0c 而 0 就是ASCII码表中的第一个字符 xff0c ASCII码为00000000 xff0c 它被称为空字符
  • OpenCV 创建图像时,CV_8UC1,CV_32FC3,CV_32S等参数的含义

    形式 xff1a CV lt bit depth gt S U F C lt number of channels gt bit depth xff1a 比特数 代表8bite 16bites 32bites 64bites 举个例子吧 比
  • 解决apt-get update更新错误

    sudo apt get update出现解析错误 xff0c 如下 fkuner 64 data3 span class token function sudo span span class token function apt get
  • C++初阶:vector类

    vector 0 vector的介绍 vector是用数组实现的 可变长度的顺序容器 xff0c 本质是一种类模板 span class token keyword template span span class token operat
  • Git之分支创建策略

    分支类型 git上始终保持两个分支 xff0c master分支 develop分支 master分支主要用于发布时使用 xff0c 而develop分支主要用于开发使用 除了以上两个常驻分支外 xff0c 我们还可以适当分支出三种分支 x
  • ubuntu 设置pip源

    前言 在Ubuntu下我们一般使用pip工具去管理我们的Python包 但是在使用pip命令操作的时候一般都是使用的默认设置 xff0c 使用的是国外的镜像 xff0c 这就导致了我们在国内下载安装包的时候很慢 xff08 乌龟慢慢爬 xf
  • 27.串口通信实验源码讲解

    串口通信实验源码讲解 笔记基于正点原子官方视频 视频连接https www bilibili com video BV1Wx411d7wT p 61 71 amp spm id from 61 333 1007 top right bar
  • 国内快速下载keil的pack文件包

    问题 xff1a 国内keil官网下载pack文件包太慢 xff0c 网上很多网盘资源如果没有VIP也是很慢 解决方案 xff1a https www keil com dd2 pack 第一步 xff1a 首先去上面的keil官网找自己需
  • forensics - make virtual machine with E01[ewf] files on OSX ———— 电子取证 MAC OS平台仿真

    forensics make virtual machine with E01 ewf files on OSX 电子取证 MAC OS平台仿真1挂载库安装osxfuselibewf 2 虚拟机存储文件qemu 3 开始实验 amp amp
  • 如何从官网下载 Google Chrome 离线安装包

    Google Chrome 已经是许多人的默认浏览器 xff0c 但由于 你懂的 原因 xff0c 在线安装基本没有成功过 xff0c 他自己的自动更新也多数一直在加载中 xff0c 所以我们会到一些下载站下载安装包 xff0c 但我的多次
  • 腾讯资深3D游戏建模师你不知道的5个3DMAX细节

    首先我们要清楚的是行业划分 3DMAX的用途非常广泛 xff0c 所涉及的行业大致有 xff0c 园林景观 城市规划 建筑设计 室内设计 动漫设计 商业动画制作等 所以我们在入手学3DMAX软件时 xff0c 大家应该分清楚 xff0c 你
  • 通过GetProcessNameByProcessId得到进程路径

    写主防时 xff0c 为了拿到进程路径 xff0c 所以查询发现一种发现一种方式是通过PID xff0c 调用PsLookupProcessByProcessId ProcessId amp ProcessObj 拿到进程的EPROCESS
  • 10.Python修炼之路【14-链表】2018.05.11

    关键字 xff1a 单链表 双链表 循环单链表 循环双链表 一 链表 1 为什么需要链表 顺序表的构建需要预先知道数据大小来申请连续的存储空间 xff0c 而在进行扩充时又需要进行数据的搬迁 xff0c 所以使用起来并不是很灵活 链表结构可