Python双向链表的操作

news2024/11/16 2:41:02

目录

 

一、双向链表

双向链表示例图

 二、双向链表的操作

1、判断链表是否为空

2,链表长度

3,遍历整个链表

4,在链表头部添加元素

5、链表尾部添加元素

6,在指定位置插入元素

7,修改指定位置的元素

8,删除元素

9、查找元素是否存在

三、完整代码


一、双向链表

双向链表示例图

结点node里有三个部分:pre(指向上一结点next的指针)、elem(元素)和next(指向下一结点的指针),head指针指向头结点

 二、双向链表的操作

1、判断链表是否为空
 

    def is_empty(self):
        # 链表是否为空
        if self.__head is None:
            return True
        else:
            return False

2,链表长度

    def length(self):
        # 链表长度
        if self.is_empty():
            return 0
        count = 0
        cur = self.__head
        while cur.next is not None:
            count += 1
            cur = cur.next
        return count

3,遍历整个链表

    def travel(self):
     # 遍历整个链表
        if self.is_empty():
            return
        cur = self.__head
        while cur.next is not None:
            print(cur.elem, end=' ')
            cur = cur.next
        print(cur.elem)

4,在链表头部添加元素

    def add(self, item):
        # 链表头部添加元素
        node = Node(item)
        if self.is_empty():  # 原本是空链表的就让头指针直接指向这个新添加的元素结点
            self.__head = node
        else:  # 链表不为空时
            node.next = self.__head  # 新结点的next指针指向头指针所指的结点
            self.__head.pre = node.next  # 再将头指针结点的pre指针指向新结点的next
            self.__head = node  # 最后修改头指针指向新结点


5、链表尾部添加元素

    def append(self, item):
        # 链表尾部添加元素
        # 创建新结点
        node = Node(item)
        # 是空链表就把头节点指向这个节点
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next is not None:  # 循环找到尾部结点的指向,当退出循环时指针已指向最后一个结点
                cur = cur.next
            cur.next = node  # 将尾部结点的next指向新结点
            node.pre = cur.next  # 新结点的pre指向尾结点的next


6,在指定位置插入元素

因为插入的代码比较难理解,所以这里画了个图帮助理解

新结点node值是100,要插入到原链表11,22,33的下标为2的位置(也就是pos为2的位置插入100),所以就要修改指针的指向做到插入结点的目的

步骤:

根据给定的pos位置去遍历让指针指向要插入的位置的上一个结点cur.next

按红色箭头和数字顺序修改指针指向即可:

        1.cur.next.pre现让它指向新结点100的next区域

        2.新结点100的next区域指向33这个结点(不是pre区域)

        3.新结点pre区域指向结点22的next区域

        4.结点22的next区域指向新结点100(不是pre区域)

重新改变这四个指针的指向后就完成了插入

    def insert(self, pos, item):
        # 位置pos在第一个元素之前,则在头部插入
        if pos <= 0:
            self.add(item)
            # 位置pos大于总长度,则在尾部插入
        elif pos > self.length():
            self.append(item)
        else:
            # 指定位置添加元素
            # 创建新结点
            node = Node(item)
            count = 0
            cur = self.__head  # 当时指针
            while count < (pos-1):  # 循环找到指向pos位置结点的指针
                count += 1
                cur = cur.next
            # 当上面退出循环时,说明cur已经指向了pos的位置
            # 所以接下来修改四个指针的指向来实现插入元素
            cur.next.pre = node.next  # 1.将cur的下一结点的pre指向新结点next
            node.next = cur.next  # 2.将新结点的next指向cur的下一结点
            cur.next = node  # 3.将cur的next指向新结点
            node.pre = cur.next  # 4.将新结点的pre指向cur的next

7,修改指定位置的元素

    def modify(self, pos, item):
        """修改指定位置的元素"""
        # 当指定的位置pos小于等于0时,则修改头部元素
        if pos <= 0:
            self.__head.elem = item
        # 当pos大于等于链表总长度时,则修改尾部元素
        elif pos >= self.length():
            tail = self.__head
            # 循环让指针指向尾部元素
            while tail.next is not None:
                tail = tail.next
            tail.elem = item  # 修改尾部元素
        else:
            count = 0
            tail = self.__head
            # 循环指针找到指定的位置
            while count < pos:  # 1.当不满足条件退出循环时,说明指针已经指向了给定的pos位置
                tail = tail.next
                count += 1
            tail.elem = item  # 2.将pos位置的元素修改

