学习日志016--python实现双向循环列表与链栈

news2024/11/27 8:55:40

python中一些复合数据结构通过类的封装来实现的。双向循环链表与链栈也在其中。

双向循环链表

双向循环链表是一种特殊类型的链表,它结合了双向链表和循环链表的特点。在双向循环链表中,每个节点不仅包含数据,还持有指向前一个和后一个节点的指针,而且链表的最后一个节点指向第一个节点,形成一个闭环。

封装

就像上面介绍的一样,每一个结点(头结点除外)都有前驱,后继,以及数据域。由此创建结点类。

# 创建双向链表节点
# 双向链表结点有前驱有后继有数据域
class Node:
    def __init__(self,data):
        self.data = data
        self.prior = None
        self.next = None

头结点

不是必须的,但为了方便对链表的操作,我们还是会创建。和其他链表的头结点一样,包含链表长度和head的成员变量。

#创建头结点便于操作链表
class Double:
    # 头结点记录链表地址,链表长度
    def __init__(self,node = None):
        self.head = node
        self.size = 0

判空

同样由于链式存储的优点,我们只需要判空。

    # 判空
    def is_empty(self):
        return self.size == 0

双向链表的插入与删除,根据表内元素个数不同,需要分开编写代码

尾插法

#尾插 根据链表是否为空有不同的插入方法
    def insert_rear(self,value):
        node = Node(value)
        # 当表为空时
        if self.is_empty():
            # 当只有一个元素时,循环链表前驱和后继指向自己
            self.head = node
            node.next =  node
            node.prior = node
        else:
            # 变量指向最后一个结点,即head的前驱
            p = self.head.prior
            node.next = p.next
            node.prior = p
            p.next.prior = node
            p.next = node
        self.size += 1

尾删法

# 尾删
    def del_rear(self):
        if self.is_empty():
            print("删除失败")
        elif self.size == 1:
            self.head = None
        else:
            # 尾删直接将头结点的前驱指向前前结点,同时将现前结点的后继指向头结点
            q = self.head.prior.prior
            self.head.prior = q
            q.next = self.head
        self.size -= 1

遍历

双向循环列表可以使用前驱遍历和后继遍历两种方式

# 后继 
    def show(self):
        if self.size == 0:
            print("遍历失败")
            return
        else:
          
            p = self.head
            while p.next != self.head:
                print(f"{p.data}",end=" ")
                p = p.next
                
            print(f"{p.data}")


#前驱
    def r_show(self):
        if self.size == 0:
            print("遍历失败")
            return
        else:
           
            p = self.head
            while p.prior != self.head:
                print(f"{p.data}", end=" ")
                p = p.prior
                
            print(f"{p.data}")

全部代码

# 创建双向链表节点
# 双向链表结点有前驱有后继有数据域
class Node:
    def __init__(self,data):
        self.data = data
        self.prior = None
        self.next = None

#创建头结点便于操作链表
class Double:
    # 头结点记录链表地址,链表长度
    def __init__(self,node = None):
        self.head = node
        self.size = 0

    # 判空
    def is_empty(self):
        return self.size == 0

    #尾插 根据链表是否为空有不同的插入方法
    def insert_rear(self,value):
        node = Node(value)
        # 当表为空时
        if self.is_empty():
            # 当只有一个元素时,循环链表前驱和后继指向自己
            self.head = node
            node.next =  node
            node.prior = node
        else:
            # 变量指向最后一个结点,即head的前驱
            p = self.head.prior
            node.next = p.next
            node.prior = p
            p.next.prior = node
            p.next = node
        self.size += 1

    # 根据链表长度遍历输出
    def show(self):
        if self.size == 0:
            print("遍历失败")
            return
        else:
            i = 1
            p = self.head
            while p.next != self.head:
                print(f"{p.data}",end=" ")
                p = p.next
                i+=1
            print(f"{p.data}")

    def r_show(self):
        if self.size == 0:
            print("遍历失败")
            return
        else:
            i = 1
            p = self.head
            while p.prior != self.head:
                print(f"{p.data}", end=" ")
                p = p.prior
                i += 1
            print(f"{p.data}")
    # 尾删
    def del_rear(self):
        if self.is_empty():
            print("删除失败")
        elif self.size == 1:
            self.head = None
        else:
            # 尾删直接将头结点的前驱指向前前结点,同时将现前结点的后继指向头结点
            q = self.head.prior.prior
            self.head.prior = q
            q.next = self.head
        self.size -= 1

