Python双向循环链表的操作

news2024/12/23 13:56:14

目录

一、双向循环链表

双向循环链表图

 二、双向循环链表的操作

1、判断链表是否为空

2,链表长度

3,遍历整个链表

4,在链表头部添加元素

5、链表尾部添加元素

6,在指定位置插入元素

7,修改指定位置的元素

8,删除元素

9、查找元素是否存在

三、完整代码


一、双向循环链表

双向循环链表图

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

 二、双向循环链表的操作

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 != self.__head:
            count += 1
            cur = cur.next
        return count

3,遍历整个链表
 

  def travel(self):
     # 遍历整个链表
        if self.is_empty():
            return
        cur = self.__head
        while cur.next != self.__head:
            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
            # 修改新结点的next指向结点自己
            node.next = node
            # 新结点的pre指向结点自己的next构成一个结点的双向循环
            node.pre = node.next
        else:
            tail = self.__head
            # 循环找到尾结点
            while tail.next != self.__head:
                tail = tail.next
            # 1.新来的节点的next指向第一个头节点
            node.next = self.__head
            # 2.再改变第一个头节点的指针指向新节点的next
            self.__head.pre = node.next
            # 3.将尾指向指向添加node节点
            tail.next = node
            # 4.新结点pre指向尾结点的next
            node.pre = tail.next
            # 5.最后修改头指针指向新结点
            self.__head = node


5、链表尾部添加元素

修改尾结点与新结点的双向指针指向

再修改新结点(这时也是尾结点了)与头结点的双向指针指向

    def append(self, item):
        # 链表尾部添加元素
        # 创建新结点
        node = Node(item)
        # 是空链表就把头节点指向这个节点
        if self.is_empty():
            self.__head = node
            node.next = node
            node.pre = node.next
        else:
            tail = self.__head
            # 找到尾节点
            while tail.next != self.__head:
                tail = tail.next
            # 修改尾结点与新结点的指针
            tail.next = node
            node.pre = tail.next
            # 修改尾结点和头结点的循环指针
            node.next = self.__head
            self.__head.pre = node.next


6,在指定位置插入元素

找到要插入的位置的前一个结点的指针

修改前一个结点与新插入结点的双向指针

再修改新插入的结点与后一个结点的双向指针

    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):
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next.pre = node.next
            node.pre = cur.next
            cur.next = node

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 != self.__head:
                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.next != self.__head:
            # 找到了要删除的元素
            if cur.elem == item:
                # 要删除的元素就是第一个元素
                if cur == self.__head:
                    tail = self.__head
                    # 让tail指向最后一个元素
                    while tail.next != self.__head:
                        tail = tail.next
                    # 1.尾结点的next指向头结点的next(这个next指向第二个结点)
                    tail.next = cur.next
                    # 2.第二个结点的pre指向尾结点的next
                    cur.next.pre = tail.next
                    # 3.修改头指针指向第二个结点
                    self.__head = cur.next

                else:
                    forword.next = cur.next
                return
            # 未找到要删除的元素,指针向后走,继续遍历
            else:
                forword = cur
                cur = cur.next
        # 当上面的while循环不满足条件时(cur.next == self.__head),说明只有一个结点元素
        if cur.elem == item:
            if cur.next == self.__head:
                forword.next = self.__head

