【数据结构】数组、双链表代码实现

💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢迎在文章下方留下你的评论和反馈。我期待着与你分享知识、互相学习和建立一个积极的社区。谢谢你的光临,让我们一起踏上这个知识之旅!
请添加图片描述

文章目录

  • 🍋数组(Array)
  • 🍋链表(Linked List)
  • 🍋代码实现
  • 🍋总结

🍋数组(Array)

基本原理:
    数组是一种线性数据结构,它在内存中是一段连续的存储空间。
    数组通过索引(或下标)访问元素,索引从 0 开始递增。
    所有元素的类型相同,占用的内存空间相等。

优点:
    随机访问:可以通过索引快速访问任意位置的元素,时间复杂度为 O(1)。
    索引计算简单:根据索引计算元素的内存地址很简单,只需一个乘法和一个加法操作。

缺点:
    大小固定:数组的大小在创建时就固定了,无法动态调整。
    插入和删除操作效率低:在数组中间插入或删除元素会涉及到大量元素的移动,时间复杂度为 O(n)。
    内存空间的浪费:如果数组预留了很大的空间但只存储了少量元素,会造成内存空间的浪费。

🍋链表(Linked List)

基本原理:
    链表是一种由节点组成的数据结构,每个节点包含数据和指向下一个节点的指针(或引用)。
    节点不必在内存中连续存储,通过指针将它们串联起来。

优点:
    动态大小:链表的大小可以动态增长或缩小,不需要预先分配固定大小的空间。
    插入和删除操作高效:在链表中插入或删除元素只需要改变指针的指向,时间复杂度为 O(1)。

缺点:
    随机访问低效:要访问链表中的第 k 个元素,需要从头节点开始依次遍历,时间复杂度为 O(k)。
    需要额外的空间存储指针:每个节点都需要额外的空间存储指向下一个节点的指针,占用的内存空间较大。

🍋代码实现

数组

from selenium.common import NoSuchElementException


