三、数组————相关概念详解

news2025/5/23 6:59:24

数组

  • 前言
  • 一、数据理论基础
  • 二、数组常用操作
    • 2.1 初始化数组
    • 2.2 访问数组中的元素
    • 2.3 插入元素
    • 2.4 删除元素
  • 三、数组扩展
    • 3.1 遍历数组
    • 3.2 数组扩容
  • 总结
    • 1、数组的优点
    • 2、数组的不足


前言

  • 在数据结构中,数组可以算得上最基本的数据结构。
  • 数组可以用于实现栈、队列、哈希表、堆、图等数据结构。例如,图的邻接矩阵表示实际上是一个二维数组。(后续我们再讲)

一、数据理论基础

  • 学习数组之前我们首先要了解数组在内存中的存储方式,这样才能真正理解数组的相关操作
    数组是储存在连续内存空间的相同类型的数据的集合,举一个字符数组的例子,如下图所示
    在这里插入图片描述
  • 观察上图,我们发现数组首个元素的索引为 0,这似乎有些反直觉,因为从 1 开始计数会更自然。那是因为,索引本质上是内存地址的偏移量。首个元素的地址偏移量是 0,因此它的索引为 0 是合理的。

二、数组常用操作

2.1 初始化数组

  • 我们可以根据需求选用数组的两种初始化方式:无初始值、给定初始值。在未指定初始值的情况下,大多数编程语言会将数组元素初始化为 0

代码如下(示例):

# 初始化数组
arr: list[int] = [0] * 5            # [ 0, 0, 0, 0, 0 ]
nums: list[int] = [1, 3, 2, 5, 4]   # [1, 3, 2, 5, 4]

2.2 访问数组中的元素

  • 数组元素被存储在连续的内存空间中,这意味着计算数组元素的内存地址非常容易。
    在这里插入图片描述
  • 从上图中我们知道,我们只要知道数组第一位元素地址跟某元素的索引就可以轻松的算出来该元素的地址。
计算公式
元素内存地址 = 数组内存地址(即第一位元素的地址) + 元素长度(因为存的都是相同类型的元素,所以长度一样) x 元素索引
譬如求数组中 E 的元素的内存地址
16 = 00 + 4 x 4

代码如下(示例):

# 导包
import random
# 定义数组列表
list1: list[int] = [1, 3, 2, 5, 4]

def random_access(list1: list[int]) -> int:
    """
    随机访问数组中的元素演示
    :param list1: 接受 数组 
    :return: 返回数组中的随机一个元素
    """
    # 在区间 [0, len(nums)-1] 中随机抽取一个数字
    random_index = random.randint(0, len(list1) - 1)
    # 获取并返回随机元素
    random_num = list1[random_index]
    return random_num

if __name__ == '__main__':
    res = random_access(list1)
    print(res)

数组中访问元素非常高效,我们可以在 O(1) 时间内访问数组中的任意一个元素

2.3 插入元素

  • 因为数组中的元素在内存中是连续存在的,所以插入元素的时候,需要将插入位置后的所有元素都往后移动一位,之后再将元素赋值给该索引,如下图所示:
    在这里插入图片描述
    因为数组的长度是固定的,因此插入元素的时候,必定导致尾部元素丢失,这个我们在列表中在进行讨论。

代码如下(示例):

def insert(nums, num, index):
    """
    在数组的索引 index 处插入元素 num
    :param nums: 接受的数组
    :param num: 要插入的元素
    :param index: 要插入的位置(索引)
    :return: 无返回值
    """
    """在数组的索引 index 处插入元素 num"""
    # 把索引 index 以及之后的所有元素向后移动一位
    for i in range(len(nums) - 1, index, -1):
        nums[i] = nums[i - 1]
    # 将 num 赋给 index 处的元素
    nums[index] = num



if __name__ == '__main__':
    nums = ['A', 'B', 'C', 'D', '']
    print(f'插入前的数组为{nums}')   # ['A', 'B', 'C', 'D', '']
    insert(nums, 'E', 1)
    print(f'插入前的数组为{nums}')   # ['A', 'E', 'B', 'C', 'D']

2.4 删除元素

  • 跟插入元素相同,删除元素也需要移动元素
  • 数组中元素不能删除,只能覆盖
  • 若删除索引 1 处的元素,就要将索引 1 之后的元素都往前移动一位,如下图所示:
    在这里插入图片描述
    删除 E 后, 你会发现数组中最后有两个 D ,这个我们之后在讨论

代码如下(示例):

def remove(nums, index):
    """
    删除索引 index 处的元素
    :param nums: 传入的数组
    :param index: 要删除的元素的索引
    :return: 无
    """
    # 把索引 index 之后的所有元素向前移动一位
    for i in range(index, len(nums) - 1, 1):
        nums[i] = nums[i + 1]


if __name__ == '__main__':
    nums = ['A', 'E', 'B', 'C', 'D']
    print(f'删除前的数组为{nums}')   # ['A', 'E', 'B', 'C', 'D']
    remove(nums, 1)
    print(f'删除后的数组为{nums}')   # ['A', 'B', 'C', 'D', 'D']

