链表的原理和实现python

为什么需要链表

数组的底层原理是顺序存储,是一块连续的内存空间,有了这块内存空间的首地址,就能直接通过索引计算出任意位置的元素地址。

链表不一样,一条链表并不需要一整块连续的内存空间存储元素。链表的元素可以分散在内存空间的天涯海角,通过每个节点上的next, prev 指针,将零散的内存块串联起来形成一个链式结构。

这样做的好处很明显,首先就是可以提高内存的利用效率,链表的节点不需要挨在一起,给点内存 new 出来一个节点就能用,操作系统会觉得这娃好养活。

可以抽象为一条弯曲的链子,通过一个个环连接在一起。

另外一个好处,它的节点要用的时候就能接上,不用的时候拆掉就行了,从来不需要考虑扩缩容和数据搬移的问题,理论上讲,链表是没有容量限制的(除非把所有内存都占满,这不太可能)。

当然,不可能只有好处没有局限性。数组最大的优势是支持通过索引快速访问元素,而链表就不支持

这个不难理解吧,因为元素并不是紧挨着的,所以如果你想要访问第 3 个链表元素,你就只能从头结点开始往顺着 next 指针往后找,直到找到第 3 个节点才行。

单链表

链表的创建

class Listnode:def __init__(self, x):self.val = xself.next = Nonedef create_linked_list(nums):head = Listnode(nums[0])cur = headfor i in range(1, len(nums)):cur.next = Listnode(nums[i])cur = cur.nextreturn headdef print_linked_list(current_node):while current_node:print(current_node.val, end='->')current_node = current_node.nextprint('None')if __name__ == '__main__':nums = [1, 2, 3, 4, 5]linked_list = create_linked_list(nums)print_linked_list(linked_list)

最终的输出结果:1->2->3->4->5->None

链表的实现

class ListNode:def __init__(self, val):self.val = valself.next = Noneclass MyLinkedList(object):def __init__(self):self.size = 0self.head = ListNode(0)def get(self, index):"""从链表中获取指定位置的元素值。:param index: 要获取元素的位置索引,从0开始计数。:type index: int:return: 如果索引有效,则返回对应位置的元素值;否则返回-1。:rtype: int"""# 检查索引是否超出链表范围if index < 0 or index >= self.size:return -1cur = self.head# 遍历链表至指定索引位置for _ in range(index + 1):cur = cur.nextreturn cur.val  # 返回指定位置的元素值def addAtHead(self, val):""":type val: int:rtype: None"""self.addAtIndex(0, val)def addAtTail(self, val):""":type val: int:rtype: None"""self.addAtIndex(self.size, val)def addAtIndex(self, index, val):"""在指定索引处插入一个新节点。:param index: 要插入节点的索引位置。如果索引大于当前链表长度,则不做任何操作;如果索引小于0,则将节点插入到链表开头。:param val: 要插入的节点的值。:return: None"""if index > self.size:  # 如果索引大于链表长度,则直接返回,不做任何操作returnif index < 0:  # 如果索引小于0,将节点插入到链表开头index = 0self.size += 1  # 更新链表大小pre = self.head# 定位到要插入节点的前一个节点for _ in range(index):pre = pre.next  # 逐个遍历,找到正确的位置to_add = ListNode(val)  # 创建新节点to_add.next = pre.next  # 新节点指向pre节点的next节点pre.next = to_add  # pre的next指向新节点def deleteAtIndex(self, index):"""从链表中删除指定索引的元素。:param index: 要删除的元素的索引。如果索引无效(小于0或大于等于链表长度),则不进行任何操作。:type index: int:return: None"""if index < 0 or index >= self.size:returnself.size -= 1pre = self.head# 移动到要删除节点的前一个节点for _ in range(index):pre = pre.next# 要删除节点的前一个节点next指向删除节点的后一个节点pre.next = pre.next.next

双链表

链表的创建