9、查找元素是否存在

    def search(self, item):
        # 查找节点是否存在
        cur = self.__head
        while cur.next != self.__head:
            # 找到了返回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 DoubleCircleLinkList():
    def __init__(self, node=None):
        self.__head = node
        if node:
            node.next = node  # 只有一个结点时,next指针指向自己,构成循环
            node.pre = node.next

    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 != self.__head:
            count += 1
            cur = cur.next
        return count

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

    def add(self, item):
        # 链表头部添加元素
        node = Node(item)
        if self.is_empty():
            # 是空链表头指针直接指向新结点
            self.__head = node
            # 修改新结点的next指向结点自己
            node.next = node
            # 新结点的pre指向结点自己的next构成一个结点的双向循环
            node.pre = node.next
        else:
            tail = self.__head
            # 循环找到尾结点
            while tail.next != self.__head:
                tail = tail.next
            # 1.新来的节点的next指向第一个头节点
            node.next = self.__head
            # 2.再改变第一个头节点的指针指向新节点的next
            self.__head.pre = node.next
            # 3.将尾指向指向添加node节点
            tail.next = node
            # 4.新结点pre指向尾结点的next
            node.pre = tail.next
            # 5.最后修改头指针指向新结点
            self.__head = node

    def append(self, item):
        # 链表尾部添加元素
        # 创建新结点
        node = Node(item)
        # 是空链表就把头节点指向这个节点
        if self.is_empty():
            self.__head = node
            node.next = node
            node.pre = node.next
        else:
            tail = self.__head
            # 找到尾节点
            while tail.next != self.__head:
                tail = tail.next
            # 修改尾结点与新结点的指针
            tail.next = node
            node.pre = tail.next
            # 修改尾结点和头结点的循环指针
            node.next = self.__head
            self.__head.pre = node.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 != self.__head:
                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):
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next.pre = node.next
            node.pre = cur.next
            cur.next = node

    def remove(self, item):
        # 删除节点
        cur = self.__head  # cur当前指针
        forword = None  # 前一个指针
        while cur.next != self.__head:
            # 找到了要删除的元素
            if cur.elem == item:
                # 要删除的元素就是第一个元素
                if cur == self.__head:
                    tail = self.__head
                    # 让tail指向最后一个元素
                    while tail.next != self.__head:
                        tail = tail.next
                    # 1.尾结点的next指向头结点的next(这个next指向第二个结点)
                    tail.next = cur.next
                    # 2.第二个结点的pre指向尾结点的next
                    cur.next.pre = tail.next
                    # 3.修改头指针指向第二个结点
                    self.__head = cur.next

                else:
                    forword.next = cur.next
                return
            # 未找到要删除的元素,指针向后走,继续遍历
            else:
                forword = cur
                cur = cur.next
        # 当上面的while循环不满足条件时(cur.next == self.__head),说明只有一个结点元素
        if cur.elem == item:
            if cur.next == self.__head:
                forword.next = self.__head

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


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

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

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

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

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

    print('modify')
    ll.modify(1, 200)
    ll.travel()

    print(ll.search(200))

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

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

相关文章

被裁后找不到工作,本质上是因为原来的能力就配不上高薪,如果技术好,根本不怕被裁,相当于白送n+1!...

被裁员后&#xff0c;能要求公司补缴公积金吗&#xff1f; 一位网友问&#xff1a; 被裁员了&#xff0c;要求公司把历史公积金全部足额缴纳&#xff0c;现在月薪2.3万&#xff0c;但公司每个月只给自己缴纳300元公积金&#xff0c;结果一次补了二十多万&#xff0c;一次性取出…

进程等待、进程替换

目录 进程等待 waitpid函数 wait函数 进程替换 进程等待 进程等待的意义 如果子进程退出&#xff0c;父进程如果不管不顾&#xff0c;就可能造成‘僵尸进程’的问题&#xff0c;进而造成内存泄漏。 另外&#xff0c;进程一旦变成僵尸状态&#xff0c;那就刀枪不入&#xff…

5.5G的关键一跳!将数智未来照进现实

编辑&#xff1a;阿冒 设计&#xff1a;沐由 作为数字时代的三大思想家之一&#xff0c;乔治吉尔德在1993年就指出&#xff0c;未来25年内主干网的带宽每6个月增长一倍&#xff0c;其增长速度是摩尔定律预测的CPU增长速度的3倍。 这就是著名的吉尔德定律&#xff08;Gilder’s …

Qt开源项目:校医院远程诊断系统介绍

本人研一参考技术书籍开发的一款Qt程序&#xff0c;两年前已上传到GitHub&#xff0c;有兴趣的同学可以去看看。可能之前上传的项目不够完整&#xff0c;导致有一些同学没有在自己的环境上跑通&#xff0c;所以今天将整个工程都重新上传一遍&#xff0c;包括使用到的opencv的动…

Lambda 表达式中的变量必须是 final 的吗

如果我们定义了一个变量&#xff0c;想要在Lambda 表达式中修改变量的值&#xff0c;编译器会发出警告&#xff1a;“variable used in lambda expression should be final or effectively final”。 比如对一个list进行遍历&#xff0c;遍历的过程中对i进行操作 Java 规范中…

浅理解 ES6 新增的数组方法Array.of() 和 Array.from()

文章目录 &#x1f4cb;前言&#x1f3af;Array.of() 方法&#x1f3af;Array.from() 方法&#x1f3af;二者区别&#x1f4dd;最后 &#x1f4cb;前言 在前端开发的面试过程中&#xff0c; ES6 新增是一个很常见的考点&#xff0c;比如说箭头函数、模板字符串、let 和 const …

宁波汽车运输集团:引入二维码技术,实现车辆精细化管理

宁波市汽车运输集团有限公司是宁波市道路货运业的龙头企业之一&#xff0c;主营全国各地的普通货运以及货物专用运输&#xff08;集装箱、罐式&#xff09;。 作为汽车运输集团&#xff0c;车辆的安全问题极其重要。因此&#xff0c;公司设备安全部门要求每个驾驶员在作业之前…

netfilter filter表(二)

这次继续分析filter表&#xff0c;不同与之前的分析方式&#xff0c;这次通过将内核中的数据打印出来&#xff0c;对比结构关系图来分析。这是本次分析涉及的几个数据结构&#xff1a; struct xt_table { struct list_head list; /* What hooks you will enter on */ unsigned …