8,删除元素

    def remove(self, item):
        # 删除节点
        cur = self.__head  # cur当前指针
        forword = None  # 前一个指针
        # 遍历链表当时指针
        while cur is not None:
            # 如果找到了要删除的元素
            if cur.elem == item:
                # 要删除的元素刚好是头部元素,就把头指针指向当前的下一个结点
                if cur == self.__head:
                    self.__head = cur.next
                else:
                    forword.next = cur.next  # 如果不是头元素指针就继续向后走
                return
            else:  # 未找到要删除的元素,指针向后走,继续遍历
                forword = cur
                cur = cur.next

9、查找元素是否存在

    def search(self, item):
        # 查找节点是否存在
        cur = self.__head
        while cur.next is not None:
            # 找到了返回True,未找到指向下一个继续遍历
            if cur.elem == item:
                return True
            cur = cur.next
        # 查找的元素在最后一个,遍历后指向最后一个,但是没有进入循环,所以需要在循环体外判断一次
        if cur.elem == item:
            return True
        return False

三、完整代码

class Node():
    def __init__(self, elem):
        # 双向链表结点
        self.pre = None
        self.elem = elem
        self.next = None


class DoubleLinkList():
    def __init__(self, node=None):
        self.__head = node

    def is_empty(self):
        # 链表是否为空
        if self.__head is None:
            return True
        else:
            return False

    def length(self):
        # 链表长度
        if self.is_empty():
            return 0
        count = 0
        cur = self.__head
        while cur.next is not None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
     # 遍历整个链表
        if self.is_empty():
            return
        cur = self.__head
        while cur.next is not None:
            print(cur.elem, end=' ')
            cur = cur.next
        print(cur.elem)

    def add(self, item):
        # 链表头部添加元素
        node = Node(item)
        if self.is_empty():  # 原本是空链表的就让头指针直接指向这个新添加的元素结点
            self.__head = node
        else:  # 链表不为空时
            node.next = self.__head  # 新结点的next指针指向头指针所指的结点
            self.__head.pre = node.next  # 再将头指针结点的pre指针指向新结点的next
            self.__head = node  # 最后修改头指针指向新结点

    def append(self, item):
        # 链表尾部添加元素
        # 创建新结点
        node = Node(item)
        # 是空链表就把头节点指向这个节点
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next is not None:  # 循环找到尾部结点的指向,当退出循环时指针已指向最后一个结点
                cur = cur.next
            cur.next = node  # 将尾部结点的next指向新结点
            node.pre = cur.next  # 新结点的pre指向尾结点的next

    def modify(self, pos, item):
        """修改指定位置的元素"""
        # 当指定的位置pos小于等于0时,则修改头部元素
        if pos <= 0:
            self.__head.elem = item
        # 当pos大于等于链表总长度时,则修改尾部元素
        elif pos >= self.length():
            tail = self.__head
            # 循环让指针指向尾部元素
            while tail.next is not None:
                tail = tail.next
            tail.elem = item  # 修改尾部元素
        else:
            count = 0
            tail = self.__head
            # 循环指针找到指定的位置
            while count < pos:  # 1.当不满足条件退出循环时,说明指针已经指向了给定的pos位置
                tail = tail.next
                count += 1
            tail.elem = item  # 2.将pos位置的元素修改

    def insert(self, pos, item):
        # 位置pos在第一个元素之前,则在头部插入
        if pos <= 0:
            self.add(item)
            # 位置pos大于总长度,则在尾部插入
        elif pos > self.length():
            self.append(item)
        else:
            # 指定位置添加元素
            # 创建新结点
            node = Node(item)
            count = 0
            cur = self.__head  # 当时指针
            while count < (pos-1):  # 循环找到指向pos位置结点的指针
                count += 1
                cur = cur.next
            # 当上面退出循环时,说明cur已经指向了pos的位置
            # 所以接下来修改四个指针的指向来实现插入元素
            cur.next.pre = node.next  # 1.将cur的下一结点的pre指向新结点next
            node.next = cur.next  # 2.将新结点的next指向cur的下一结点
            cur.next = node  # 3.将cur的next指向新结点
            node.pre = cur.next  # 4.将新结点的pre指向cur的next

    def remove(self, item):
        # 删除节点
        cur = self.__head  # cur当前指针
        forword = None  # 前一个指针
        # 遍历链表当时指针
        while cur is not None:
            # 如果找到了要删除的元素
            if cur.elem == item:
                # 要删除的元素刚好是头部元素,就把头指针指向当前的下一个结点
                if cur == self.__head:
                    self.__head = cur.next
                else:
                    forword.next = cur.next  # 如果不是头元素指针就继续向后走
                return
            else:  # 未找到要删除的元素,指针向后走,继续遍历
                forword = cur
                cur = cur.next

    def search(self, item):
        # 查找节点是否存在
        cur = self.__head
        while cur.next is not None:
            # 找到了返回True,未找到指向下一个继续遍历
            if cur.elem == item:
                return True
            cur = cur.next
        # 查找的元素在最后一个,遍历后指向最后一个,但是没有进入循环,所以需要在循环体外判断一次
        if cur.elem == item:
            return True
        return False