if __name__ =="__main__":

    d = Double()
    # 尾插法
    d.insert_rear(10)
    d.insert_rear(20)
    d.insert_rear(30)
    d.insert_rear(40)
    d.show()
    d.r_show()
        # 尾删法
    d.del_rear()
    d.show()
    d.del_rear()
    d.show()
    d.del_rear()
    d.show()
    d.del_rear()
    d.show()
10 20 30 40
10 40 30 20
10 20 30
10 20
10
遍历失败

链栈

链栈(Linked Stack)是一种基于链表实现的栈结构。在链栈中,每个元素都是一个节点,包含数据域和指向下一个节点的指针。链栈不需要像顺序栈那样预先分配固定大小的存储空间,它可以动态地分配和释放内存,因此更加灵活。

经过之前的练习,对于链式存储已经得心应手,简单完成栈的结点与头结点的封装

结点

和我们学习的线性表相同,链栈的结点也是由数据域与链接域组成。

# 创建链栈
# 创建链栈的结点,包含数据域data与链接域next
class Node:
    def __init__(self,data):
        self.data = data
        self.next = None

 头结点

栈没有像线性表一样,计算长度的实例变量。有一个指向栈顶元素的top

# 封装链栈 一个永远指向栈顶的头结点,不限于统计链栈长度 ,记录栈顶位置
class LinkStack:
    def __init__(self,top = None):
        self.top = top

判空

    # 判空
    def is_empty(self):
        return self.top is None

入栈

类似之前线性表的头插法 ,新结点指向栈顶,top指向新的结点

   # 入栈 每个新元素充当栈顶
    def push(self,value):
        node = Node(value)
#         根据是否栈空这里有不同的插入方法
        if self.is_empty():
            self.top = node
        else:
            node.next = self.top
            self.top = node

出栈

先入后出是栈的特性,最后入栈的元素后出来。出栈会返回该元素并删除。

     出栈 返回栈顶元素并删除
    def pop(self):
#         这里根据元素的多少有两种写法
        i = self.top
        if self.is_empty():
            print("栈空操作失败")
            return i
        else:
            if self.top.next is None:
                self.top = None
                return i.data
            else:
                self.top = self.top.next
                return i.data

返回栈顶元素

    def peek(self):
        #         这里根据元素的多少有两种写法
        i = self.top
        if self.is_empty():
            print("栈空操作失败")
            return i
        else:

            self.top = self.top.next
            return i

统计栈的大小

    def size(self):
        i = 0
        p = self.top
        while p:
            p = p.next
            i+=1
        return i

遍历栈的元素

  def show(self):
        if self.is_empty():
            print("栈空操作失败")
        else:
            p =self.top
            while p:
                print(f"{p.data}",end=" ")
                p = p.next
            print()

全部代码

# 创建链栈
# 创建链栈的结点,包含数据域data与链接域next
class Node:
    def __init__(self,data):
        self.data = data
        self.next = None

# 封装链栈 一个永远指向栈顶的头结点,不限于统计链栈长度 ,记录栈顶位置
class LinkStack:
    def __init__(self,top = None):
        self.top = top

    # 判空
    def is_empty(self):
        return self.top is None

    # 入栈 每个新元素充当栈顶
    def push(self,value):
        node = Node(value)
#         根据是否栈空这里有不同的插入方法
        if self.is_empty():
            self.top = node
        else:
            node.next = self.top
            self.top = node

#     出栈 返回栈顶元素并删除
    def pop(self):