class MyArrayList:
    def __init__(self, init_capacity=1):
        self.data = [None] * init_capacity
        self.size = 0
    #     在列表末尾添加元素 e。
    #     如果列表已满,则调用 _resize 函数扩展列表的容量。

    def add_last(self, e):
        cap = len(self.data)
        if self.size == cap:
            self._resize(2 * cap)
        self.data[self.size] = e
        self.size += 1
    #     在指定索引 index 处插入元素 e。
    #     如果列表已满,则调用 _resize 函数扩展列表的容量。
    #     使用切片操作实现在 index 处插入元素,并将后续元素向后移动一个位置。

    def add(self, index, e):
        self._check_position_index(index)
        cap = len(self.data)
        if self.size == cap:
            self._resize(2 * cap)
        self.data[index+1:self.size+1] = self.data[index:self.size]
        self.data[index] = e
        self.size += 1

    # 在列表开头添加元素 e,实际上是调用 add(0, e)。
    def add_first(self, e):
        self.add(0, e)

    #     移除并返回列表末尾的元素。
    #     如果列表的大小为容量的四分之一,则调用 _resize 函数缩小列表的容量。
    def remove_last(self):
        if self.size == 0:
            raise NoSuchElementException()
        cap = len(self.data)
        if self.size == cap // 4:
            self._resize(cap // 2)
        deleted_val = self.data[self.size - 1]
        self.data[self.size - 1] = None
        self.size -= 1
        return deleted_val

    #     移除并返回指定索引 index 处的元素。
    #     如果列表的大小为容量的四分之一,则调用 _resize 函数缩小列表的容量。
    #     使用切片操作实现在 index 处移除元素,并将后续元素向前移动一个位置。
    def remove(self, index):
        self._check_element_index(index)
        cap = len(self.data)
        if self.size == cap // 4:
            self._resize(cap // 2)
        deleted_val = self.data[index]
        self.data[index:self.size-1] = self.data[index+1:self.size]
        self.data[self.size - 1] = None
        self.size -= 1
        return deleted_val

    # 移除并返回列表开头的元素,实际上是调用 remove(0)。
    def remove_first(self):
        return self.remove(0)

    # 返回指定索引 index 处的元素。
    def get(self, index):
        self._check_element_index(index)
        return self.data[index]

    # 将指定索引 index 处的元素设置为 element,并返回原始值。
    def set(self, index, element):
        self._check_element_index(index)
        old_val = self.data[index]
        self.data[index] = element
        return old_val

    # 返回列表的大小。
    def size(self):
        return self.size

    # 返回列表是否为空。
    def is_empty(self):
        return self.size == 0

    #     将列表的容量调整为 new_cap。
    #     如果新容量小于当前大小,则不进行调整。
    def _resize(self, new_cap):
        if self.size > new_cap:
            return
        temp = [None] * new_cap
        temp[:self.size] = self.data[:self.size]
        self.data = temp

    # 用于检查索引是否在有效范围内。
    def _is_element_index(self, index):
        return 0 <= index < self.size
    def _is_position_index(self, index):
        return 0 <= index <= self.size

    # 用于检查索引是否在有效范围内,如果不在有效范围内,则抛出 IndexError。
    def _check_element_index(self, index):
        if not self._is_element_index(index):
            raise IndexError("Index: " + str(index) + ", Size: " + str(self.size))
    def _check_position_index(self, index):
        if not self._is_position_index(index):
            raise IndexError("Index: " + str(index) + ", Size: " + str(self.size))

    # 使 MyArrayList 对象可迭代,从而可以使用 for 循环遍历其中的元素。
    def __iter__(self):
        self.p = 0
        return self

    def __next__(self):
        if self.p == self.size:
            raise StopIteration
        self.p += 1
        return self.data[self.p - 1]
    # 打印
    def display(self):
        print(f"size = {self.size} cap = {len(self.data)}")
        print(self.data)


if __name__ == "__main__":
    arr = MyArrayList(3)
    for i in range(1, 6):
        arr.add_last(i)

    arr.remove(3)
    arr.add(1, 9)
    arr.add_first(100)
    val = arr.remove_last()

    for i in range(arr.size):
        print(arr.get(i))
    print(arr.display())

双链表

from selenium.common import NoSuchElementException


class MyLinkedList:
    class Node:
        def __init__(self, val):
            self.val = val
            self.next = None
            self.prev = None

    def __init__(self):
        self.head = self.Node(None)
        self.tail = self.Node(None)
        self.head.next = self.tail
        self.tail.prev = self.head
        self.size = 0

    def add_last(self, e):
        x = self.Node(e)
        temp = self.tail.prev
        temp.next = x
        x.prev = temp
        x.next = self.tail
        self.tail.prev = x
        self.size += 1

    def add_first(self, e):
        x = self.Node(e)
        temp = self.head.next
        temp.prev = x
        x.next = temp
        self.head.next = x
        x.prev = self.head
        self.size += 1

    def add(self, index, element):
        self._check_position_index(index)
        if index == self.size:
            self.add_last(element)
            return
        p = self._get_node(index)
        temp = p.prev
        x = self.Node(element)
        p.prev = x
        temp.next = x
        x.prev = temp
        x.next = p
        self.size += 1

    def remove_first(self):
        if self.size < 1:
            raise NoSuchElementException()
        x = self.head.next
        temp = x.next
        self.head.next = temp
        temp.prev = self.head
        x.prev = x.next = None
        self.size -= 1
        return x.val

    def remove_last(self):
        if self.size < 1:
            raise NoSuchElementException()
        x = self.tail.prev
        temp = x.prev
        temp.next = self.tail
        self.tail.prev = temp
        x.prev = x.next = None
        self.size -= 1
        return x.val

    def remove(self, index):
        self._check_element_index(index)
        x = self._get_node(index)
        prev = x.prev
        next = x.next
        prev.next = next
        next.prev = prev
        x.prev = x.next = None
        self.size -= 1
        return x.val

    def get(self, index):
        self._check_element_index(index)
        p = self._get_node(index)
        return p.val

    def get_first(self):
        if self.size < 1:
            raise NoSuchElementException()
        return self.head.next.val

    def get_last(self):
        if self.size < 1:
            raise NoSuchElementException()
        return self.tail.prev.val

    def set(self, index, val):
        self._check_element_index(index)
        p = self._get_node(index)
        old_val = p.val
        p.val = val
        return old_val

    def size(self):
        return self.size

    def is_empty(self):
        return self.size == 0

    def _get_node(self, index):
        self._check_element_index(index)
        p = self.head.next
        for _ in range(index):
            p = p.next
        return p

    def _is_element_index(self, index):
        return 0 <= index < self.size

    def _is_position_index(self, index):
        return 0 <= index <= self.size

    def _check_element_index(self, index):
        if not self._is_element_index(index):
            raise IndexError("Index: " + str(index) + ", Size: " + str(self.size))

    def _check_position_index(self, index):
        if not self._is_position_index(index):
            raise IndexError("Index: " + str(index) + ", Size: " + str(self.size))

    def display(self):
        print("size =", self.size)
        p = self.head.next
        while p != self.tail:
            print(p.val, "-> ", end="")
            p = p.next
        print("null")
        print()

    def __iter__(self):
        self.p = self.head.next
        return self

    def __next__(self):
        if self.p == self.tail:
            raise StopIteration
        val = self.p.val
        self.p = self.p.next
        return val
if __name__ == "__main__":
    # 创建一个 MyLinkedList 实例
    linked_list = MyLinkedList()

    # 在链表末尾添加元素
    linked_list.add_last(1)
    linked_list.add_last(2)
    linked_list.add_last(3)

    # 在链表开头添加元素
    linked_list.add_first(0)

    # 在指定位置插入元素
    linked_list.add(2, 1.5)

    # 输出链表大小
    print("Size of linked list:", linked_list.size)

    # 输出链表中的元素
    print("Linked list elements:")
    for val in linked_list:
        print(val)

    # 移除链表开头和末尾的元素
    print("Removed first element:", linked_list.remove_first())
    print("Removed last element:", linked_list.remove_last())

    # 输出链表中的元素
    print("Linked list elements after removal:")
    for val in linked_list:
        print(val)

🍋总结

下一节,我把单链表的也给出来,顺便做两道题应用一下以上的基本操作

请添加图片描述

挑战与创造都是很痛苦的,但是很充实。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

迁移篇 | MatrixOne与MySQL全面对比

Part 1 迁移背景 Skyable 自研了物联网私有云平台用于 IoT 设备的数据上报和协议解析&#xff0c;由于管理设备数量的增加导致设备上报的数据量越来越大&#xff0c;架构中原使用的 MySQL 数据库&#xff08;分库分表&#xff09;的部分业务在对设备上报信息进行相关的查询时&…

ChatGPT 结合实际地图实现问答式地图检索功能基于Function calling

ChatGPT 结合实际地图实现问答式地图检索功能基于Function calling ChatGPT结合实际业务&#xff0c;主要是研发多函数调用&#xff08;Function Calling&#xff09;功能模块&#xff0c;将自定义函数通过ChatGPT 问答结果&#xff0c;实现对应函数执行&#xff0c;再次将结果…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:文本通用)

文本通用属性目前只针对包含文本元素的组件&#xff0c;设置文本样式。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 属性 名称参数类型描述fontColorResourceColor设置字体颜色。 从API version 9开…

VBA更新xlOLELinks链接的值

xlOLELinks是在Excel文档中插入对象的链接&#xff0c;该链接能够显示被插入文档的数据&#xff0c;通常情况下链接的数值会自动更新&#xff0c;但有时更新也会不及时或失效&#xff0c;这时就需要手动更新&#xff0c;如下图&#xff1a; 以插入Word文档为例&#xff0c;使用…

【漏洞复现】Laykefu客服系统任意文件上传

漏洞描述 Laykefu客服系统/admin/users/upavatar.html接口处存在文件上传漏洞,而且当请求中Cookie中的”user_name“不为空时即可绕过登录系统后台,未经身份验证的攻击者可利用此问题,上传后门文件,获取服务器权限。 免责声明 技术文章仅供参考,任何个人和组织使用网络…

js【深度解析】代码的执行顺序

代码的分类 我们将每一句要执行的 js 代码当做一个任务&#xff0c;则 js 代码可以按照其执行方式的不同&#xff0c;按下图分类 同步任务&#xff1a;立即执行的代码异步任务&#xff1a;延迟执行的代码 微任务&#xff1a;被放入微任务队列&#xff08;micro task queue&…

【记录37】VueBaiduMap 踩坑一

截图 错误 Error in callback for watcher “position.lng”: “TypeError: Cannot read properties of undefined (reading ‘setPosition’)” 解释 回调观察程序“content”时出错&#xff1a;“TypeError:无法读取未定义的属性&#xff08;读取’setContent’&#xff09;”…

设计模式-行为型模式-模版方法模式

模板方法模式&#xff0c;定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。[DP] 模板方法模式是通过把不变行为搬移到超类&#xff0c;去除子类中的重复代码来体现它的优势。 //首…

L-2:插松枝(Python)

作者 陈越 单位 浙江大学 人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上&#xff0c;做成大大小小的松枝。他们的工作流程&#xff08;并不&#xff09;是这样的&#xff1a; 每人手边有一只小盒子&#xff0c;初始状态为空。每人面前有用不完的松枝干和一个推送…

《汇编语言》第3版(王爽)实验9

第9章 实验9 编程&#xff1a;在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串 ‘welcome to masm!’ assume cs:code,ds:datadata segmentdb welcome to masm!,0 data endscode segmentstart:mov ax,data mov ds,ax ;ds指向data段mov ax,0B800H ;显存空间从B800H…

LeetCode_24_中等_两两交换链表中的节点

文章目录 1. 题目2. 思路及代码实现&#xff08;Python&#xff09;2.1 递归2.2 迭代 1. 题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换…

windows11编译FFmpeg源码完整步骤

1.安装MSYS2 下载并安装MSYS2 安装GCC GCC安装成功 克隆FFmpeg源码 打开MSYS2终端并进入ffmpeg文件夹,然后输入./configure回车开始生成makefile

JavaEE——简单认识JS(Web API)

文章目录 一、认识什么是 WebAPI二、认识事件三、操作元素1. innerHTML 属性2. 获取 / 修改元素内容3. 获取 / 修改 元素属性4. 获取 / 修改 表单元素属性5. 获取 / 修改 样式属性6. 创建 / 删除元素 一、认识什么是 WebAPI 1.什么是API 在我们了解 WebAPI 之前&#xff0c;我们…

苍穹外卖学习-----2024/03/09

1.菜品分页查询 代码在这里 分页查询菜品 2.删除菜品 [链接]param 1、概览 本文将带你了解 Spring 中 RequestParam 注解的用法。 简单地说&#xff0c;可以使用 RequestParam 从请求中提取查询参数、表单参数甚至是多个参数。 2、示例端点 假设我们有一个端点 /api/foos&a…

二叉树遍历(前中后序的递归/非递归遍历、层序遍历)

二叉树的遍历 1. 二叉树的前序、中序、后序遍历 前、中、后序遍历又叫深度优先遍历 注&#xff1a;严格来说&#xff0c;深度优先遍历是先访问当前节点再继续递归访问&#xff0c;因此&#xff0c;只有前序遍历是严格意义上的深度优先遍历 首先需要知道下面几点&#xff1a; …

Spring学习 基础(三)MVC

5、Spring MVC 传统Web模式&#xff1a; Model:系统涉及的数据&#xff0c;也就是 dao 和 bean。View&#xff1a;展示模型中的数据&#xff0c;只是用来展示。Controller&#xff1a;处理用户请求都发送给 &#xff0c;返回数据给 JSP 并展示给用户。 随着 Spring 轻量级开发…

Vue项目实战-空间论坛(2)

项目实战 实现userlist页面 获取userlist列表&#xff0c;可使用ajax,axios 实现 这里采用ajax实现&#xff0c;需要添加Jquery依赖&#xff0c;然后在UserListView.vue中引入 在UserListView.vue组件的入口函数中定义users变量&#xff0c;并引入ref 使用ajax从云端动…

目标检测——监控下打架检测数据集

一、简述 首先&#xff0c;监控下打架检测是维护公共安全的重要手段。在公共场所、学校、监狱等地方&#xff0c;打架事件往往难以避免。通过安装打架检测监控系统&#xff0c;可以实时监控并准确识别打架事件&#xff0c;及时采取必要的应对措施&#xff0c;有效地减少打架事…

手写分布式配置中心(五)整合springboot(不自动刷新的)

springboot中使用配置方式有四种&#xff0c;分别是environment、BeanDefinition、Value、ConfigurationProperties。具体的原理可以看我之前的一篇文章https://blog.csdn.net/cjc000/article/details/132800290。代码在https://gitee.com/summer-cat001/config-center 原理 …

PTA L2-004 这是二叉搜索树吗?

一棵二叉搜索树可被递归地定义为具有下列性质的二叉树&#xff1a;对于任一结点&#xff0c; 其左子树中所有结点的键值小于该结点的键值&#xff1b;其右子树中所有结点的键值大于等于该结点的键值&#xff1b;其左右子树都是二叉搜索树。 所谓二叉搜索树的“镜像”&#xf…