class ListNode:def __init__(self, val):self.val = valself.next = Noneself.prev = Nonedef create_double_linked_list(arr):if not arr:return Nonehead = ListNode(arr[0])cur = headfor i in range(1, len(arr)):node = ListNode(arr[i])cur.next = nodenode.prev = curcur = cur.nextreturn headdef print_double_linked_list(head):while head:print(head.val, end='->')head = head.nextif __name__ == '__main__':head = create_double_linked_list([1, 2, 3, 4, 5])print_double_linked_list(head)

链表的实现

class ListNode:def __init__(self, x):self.val = xself.next = Noneself.prev = Noneclass MyLinkedList:def __init__(self):self.size = 0self.head, self.tail = ListNode(0), ListNode(0)self.head.next = self.tailself.tail.prev = self.headdef get(self, index: int) -> int:"""从链表中获取指定位置的元素值。"""# 检查索引是否超出链表范围if index < 0 or index >= self.size:return -1# 选择从头结点还是尾结点开始遍历取决于索引的位置,以优化遍历效率# 以索引值作为分割,左边短就从头结点开始遍历,右边短就从尾结点开始遍历if index + 1 < self.size - index:curr = self.head# 遍历链表到达指定索引位置for _ in range(index + 1):curr = curr.nextelse:curr = self.tail# 遍历链表到达指定索引位置for _ in range(self.size - index):curr = curr.prev# 遍历链表到达指定索引位置return curr.valdef addAtHead(self, val: int) -> None:self.addAtIndex(0, val)def addAtTail(self, val: int) -> None:self.addAtIndex(self.size, val)def addAtIndex(self, index: int, val: int) -> None:"""在双向链表的指定位置插入一个新节点,并保持双向链表的有序。"""# 处理index大于链表长度的情况,直接返回不进行操作if index > self.size:return# 将负索引调整为0if index < 0:index = 0# 确定插入位置的前驱节点和后继节点if index < self.size - index:# 当index在链表前半部分时,正常计算前驱节点和后继节点pred = self.headfor _ in range(index):pred = pred.nextsucc = pred.nextelse:# 当index在链表后半部分时,从尾部向前计算前驱节点和后继节点succ = self.tailfor _ in range(self.size - index):succ = succ.prevpred = succ.prev# 更新链表大小self.size += 1# 创建新节点并插入到链表中to_add = ListNode(val)to_add.next = succto_add.prev = predpred.next = to_addsucc.prev = to_adddef deleteAtIndex(self, index: int) -> None:if index < 0 or index >= self.size:returnif index < self.size - index:# 当index在链表前半部分时,正常计算前驱节点和后继节点pred = self.headfor _ in range(index):pred = pred.nextsucc = pred.next.nextelse:# 当index在链表后半部分时,从尾部向前计算前驱节点和后继节点succ = self.tailfor _ in range(self.size - index - 1):succ = succ.prevpred = succ.prev.prevself.size -= 1pred.next = succsucc.prev = pred

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

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

相关文章

加速数据要素流通,“隐语杯”全国高校隐私计算大赛正式启动报名!

当前&#xff0c;我国数字经济正处在一个快速增长的阶段&#xff0c;数据要素逐渐成为促进社会经济繁荣的关键驱动力。随着国家对数据治理及隐私保护政策的不断完善&#xff0c;隐私计算技术的创新和实践应用变得愈发重要。面对数据安全与隐私保护的双重挑战&#xff0c;如何实…

高性价比开放式耳机有哪些?五大好评热卖开放式耳机推荐

近年来&#xff0c;开放式耳机凭借其独特的开放式声学设计&#xff0c;给用户带来了动态空间的音质享受。在佩戴等方面也带来了一定的舒适度。然而&#xff0c;面对满目的耳机品牌&#xff0c;新手小白往往会不知道如何挑选。那如何选择一款适合自己的产品呢&#xff1f;我整理…