三、数组扩展

3.1 遍历数组

  • 我们既可以通过索引遍历数组,也可以直接遍历获取数组中的每个元素

代码如下(示例):

def traverse1(nums):
    """遍历数组"""
    count = 0
    # 通过索引遍历数组
    for i in range(len(nums)):
        print(nums[i])
        count += 1

def traverse2(nums):
    # 直接遍历数组元素
    for num in nums:
        print(num)

def traverse3(nums):
    # 同时遍历数据索引和元素
    # enumerate()函数会返回一个枚举对象,这个对象包含了列表中每个元素的索引和值。
    # enumerate函数默认从0开始计数索引,如果你需要从其他的数字开始,可以通过传递一个可选的起始参数来实现。
    for i, num in enumerate(nums):
        print(f'索引是{i},对应的元素是{num}')



if __name__ == '__main__':
    nums = ['A', 'B', 'C', 'D', 'E']
    traverse1(nums)   #  A   B   C    D    E 
    traverse2(nums)   #  A   B   C    D    E 
    traverse3(nums)   #  A   B   C    D    E 

3.2 数组扩容

  • 在Python中数组的长度是不可变的,因为程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。
  • 如果我们想要扩容数组的话,只能重新建立一个新数组,然后将原数组的元素依次复制到新数组,这是一个时间复杂度为 O ( n ) O(n) O(n)的操作,当数组很大的时候,很消耗时间。

代码如下(示例):

def extend(nums, enlarge):
    """
    扩展数组长度
    :param nums: 原数组
    :param enlarge: 要扩多大的空间
    :return: 返回扩容后的新数组
    """

    # 初始化一个扩展长度后的数组
    res = [0] * (len(nums) + enlarge)
    # 将原数组中的所有元素复制到新数组
    for i in range(len(nums)):
        res[i] = nums[i]
    # 返回扩展后的新数组
    return res



if __name__ == '__main__':
    nums = ['A', 'B', 'C', 'D', 'E']
    print(f'扩容前的数组为{nums}') # ['A', 'B', 'C', 'D', 'E']
    res = extend(nums, 3)
    print(f'扩容后的数组为{res}')  # ['A', 'B', 'C', 'D', 'E', 0, 0, 0]

总结

1、数组的优点

  • 空间效率高:数组为数据分配了连续的内存块,无须额外的结构开销。
  • 支持随机访问:数组允许在 O ( 1 ) O(1) O(1) 时间内访问任何元素。
  • 缓存局部性:当访问数组元素时,计算机不仅会加载它,还会缓存其周围的其他数据,从而借助高速缓存来提升后续操作的执行速度

2、数组的不足

  • 插入与删除效率低:当数组中元素较多时,插入与删除操作需要移动大量的元素。
  • 长度不可变:数组在初始化后长度就固定了,扩容数组需要将所有数据复制到新数组,开销很大。
  • 空间浪费:如果数组分配的大小超过实际所需,那么多余的空间就被浪费了。

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

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

相关文章

中资优配:炒股最笨十句口诀?

在出资股票时,出资者假设掌握一些方法技巧等,可以协助出资者更好地在股市进行生意,下面为我们介绍炒股十大口诀。 1、不跳水不买,不冲高不卖,横盘不生意 不要在股价跳水时急速买入,也不要在股价一开始冲高…

薛定谔的空气墙?一文带你了解其背后的技术原理

封面图 悟空来了都得撞墙? 目前,被称作“村里第一个大学生”的国产3A游戏《黑神话:悟空》发售已经有一段时间了,游戏采用虚幻引擎4技术,仿佛将传统与现代的界限模糊,玩家游玩时沉浸感极强。然而&#xff…

C# 窗口页面布局

1.Groupbox 单机鼠标右键,置于底层 2.Label 在右方属性中修改名称 3.ComboBox 点击属性中的集合,可以添加选择项 4.CheckBox 在属性中修改名称 5.RichTextBox 富文本 在属性中修改名称与区域 6.StatusStrip 状态栏 将AutoSize改成false就可以修改…

带你速通C语言——结构体(18)

结构体是 C 语言中用于创建复杂数据类型的关键工具。它们允许将多个变量(可能是不同类型的)组合成一个单一的实体,这对于组织和处理数据非常有用。这使得结构体成为数据库记录、配置设置、复杂数据交换等应用的理想选择。 1.定义结构体 结构…

NX二次开发——基础

1.打开信息窗口并写入 UC1601是将想显示的内容显示在一个UI消息框中,或者是状态栏,如果内容很多的时候,就不适合使用UC1601 使用信息窗口,相关命令:信息->....... 要实现这个功能具有的逻辑,先是要打…

【Kubernetes部署篇】二进制搭建K8s高可用集群1.26.15版本(超详细,可跟做)