4、SpringBoot接收和响应xml报文请求

背景 平时开发的接口&#xff0c;基本是使用 json 格式的请求报文。然而&#xff0c;有时候也避免不了有 xml 报文请求的场景&#xff0c;最近就遇到了这种情况&#xff0c;在此记录下。另外&#xff0c;工程中使用的是 controller-service……这种结构。 xml请求报文&#x…

链表(JS实现)

&#x1f4dd;个人主页&#xff1a;爱吃炫迈 &#x1f48c;系列专栏&#xff1a;数据结构与算法 &#x1f9d1;‍&#x1f4bb;座右铭&#xff1a;道阻且长&#xff0c;行则将至&#x1f497; 文章目录 链表链表的分类创建链表LinkedList类的骨架 实现链表的方法push尾部添加元…

chatgpt智能提效职场办公-ppt怎么蒙层

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 在 PowerPoint 中添加蒙版图层&#xff0c;可以在幻灯片中创建一个半透明的矩形或形状&#xff0c;并在其上方添加或放置其他对象。 下…

FPGA终于可以愉快地写代码了!Vivado和Visual Studio Code黄金搭档

如果你是一位FPGA开发者&#xff0c;那么你一定会对VIvado这款软件非常熟悉。但是&#xff0c;对于vivado兼容的第三方编辑器软件&#xff0c;你知道Visual Studio Code吗&#xff1f;这是个非常不错的选择&#xff0c;Visual Studio Code搭配众多插件&#xff0c;能让你FPGA开…

【SpringBoot】一:SpringBoot的基础(下)

文章目录 1.外部化的配置1.1 配置文件基础1.1.1 配置文件格式1.1.2 application文件1.1.3 application.properties1.1.4 application.yml1.1.5 environment1.1.6 组织多文件1.1.7多环境配置 1.2 绑定Bean1.2.1 简单的属性绑定1.2.2 嵌套Bean1.2.3 扫描注解1.2.4 处理第三方库对…

【移动端网页布局】移动端网页布局基础概念 ② ( 视口 | 布局视口 | 视觉视口 | 理想视口 )

文章目录 一、视口1、布局视口 ( 网页大小 | 网页大小 > 设备大小 )2、视觉视口 ( 设备大小 | 网页大小 > 设备大小 )3、理想视口 ( 网页大小 设备大小 ) 一、视口 浏览器 显示 网页页面内容 的 屏幕区域 被称为 " 视口 " ; 视口分为以下几个大类 : 布局视口…

项目协同中的git

在远程代码仓库&#xff08;云效&#xff0c;gitee&#xff0c;github&#xff0c;Coding等&#xff09;新建一个代码库&#xff0c; 我使用的云效 新建一个develop分支&#xff0c;后续所有人的提交代码都合并到develop分支上面&#xff0c;一般develop分支是用来开发用的&…

尚融宝22-提交借款申请

目录 一、需求介绍 二、图片上传 &#xff08;一&#xff09;前端页面 &#xff08;二&#xff09;实现图片上传 三、数据字典展示 &#xff08;一&#xff09;后端 &#xff08;二&#xff09;前端 四、表单信息提交 &#xff08;一&#xff09;后端 1、VO对象&…

嵌入式工程师如何快速的阅读datasheet的方法

目录 ▎从项目角度来看datasheet ▎各取所需 ▎最后 Datasheet&#xff08;数据手册&#xff09;的快速阅读能力&#xff0c;是每个工程师都应该具备的基本素养。 无论是项目开始阶段的选型还是后续的软硬件设计&#xff0c;到后期的项目调试&#xff0c;经常有工程师对着英…

06-Node.js—模块化

目录 1、介绍1.1 什么是模块化与模块 ?1.2 什么是模块化项目 ?1.3 模块化好处 2、模块暴露数据2.1 模块初体验2.2 暴露数据2.2.1 module.exports value2.2.2 exports.name value 3、导入&#xff08;引入&#xff09;模块4、导入模块的基本流程5、CommonJS 规范参考 1、介绍…

使用RabbitMQ的手动接收模式:消息第二次入队Failed to declare queue

问题&#xff1a;在rabbitMQ测试使用手动接收模式时发生 Failed to declare queue错误 : Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code406, reply-textPRECONDITION_FAILED - unknown delivery tag 1, class-id60, method-id80…

C++ 命名空间、域、缺省参数、函数重载、引用、auto、内联函数的知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏

绪论 从本章开始我们正式进入到C的内容&#xff0c;对此如果没有学习过C语言的建议先将C语言系统的学习一遍后再来&#xff08;已经更新完在专栏就能看到&#xff09;。 话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑观看&#xff09;。 附&#xff1a;红色&#…