了解如何有效地利用 Swagger UI

在讨论程序员职业生涯中的一些琐碎但必须的任务时&#xff0c;众所周知&#xff0c;编写和维护文档是他们最不喜欢的活动之一。程序员普遍不愿意编写注释和文档&#xff0c;同时又对那些没有留下适当文档的同事感到失望。这种矛盾主要是因为文档管理是一个繁琐的过程&#xff0…

Yolov8-pose关键点检测:卷积魔改 | 变形条状卷积,魔改DCNv3二次创新

💡💡💡本文独家改进: 变形条状卷积,DCNv3改进版本,小幅涨点的前提下相比较DCNv3大幅度运算速度 💡💡💡强烈推荐:先到先得,paper级创新,直接使用; 💡💡💡创新点:1)去掉DCNv3中的Mask;2)空间域上的双线性插值转改为轴上的线性插值; 💡💡💡如…

计算机专业全解析:热门方向与就业前景

在每年的高考填报中&#xff0c;计算机专业总是出现在填报热门专业榜单之中&#xff0c;可见计算机类专业的热门程度。 然而&#xff0c;随着时代和教育的发展&#xff0c;计算机大类下细分出越来越多的专业&#xff0c;除了核心的计算机科学与技术、软件工程外&#xff0c;还…

计算机毕业设计 | springboot+vue凌云在线阅读平台 线上读书系统(附源码)

1&#xff0c;绪论 随着社会和网络技术的发展&#xff0c;网络小说成为人们茶钱饭后的休闲方式&#xff0c;但是现在很多网络小说的网站都是收费的&#xff0c;高额的收费制度是很多人接受不了的&#xff0c;另外就是很多小说网站都会有大量的弹窗和广告&#xff0c;这极大的影…

代码随想录第四十七天|打家劫舍、打家劫舍Ⅱ、打家劫舍Ⅲ

题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 代码如下&#xff1a; 打家劫舍问题需要注意相邻房子不能偷&#xff0c;因此在偷与不偷的选择上可以归类为&#xff1a; 偷当前&#xff08;i&#xff09;的房子&#xff0c;则子问题变为前i-2个房子的偷取金额…

探秘编程之旅:Baidu Comate 智能代码助手的魔法揭秘

目录 Baidu Comate智能代码助手1.场景需求2.安装步骤3.功能介绍3.1 /指令3.2 插件3.3 #知识 4.使用体验5.总结 Baidu Comate智能代码助手 智能编程助手的意义在于提升编程体验和效率&#xff0c;使开发人员能够更轻松、更快速地完成编码任务&#xff0c;是如今人工智能技术的一…

【cpp题解】最大子数组和(53)

目录 前言我的思路思路一思路二 我的代码 前言 今天继续来学一学动态规划&#xff0c;一上来就遇到了网红题&#xff0c;据说是以前清北的考研题哈哈哈哈。挺难的&#xff0c;让我做的话&#xff0c;那就是双层循环暴力解&#xff0c;思路很巧妙&#xff0c;学到啦~ 我的思路…

yaml配置文件的在深度学习中的简单应用

1 .创作灵感 小伙伴们再阅读深度学习模型的代码的时候&#xff0c;经常会遇到yaml格式的配置文件。用这个配置文件是因为我们在训练模型的时候会涉及很多的参数&#xff0c;如果这些参数东一个&#xff0c;西一个&#xff0c;我们调起来的时候就会很不方便&#xff0c;所以用y…

数字电商人才孵化基地授牌仪式在天府锋巢直播产业基地隆重举行!

2024年4月25日&#xff0c;数字电商人才孵化基地授牌仪式在天府锋巢直播产业基地隆重举行。此次仪式不仅标志着德商锋巢与天府新区信息技术职业学院的紧密合作正式启动&#xff0c;更意味着双方在数字电商领域的人才培养和产业发展上迈出了坚实的步伐。 仪式现场&#xff0c;德…