文章目录 一、服务器环境信息及部署规划1、K8S服务器信息及网段规划2、服务器部署架构规划3、组件版本信息4、实验架构图 二、初始化环境操作1、关闭防火墙2、配置本地域名解析3、配置服务器时间保持一致4、禁用swap交换分区(K8S强制要求禁用)5、配置主机之间无密码登录6、修改…

ArkUI-状态管理-@Provide、@Consume、@Observed、@ObjectLink

ArkUI-状态管理 Provide装饰器和Consume装饰器:与后代组件双向同步概述观察变化框架行为Provide支持allowOverride参数 Observed装饰器和ObjectLink装饰器:嵌套类对象属性变化概述限制条件观察变化框架行为 Provide装饰器和Consume装饰器:与后…

【python计算机视觉编程——4.照相机模型与增强现实】

python计算机视觉编程——4.照相机模型与增强现实 4.照相机模型与增强现实4.1 真空照相机模型4.1.1 照相机矩阵4.1.2 三维点的投影4.1.3 照相机矩阵的分解4.1.4 计算照相机中心 4.2 照相机标定4.3 以平面和标记物进行姿态估计sift.pyhomography.py主函数homography.pycamera.py…

开源 AI 智能名片 O2O 商城小程序在营销中的应用

摘要:本文探讨了开源 AI 智能名片 O2O 商城小程序在营销中的应用,重点分析了喜好原则、互惠互利和高度认可三个方面对小程序推广和用户忠诚度提升的重要性。通过融入这些原则,开源 AI 智能名片 O2O 商城小程序能够更好地满足用户需求&#xf…

UnsupportedOperation: not readable 解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【操作系统】同步互斥与Golang互斥锁实现

【操作系统】同步互斥问题与Golang互斥锁实现 1 背景1.1 独立线程1.2 合作线程1.3 合作有风险,为什么需要合作1.4 多协程并发执行的风险举例(Golang语言)1.5 对风险的思考 2 同步互斥2.1 一些概念2.2 解决方案——保护临界区2.3 禁用硬件中断…

【转变之旅】从程序员到AI绘画艺术家,我的月入过万之路

曾经,我的生活平淡如水,作为一名程序员,每天重复着朝九晚五的工作。然而,一场突如其来的裁员,让我陷入了失业的深渊。为了生活,我选择了开滴滴谋生。没想到,这个看似权宜之计的决定,…

计算机网络——ARP篇

最近在学习计算机网络,做一下学习笔记: 抛出疑问?什么是ARP?ARP协议的作用是什么?ARP的工作原理是什么?ARP有哪些类型? 首先,我们要了解ARP的概念,ARP(Addre…

python计算机视觉编程——照相机模型与增强现实

一、针孔照相机模型 针孔照相机模型(有时称为射影照相机模型)是计算机视觉中广泛使用的照相机模型。针孔照相机模型简单,并且具有足够的精确度。这个名字来源于一种类似暗箱机的照相机。该照相机从一个小孔采集射到暗箱内部的光线。在针孔照相机模型中,在光线投影到图像平面之…

Windows 11 下使用 MSVC 2022 编译64位Nginx

一、软件准备 1、安装 Visual Studio 2022 包含单个组件: .NET Framework 4.6.1 目标包.NET Framework 4.6.1 SDKWindows 通用 C 运行时Windows 通用 CRT SDKMSVC v142 - VS 2019 C x64/x86 生成工具(v14.26)对 v142 生成工具(14.21)的 C/CLI 支持Clang compile fo…

Linux中MFS分布式文件系统(实战教程)全网最详细

MFS架构图 元数据服务器(Master):在整个体系中负责管理文件系统,维护元数据。 元数据日志服务器(MetaLogger):备份Master服务器的变化日志文件,文件类型为 changelog_ml.*.mfs。当 …

第六届机器学习、大数据与商务智能国际会议(MLBDBI 2024)

目录 主办单位 大会简介 会议组委会 征稿主题 参会方式 会议日程 重要信息 大会官网:www.mlbdbi.org 会议时间:2024年11月1-3日 会议地点:中国-杭州 收录检索:EI Compendex,Scopus 主办单位 大会简介 由…

SSD300模型总结

1、SSD网络结构 SSD以VGG16作为特征提取特征的基础模型,然后在VGG16的基础上增加了额外的卷积和池化操作来获得更多不同尺度的特征图用来检测不同大小的目标 本文主要是SSD300作为例子进行分析 整体主要分为3个部分 backbone网络:VGG16Extra网络&…

使用Mid360进行FAST_LIO建图,并使用Octomap在线转栅格地图

在之前的教程中,我们已经成功的安装了激光雷达驱动,成功复现了FAST_LIO,并使用OCtomap将点云地图转为栅格地图。 但是之前我们是建图生成了.PCD文件后,读取pcd文件进行离线octomap转栅格地图,这样在实际的场景中并不完…

Python实现贝叶斯优化器(Bayes_opt)优化卷积神经网络-双向长短时记忆循环神经网络分类模型(CNN-BiLSTM分类算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 随着深度学习技术的发展,卷积神经网络(Convolutional Neural Networks, CNNs&a…