if __name__ == '__main__':
    ll = DoubleLinkList()
    print(ll.is_empty())
    print(ll.length())
    ll.travel()

    print('add')
    ll.add(9)
    ll.travel()
    ll.add(10)
    ll.travel()

    print('append')
    ll.append(13)
    ll.travel()

    print('insert')
    ll.insert(1, 33)
    ll.travel()

    print('remove')
    ll.remove(10)
    ll.travel()

    print('modify')
    ll.modify(2, 100)
    ll.travel()

    print(ll.search(9))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/446808.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

百度ai智能写作工具-百度ai自动写文章

百度AI智能写作工具&#xff1a;让创作更快捷、高效&#xff01; 在当今竞争激烈的文化创意市场中&#xff0c;创作一篇高质量的文章需要投入大量时间和精力。然而&#xff0c;有了百度AI智能写作工具&#xff0c;创作变得更快捷、高效了。 百度AI智能写作工具采用最先进的人…

JVM之垃圾回收器概述

目录 垃圾收集器分类 按线程数分 按照工作模式分 ​编辑 按碎片处理方式分 按工作的内存区间分 评估GC的性能指标 吞吐量 暂停时间 吞吐量 vs 暂停时间 垃圾回收器概述 垃圾收集器没有在规范中进行过多的规定&#xff0c;可以由不同的厂商、不同版本的JVM来实现。 由…

一起学 WebGL:感受三维世界之视图矩阵

大家好&#xff0c;我是前端西瓜哥。之前绘制的图形都是在 XY 轴所在的平面上&#xff0c;这次我们来加入一点深度信息 z&#xff0c;带你走入三维的世界。 视图矩阵 对于一个立方体来说&#xff0c;我们从它的正前方看&#xff0c;不管距离它多远&#xff0c;也只能看到一个…

微服务下网关聚合Swagger文档、starter统一配置Swagger

一、starter实现统一配置微服务文档 把Swagger配置中的公共部分抽取出来Swagger与SpringBoot整合中&#xff0c;可能会由于版本问题出现各种问题 1、制作starter 参考&#xff1a; 【SpringBoot】自定义启动器 Starter【保姆级教程】用starter实现Oauth2中资源服务的统一配置用…

中级软件设计师备考---数据库系统1

目录 数据库模式数据库的设计过程E-R模型关系代数与元组演算 数据库模式 三级模式、两级映射 定义&#xff1a; 三级模式&#xff1a;外模式、概念模式和内模式&#xff1b;两级映射&#xff1a;外模式-概念模式映射、概念模式-内模式映射 外模式是用户看到的数据库的部分 概…

Linux的常见指令 -掌握

前言 为什么要学命令行&#xff1f; windows/苹果图形界面&#xff0c;是商业化的产物&#xff0c;也就是使用必须简单小白&#xff0c;才能有人用&#xff0c;so what&#xff1f;严格意义上讲&#xff0c;我们必须要学一下Linux命令行。因为企业后端有大量的服务器&#xff…

Web3.0:重新定义互联网的未来

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Web3.0&#xff1a;重新定义互联网的未来 Web3.0是指下一代互联网&#xff0c;也称为“分布式互联网”。相比于Web1.0和Web2.0&#xff0c;Web3.0具有更强的去中心化、…

如何快速查找下载外文文献,哪个文献下载网站好用

​​如何高效获取到自己需要的外文文献&#xff0c;最好的办法就是去文献来源数据库中查找&#xff0c;你需要的文献来源数据库有可能是Elsevier&#xff08;sciencedirect&#xff09;、也可能是Wiley Online Library、也有可能是IEEE等等&#xff0c;外文数据库机构太多了。这…

微信跨平台方案Donut快速上手

一、Donut简介 Donut 是微信开发出的多端框架&#xff0c;用于支持使用小程序原生语法开发移动应用的框架&#xff0c;开发者可以一次编码&#xff0c;就可以编译出小程序和 Android 以及 iOS 应用&#xff0c;实现多端开发。能够帮助企业有效降低多端应用开发的技术门槛和研发…

html画布绘制图形