#         这里根据元素的多少有两种写法
        i = self.top
        if self.is_empty():
            print("栈空操作失败")
            return i
        else:
            if self.top.next is None:
                self.top = None
                return i.data
            else:
                self.top = self.top.next
                return i.data

    def peek(self):
        #         这里根据元素的多少有两种写法
        i = self.top
        if self.is_empty():
            print("栈空操作失败")
            return i
        else:

            self.top = self.top.next
            return i

    def size(self):
        i = 0
        p = self.top
        while p:
            p = p.next
            i+=1
        return i

    def show(self):
        if self.is_empty():
            print("栈空操作失败")
        else:
            p =self.top
            while p:
                print(f"{p.data}",end=" ")
                p = p.next
            print()

if __name__ == "__main__":
    s = LinkStack()
    s.push(10)
    s.push(20)
    s.push(30)
    s.push(40)
    s.push(50)
    print(s.size())
    s.show()
    s.pop()
    s.show()
    s.peek()
    s.show()
    s.pop()
    s.show()
    s.pop()
    s.show()
    s.pop()
    s.show()
    s.pop()
    s.show()
D:\xn\hqyj\pythonProject\.venv\Scripts\python.exe C:\Users\31284\OneDrive\Desktop\PYTHON\数据结构\day03\03.py 
5
50 40 30 20 10 
40 30 20 10 
30 20 10 
20 10 
10 
栈空操作失败
栈空操作失败
栈空操作失败

进程已结束,退出代码为 0

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

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

相关文章

【Docker】常用命令汇总

Docker 是1个开源的应用容器引擎,基于Go 语言并遵从 Apache2.0 协议开源。 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 容器是完全使用沙箱机制,相…

QT QRadioButton控件 全面详解

本系列文章全面的介绍了QT中的57种控件的使用方法以及示例,包括 Button(PushButton、toolButton、radioButton、checkBox、commandLinkButton、buttonBox)、Layouts(verticalLayout、horizontalLayout、gridLayout、formLayout)、Spacers(verticalSpacer、horizontalSpacer)、…

Docker部署mysql:8.0.31+dbsyncer

Docker部署mysql8.0.31 创建本地mysql配置文件 mkdir -p /opt/mysql/log mkdir -p /opt/mysql/data mkdir -p /opt/mysql/conf cd /opt/mysql/conf touch my.config [mysql] #设置mysql客户端默认字符集 default-character-setUTF8MB4 [mysqld] #设置3306端口 port33…

[SUCTF 2019]EasySQL--详细解析

信息搜集 进入界面是一个搜索框: 查看一下源代码,显示是POST传参: 随便上传个数字1: 抓包测试一下闭合,发现以双引号闭合会回显nonono,单引号闭合则无回显。 由于没有报错信息,所以我们不能确定具体的闭…

警钟长鸣,防微杜渐,遨游防爆手机如何护航安全生产?

近年来,携非防爆手机进入危险作业区引发爆炸的新闻屡见报端。2019年山西某化工公司火灾,2018年延安某煤业瓦斯爆炸,均因工人未用防爆手机产生静电打火引发。涉爆行业领域企业量大面广,相当一部分企业作业场所人员密集,…

【智能流体力学】RAG大模型方法:解决固体力学和流体动力学问题

【使用 AutoGen + GPT-4o + Chainlit UI 进行工程仿真的对话式多智能体 AI 聊天机器人】 本项目构建了一个由多个AI代理组成的系统,这些代理通过使用Microsoft AutoGen进行对话交互,能够自主地创建和仿真固体力学(FEA)和流体动力学(CFD)问题。每个AI代理都擅长规划、问题…

Redis与MySQL如何保证数据一致性

Redis与MySQL如何保证数据一致性 简单来说 该场景主要发生在读写并发进行时,才会发生数据不一致。 主要流程就是要么先操作缓存,要么先操作Redis,操作也分修改和删除。 一般修改要执行一系列业务代码,所以一般直接删除成本较低…

Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导 一、前言 在充满活力与激情的校园生活中,校运会不仅是…

【西瓜书】神经网络-MP神经元、感知机和多层网络