WiFine通信与Wi-sun通信对比

调制速率 WiFine通信&#xff1a;(G)FSK 50Kbps~500Kbps &#xff1b;LoRa 5Kbps~37.5Kbps Wi-Sun通信&#xff1a;(G)FSK 50Kbps~300Kbps &#xff1b;QPSK/OFDM 计划中… 2、协议简介 WiFine通信&#xff1a;为低成本、低功耗、移动设备倾力打造 的轻量级、分布式无线移动…

初始C++(二)

前言&#xff1a; C相对于C语言还有很多区别&#xff0c;接下来我们继续介绍 函数重载&#xff1a; 很好理解&#xff0c;就是Java中的函数重载。C加了函数的修饰&#xff0c;通过函数修饰规则去找。C语言是直接通过函数名查找&#xff0c;C是通过修饰后的函数名去查找。 引用…

Java 运行的底层原理

Java是一种跨平台的编程语言&#xff0c;其底层原理涉及到了多个方面&#xff0c;包括Java虚拟机&#xff08;JVM&#xff09;、字节码、类加载机制、垃圾回收器等。让我们逐一深入了解Java运行的底层原理。 1. Java虚拟机&#xff08;JVM&#xff09; Java虚拟机是Java程序运…

pandas高级操作--复杂查询

pandas高级操作 一、复杂查询1.1 逻辑筛选数据1.2 函数筛选1.3 isin()函数1.4 查询df.query()1.5 df.filter()对行名和列名进行筛选 一、复杂查询 1.1 逻辑筛选数据 以下是切片&#xff08;[]&#xff09;的一些逻辑筛选示例&#xff1a; df[df[Q1] 8] # Q1等于8 df[~(d…

Python进行excel处理-01

最近干采购&#xff0c;每个月要对供应商的对账单&#xff0c;对对应的采购订单号和物料编号的价格和数量&#xff0c;是不是和物料管控总表里面的价格数量是不是一致&#xff0c;于是写了一个代码。 从总表里面找到&#xff0c;对账单里对应采购订单和物料编码的数据&#xf…

从代码到洞察:使用API接口深入分析商品详情数据

在电子商务的世界中&#xff0c;商品详情数据是企业做出明智决策的基石。API&#xff08;应用程序编程接口&#xff09;提供了一种强大的方式来获取这些数据&#xff0c;不仅可以简化数据获取过程&#xff0c;还可以为深入分析和业务洞察提供丰富的信息。本文将探讨如何使用API…

5W 1.5KVDC 隔离 宽电压输入 DC/DC 电源模块——TP05DB 系列

TP05DB系列电源模块额定输出功率为5W&#xff0c;应用于2:1及4:1电压输入范围 4.5V-9V、9V-18V、18V-36V、36V-72V、9V-36V和18V-72V&#xff0c;40-160VDC的输入电压环境&#xff0c;输出电压精度可达1%&#xff0c;具有输出过流保护等功能。可广泛应用于通信、铁路、自动化以…

Java毕业设计 基于SpringBoot vue社区智慧养老监护管理平台

Java毕业设计 基于SpringBoot vue社区智慧养老监护管理平台 SpringBoot 社区智慧养老监护管理平台 功能介绍 登录注册 个人中心 修改密码 个人信息 房间信息管理 房间入住信息管理 反馈信息管理 留言管理 老人信息管理 公告管理 物资申请管理 管理员管理 护工管理 体检员管理…

2024-05-08 postgres-火山模型-执行-记录

摘要: 2024-05-08 postgres-火山模型-执行-记录 上下文: 2024-05-08 postgres-调试及分析-记录-CSDN博客 火山模型: 数据流是在查询树上&#xff0c;自上而下进行拉取&#xff0c;由上而下的调用。树本身就表明了数据的流动。每次执行一个元组&#xff0c;也就类似于迭代器的…