一.题目要求 使用canvas标签完成直角三角形、矩形及圆形的绘制. 二.相关知识点 1.认识<canvas> 标签翻译&#xff1a;画布。 <canvas> 标签定义图形&#xff0c;比如图表和其他图像&#xff0c;您必须使用脚本来绘制图形。 <canvas> 标签只是图形容器&am…

[学习笔记] [机器学习] 2. Seaborn及练习案例

视频链接 数据集下载地址&#xff1a;https://download.csdn.net/download/weixin_44878336/87711308 目录 1. 绘制统计图形1.1 可视化数据的分布1.2 绘制单变量分布1.3 绘制双变量分布1.4 绘制成对的双变量分布 2. 用分类数据绘图2.1 类别散点图2.1.1 sns.stripplot()2.1.2 sn…

Hi3861 硬件 i2c 驱动 oled

一、前言 最近想用 3861 做个有意思的东西&#xff0c;记录一下开发过程。今天使用 3861 的硬件 i2c 驱动 oled。 硬件平台&#xff1a;Bearpi-Nano 软件SDK&#xff1a;润和sdk 二、搬一个 OLED 轮子 我之前写过一篇基于 stm32cubemx 快速使用 iic 接口 oled 的过程&#xff0…

一文搞懂C#实时调试时,程序数据库文件.pdb(符号文件)的作用。延伸搞懂Debug/Release、AnyCPU(首选32位)/x86/x64/ARM的区别

一、准备工作 MS引用&#xff1a;在 Visual Studio 调试器&#xff08;C#、C、Visual Basic、F#&#xff09;中指定符号 (.pdb) 和源文件 MS引用&#xff1a;为 C#、ASP.NET 或 Visual Basic 项目 &#xff08;.NET Framework&#xff09; 生成符号文件 MS引用&#xff1a;用…

图解网络(三)——IP

文章目录 前言一、IP地址与MAC地址的作用二、IP基础2.1 基础2.2 IP 地址的分类 三、ping的工作原理3.1 ICMP 协议3.2 TCP发数据和ping的区别3.2.1 如果用的是TCP的方式去发送消息3.2.1 如果用的是ping 四、断网了&#xff0c;还能 ping 通 127.0.0.1 吗&#xff1f;4.1 什么是1…

编译和链接

目录 1. 程序的翻译环境和执行环境 2. 详解编译链接 2.1 翻译环境 2.2 编译本身也分为几个阶段&#xff1a; 2.2.1汇编过程的简略图 2.3讲解汇编过程的具体过程和要点 2.4运行环境 1. 程序的翻译环境和执行环境 在ANSIC的任何一种实现中&#xff0c;存在两个不同的环境。…

C++基础入门(一)

前言 欢迎进入C世界&#xff01;这是一种令人兴奋的语言&#xff0c;它在C语言的基础上添加上了对面向对象编程和泛型编程的支持&#xff0c;在20世纪90年代便是最重要的编程语言之一&#xff0c;并在21世纪仍保持强劲势头。C继承了C语言的高效、简洁、快速和可移植性的传统。C…

【计算机视觉 | 图像分割】Segment Anything论文讲解

文章目录 一、前言二、论文出发点三、创新思路四、方法4.1 Segment Anything Task4.2 Segment Anything Model4.3 Segment Anything Data Engine4.4 Segment Anything Dataset 五、结果 一、前言 论文&#xff1a;https://arxiv.org/pdf/2304.02643.pdf 项目&#xff1a;https…

数据结构(一)—— 数组

文章目录 一、数组基础二、题1. 704 二分查找2. 27 移除元素3. 977 有序数组的平方4. 209 长度最小的子数组 一、数组基础 数组是存放在连续内存空间上的相同类型数据的集合&#xff0c;也就是说数组内存空间的地址是连续的。 因为数组的在内存空间的地址是连续的&#xff0c;…

COIG:首个大规模、可商用的中文开源指令数据!

文 | ZenMoore ChatGPT 出现后的这几个月&#xff0c;整个学界和业界的疯狂想必大家都已经看到了。 然而&#xff0c;在背各种各样的动物还有山海经怪兽的英语单词的时候&#xff0c;其实不妨停下来想一想复现中文 ChatGPT 到底缺什么&#xff1f;缺大模型吗&#xff1f;缺工程…

C++的引用

目录 引用概念 引用的用法 做函数形参 优点一 优点二 引用做返回值 让我们更深入的了解引用与指针 语法层引用与指针完全不同的概念 站在底层的角度看指针与引用 笔记类型文章 引用概念 在语言层面上&#xff1a;引用不是定义新的变量&#xff0c;而是给已存在变量再…