神经网络(neural networks)的定义:神经网络是由具有适应性的简单单元组成的广泛并行互联的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。(T. Kohonen 1988年在Neural Networks创刊号上给出的定义…

《安富莱嵌入式周报》第346期:开源2GHz带宽,12bit分辨率,3.2Gsps采样率示波,开源固件安全分析器, 开源口袋电源,开源健康测量,FreeCAD

周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频: https://www.bilibili.com/video/BV1TYBhYKECK/ 《安富莱嵌入式周报》第346期:开源2GHz带…

介绍一下atoi(arr);(c基础)

hi , I am 36 适合对象c语言初学者 atoi(arr)&#xff1b;是返回整数(int型)&#xff0c;整数是arr数组中字符中数字 格式 #include<stdio.h> atoi(arr); 返回值arr数组中的数字 未改变arr数组 #include<stdlib.h>//atoi(arr); 返 <stdlib> int main(…

Docker: 教程07 - ( 如何对 Docker 进行降级和升级)

如果我们使用 docker 来管理容器&#xff0c;那么保持 docker 引擎的更新将会是十分重要的&#xff0c;这一篇文章我们将会讨论如何对Docker 进行降级和升级。 准备工作 - docker 环境 我们需要拥有一个安装好 docker 的运行环境。 如果你需要了解如何安装 docker 可以通过如…

ArcGIS pro中的回归分析浅析(加更)关于广义线性回归工具的补充内容

在回归分析浅析中篇的文章中&#xff0c; 有人问了一个问题&#xff1a; 案例里的calls数据貌似离散&#xff0c;更符合泊松模型&#xff0c;为啥不采用泊松而采用高斯呢&#xff1f; 确实&#xff0c;在中篇中写道&#xff1a; 在这个例子中我们为了更好地解释变量&#x…

第R4周:LSTM-火灾温度预测(TensorFlow版)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊]** 往期文章可查阅&#xff1a; 深度学习总结 任务说明&#xff1a;数据集中提供了火灾温度&#xff08;Tem1&#xff09;、一氧化碳浓度…

《操作系统 - 清华大学》5 -4:虚拟技术

文章目录 0. 虚拟存储的定义1. 目标2.局部性原理3. 虚拟存储的思路与规则4. 虚拟存储的基本特征5. 虚拟页式存储管理5.1 页表表项5.2 示例 0. 虚拟存储的定义 1. 目标 虚拟内存管理技术&#xff0c;简称虚存技术。那为什么要虚存技术&#xff1f;在于前面覆盖和交换技术&#…

MYSQL 表的增删改查(上)

目录 1.新增数据 2.查询数据 一般查询 去重查询 排序查询 关于NULL 条件查询 分页查询 1.新增数据 语法&#xff1a;insert into 表名[(字段1&#xff0c;字段2...)] values (值&#xff0c;值....); 插入一条新数据行&#xff0c;前面指定的列&#xff0c;要与后面v…

OSPTrack:一个包含多个生态系统中软件包执行时生成的静态和动态特征的标记数据集,用于识别开源软件中的恶意行为。

2024-11-22 &#xff0c;由格拉斯哥大学创建的OSPTrack数据集&#xff0c;目的是通过捕获在隔离环境中执行包和库时生成的特征&#xff0c;包括静态和动态特征&#xff0c;来识别开源软件&#xff08;OSS&#xff09;中的恶意指标&#xff0c;特别是在源代码访问受限时&#xf…

[Docker-显示所有容器IP] 显示docker-compose.yml中所有容器IP的方法

本文由Markdown语法编辑器编辑完成。 1. 需求背景: 最近在启动一个服务时&#xff0c;突然发现它的一个接口&#xff0c;被另一个服务ip频繁的请求。 按理说&#xff0c;之前设置的是&#xff0c;每隔1分钟请求一次接口。但从日志来看&#xff0c;则是1秒钟请求一次&#xff…

如何寻找适合的HTTP代理IP资源?

一、怎么找代理IP资源&#xff1f; 在选择代理IP资源的时候&#xff0c;很多小伙伴往往将可用率作为首要的参考指标。事实上&#xff0c;市面上的住宅IP或拨号VPS代理IP资源&#xff0c;其可用率普遍在95%以上&#xff0c;因此IP可用率并不是唯一的评判标准 其实更应该关注的…