【算法与数据结构】数组
文章目录
- 前言
- 数组
- 数组的定义
- 数组的基本操作
- 增加元素
- 删除元素
- 修改元素
- 查找元素
- C++ STL 中的数组
- array
- vector
- Python3 中的列表
- 访问
- 更改元素值
- 遍历列表
- 检查列表中是否存在某元素
- 增加元素
- 删除元素
- 拷贝列表
- 总结 Python3 列表的常用操作
- 参考资料
- 写在最后
前言
本系列专注更新基本数据结构,现以更新:
【算法与数据结构】数组.
【算法与数据结构】哈希表.
数组
数组的定义
数组是一种在内存中有着一块连续的内存空间的,并且由相同类型的元素组成的线性数据结构。以整数数组为例,数组的存储方式如下图所示:
在上图中可以看出数组在计算机中就是内存中一块连续的存储单元。数据元素的内存地址表示的就是该元素存放在内容中的地址,因为整型数据占据四个字节大小的内存,所以相邻两个元素地址之间相差 4。
在上图所示的数组中,数据元素的个数为 7,并且数组中都是整型元素。数组中每一个元素都可以通过「下标索引」来获取。下标索引从 0 开始(在计算机中数数都是从 0 开始),到数据元素的个数减一。
之所以称数组是一种线性数据结构是因为数组中所有数据元素排成像一条线一样的结构,每个数据元素最多只有前、后两个方向。链表、栈、队列这几种数据结构也有这样的线性特征。
数组的基本操作
几乎所有的数据结构都会涉及到增、删、改、查四个基本操作,数组也不例外。
增加元素
增加元素之前需要先检查数组是否已经满了(达到最大容量),如果满了就需要重新在内存中找到一块连续的地方放置原来数组中的元素以及新加入的元素。如果使用的是 C++ 中的 vector 容器,就不用担心容量不够的问题,因为在数组容量不够时 vector 会自动扩容。通常在数组尾部增加元素的时间复杂度为 O ( 1 ) O(1) O(1)。
如果在数组 nums 中位置 i 处插入一个新的元素 val,通常有以下步骤:
- 先检查
i是否有效,即在数组的下标范围内; - 确认有效后,检查数组
i处是否已经存在元素了:- 没有元素当然好,直接更新
nums[i] = val; - 但是通常会有元素,这时候就需要将
i及之后位置的元素向后挪动一个位置,然后将val放在空出来的位置i处。
- 没有元素当然好,直接更新
- 这种插入情况最坏的时间复杂度为 O ( n ) O(n) O(n), n n n 是整个数组的长度。
这里就不考虑插入元素时数组满了的问题了,因为在 C++ 程序中通常都使用 vector 作为数组,这样一旦满了就会自动扩容。
删除元素
删除元素也分几种情况:
- 删除数组尾部元素,直接将数字计数值减一即可,这通常是 C 语言中的做法。前面已经说了 C++ 中几乎都用 vector 这个可动态扩容的数组,于是删除尾部元素直接
pop_back()。在 Python3 中直接pop()。 - 删除数组
nums中位置i的元素,通常有两个方法,当然在使用两个方法之前都要先检查i是否有效:- 借助临时数组:将原数组
nums中除了i位置表示的元素之外的所有元素复制到临时数组中,然后清空数组nums,最后再将临时数组中元素复制到nums中。这种方法需要遍历两次数组,渐进时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)。 - 原地操作:利用
i位置后一位置的元素去覆盖i位置,即i+1位置的元素去覆盖i位置的元素,i+2位置的元素去覆盖i+1位置的元素,以此类推,直到i = n,最后再把最有一个元素删掉。时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)。通常有关原地删除数组中元素的操作指的就是 覆盖。
- 借助临时数组:将原数组
- 最后一种情况就是「基于特定条件进行删除」,那就需要遍历数组,根据条件筛选出需要删除的元素或位置,一个个删除就好了。
通常删除操作的时间复杂度为 O ( n ) O(n) O(n)。
修改元素
这种操作就简单了。通过遍历数组找到需要修改的元素,直接修改即可。这种操作的时间复杂度为 O ( n ) O(n) O(n)。
查找元素
这种操作也很简答。如果是查找指定下标的元素,直接进行索引查找即可,时间复杂度为 O ( 1 ) O(1) O(1)。如果需要查找指定元素,那也不难,一次遍历即可,时间复杂度为 O ( n ) O(n) O(n)。
C++ STL 中的数组
在 C++ 标准库中定义两种类型的数组:array 和 vector。
array
array 是一种定长数组,也就是 C/C++ 中描述并使用的那种数组,使用之前要定义数组中的数据类型和固定的数组长度。
初始化
#include <iostream>
#include <array> // array 的头文件using namespace std;int main() {// 初始化列表 初始化 array<int, 7> myArr = {1, 4, 6, 8, 9, 1, 3};// 拷贝初始化array<int, 7> myArr2 = myArr;for (const auto& num : myArr2) {cout << num << " ";}return 0;
}
array 有两种初始化方法:初始化列表初始化和拷贝初始化。
重要的成员函数
| 成员函数 | 释义 |
|---|---|
| begin | 首迭代器 |
| end | 尾后迭代器 |
| size | 数组大小 |
| empty | 数组是否为空 |
| operator[] | 索引元素 |
| at | 索引元素 |
| font | 数组的第一个元素 |
| back | 数组的最后一个元素 |
| fill | 填充数组 |
| swap | 两个数组交换 |
vector
vector 是一种容器,是一种可变长的数据。当向 vector 容器中增加数据时,如果容器已经满了,那么它会重新在内存中找一块更大的连续内存来存放原来的数据。通常是按照原来内存的两倍大小进行扩容的。得益于自动扩容的特性,C++ 中多使用 vector 来构造数组。
初始化(构造函数)
#include <iostream>
#include <vector>int main () {// constructors used in the same order as described above:std::vector<int> first; // empty vector of intsstd::vector<int> second (4,100); // four ints with value 100std::vector<int> third (second.begin(),second.end()); // iterating through secondstd::vector<int> fourth (third); // a copy of third// the iterator constructor can also be used to construct from arrays:int myints[] = {16,2,77,29};std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );std::cout << "The contents of fifth are:";for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}
重要的成员函数
| 成员函数 | 释义 |
|---|---|
| begin | 首迭代器 |
| end | 尾后迭代器 |
| size | 数组大小 |
| capacity | 当前数组的存储容量 |
| empty | 数组是否为空 |
| reserve | 更改容量 |
| operator[] | 索引元素 |
| at | 索引元素 |
| font | 数组的第一个元素 |
| back | 数组的最后一个元素 |
| push_back | 在数组末尾增加元素 |
| pop_back | 删除最后一个元素 |
| clear | 清空容器 |
| swap | 两个数组交换 |
Python3 中的列表
python 中没有固定长度的数组,只有类似于 vector 容器的列表。
列表是一个有序且可更改的集合。集合中可以混合放置任意类型的元素,比如文本类型、数值类型和布尔类型,不要求必须放置同一类型的元素。
list1 = [8, "srt", 98, True]
此例中,列表 list1 包含了数值类型,文本类型和布尔类型的数据元素。
访问
可以通过索引来访问列表。
list1 = [8, "str", 98, True]print(list1[0]) # 输出 "str"
在 Python3 中索引可以是负值,负值索引表示从列表的末尾开始访问,-1 表示列表的最后一个元素,-2 表示列表的倒数第二个元素,等等。
list1 = [8, "str", 98, True]print(list1[-1]) # 输出列表的最后一个元素 True
范围索引
可以对列表指定起点、终点(取不到)和步长进行范围索引。
list2 = [1, 4, 5, 6]print(list2[0 : 3 : 2]) # 输出 [1, 5]
此例子对列表 list2 进行范围索引,从索引 0 开始,到索引 3 结束,每次在上一个索引的基础上 +2 进行访问。
负范围索引
范围索引还可以是负值。
list2 = [1, 4, 5, 6]print(list2[-4 : -1 : 2]) # 仍然输出 [1, 5]
此例子对列表 list2 进行负的范围索引,从倒数第 4 个元素开始索引,到倒数第一个元素结束(取不到),每次在上一个索引的基础上 +2 进行访问。
更改元素值
通过使用索引轻松更改元素值。
list2 = [1, 4, 5, 6]
list2[0] = 0 # 将列表第一个元素更改为 0print(list2) # 输出 [0, 4, 5, 6]
遍历列表
可以像 C/C++ 一样使用索引进行遍历,Python3 有自己的一种 for 遍历方法,C++ 中的 for 范围遍历对应的就是 Python3 中的范围遍历。
list3 = ["apple", "pear", "pineapple"]for x in list3:print(x)# 输出
"""
"apple"
"pear"
"pineapple"
"""
检查列表中是否存在某元素
如果需确定列表中是否存在指定的元素,使用 in 关键字:
list3 = ["apple", "pear", "pineapple"]if "apple" in list3:print("Yes, 'apple' is in the fruits list3.")
在此例中,如果文本 “apple” 在列表 list3 中,则 if 条件语句为 True,执行对应的语句,输出 "Yes, 'apple' is in the fruits list3.".
增加元素
如需将元素添加到列表的末尾,使用 append() 方法:
list3 = ["apple", "pear", "pineapple"]
list3.append("banana")print(list3) # 输出 ["apple", "pear", "pineapple", "banana"]
要在指定的索引处添加元素,使用 insert() 方法:
list4 = ["apple", "pear", "pineapple"]
list4.insert(1, "cherry")print(list4) # 输出 ["apple", "cherry", "pear", "pineapple"]
此例中,在列表 lsit4 的索引 1 处插入 “cherry”。
删除元素
通过 remove() 删除指定元素:
list5 = ["apple", "cherry", "pear", "pineapple"]
list5.remove("apple")print(list5) # 输出 ["cherry", "pear", "pineapple"]
通过 pop() 删除指定索引的元素(如果没有指定索引,则删除最后一项):
list6 = ["cherry", "pear", "pineapple"]
list6.pop()print(list6) # 输出 ["cherry", "pear"]
使用 del 关键字删除指定的索引,del 关键字也能完整地删除列表:
list7 = ["cherry", "pear", "pineapple"]
del list7[0]
print(list7) # 输出 ["pear", "pineapple"]del list7 # 直接删除 list7
使用 clear() 方法清空列表,这一点和 vector 中的 `clear() 一样:
list8 = ["apple", "banana", "cherry"]
list8.clear()print(list8) # 输出 []
拷贝列表
拷贝列表分为浅拷贝和深拷贝。见 Python之赋值、深拷贝与浅拷贝
总结 Python3 列表的常用操作
| 关键字 | 释义 |
|---|---|
| list() | 生成列表 |
| append() | 在列表尾追加元素 |
| insert() | 在指定位置插入元素 |
| pop() | 移除列表尾元素 |
| remove() | 移除列表中指定元素 |
| clear() | 清空列表 |
| del | 清空指定元素或列表 |
| + | 合并两个列表 |
| extend() | 在一个列表后追加另一个列表 |
| len() | 列表的长度 |
| sort() | 排序(默认升序) |
| reverse() | 反转列表 |
| copy() | 浅拷贝 |
| copy.deepcopy() | 深拷贝 |
参考资料
【文章】01. 数组基础知识
【文章】Python 列表
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家觉得有些地方需要补充,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。
相关文章:
【算法与数据结构】数组
文章目录 前言数组数组的定义数组的基本操作增加元素删除元素修改元素查找元素 C STL 中的数组arrayvector Python3 中的列表访问更改元素值遍历列表检查列表中是否存在某元素增加元素删除元素拷贝列表总结 Python3 列表的常用操作 参考资料写在最后 前言 本系列专注更新基本数…...
【数据结构】队列详解(Queue)
文章目录 有关队列的概念队列的结点设计及初始化队列的销毁判空和计数入队操作出队操作 有关队列的概念 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)入队列:进行插入操作的一端…...
Baumer工业相机堡盟工业相机如何通过NEOAPISDK获取相机的Statistics图像传输统计信息(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPISDK获取相机的Statistics图像传输统计信息(C#) Baumer工业相机Baumer工业相机NEOAPI SDK和相机Statistics图像传输统计信息的技术背景Baumer工业相机通过NEOAPISDK获取相机的Statistics图像传输统计信息技术1.引…...
FreeRTOS标准库例程代码
1.设备STM32F103C8T6 2.工程模板 单片机: 部分单片机的程序例程 - Gitee.comhttps://gitee.com/lovefoolnotme/singlechip/tree/master/STM32_FREERTOS/1.%E5%B7%A5%E7%A8%8B%E6%A8%A1%E6%9D%BF 3.代码 1-FreeRTOS移植模板 #include "system.h" #include "…...
wandb: - 0.000 MB of 0.011 MB uploaded持续出现的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
分布式模式让业务更高效、更安全、更稳定
🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》 💪🏻 制定明确可量化的目标,坚持默默的做事。 🚀 转载自热榜文章🔥:探索设计模式的魅力:分布式模…...
5.11学习记录
20长安杯部分 检材 1 的操作系统版本 CentOS Linux 7.6.1810 (Core) 检材 1 中,操作系统的内核版本是 3.10.0-957.el7.x86_64 检材 1 中磁盘包含一个 LVM 逻辑卷,该 LVM 开始的逻辑区块地址(LBA)是 2099200 物理卷ÿ…...
Java类加载器介绍
在Java中,类加载器是一种动态加载类的机制,它负责在运行时查找、加载和链接类文件。当Java应用程序需要创建某个类的对象时,类加载器会在运行时查找该类对应的.class文件,并将其加载到Java虚拟机中。Java类加载器通常分为三层&…...
VC++ PDH/性能计数器
例子: PID0,缺省为当前进程,但最好是获取当前进程ID传递进去,当然也可以选择其它进程的ID。 PerformanceCounter pc; pc.Open(0, "//Processor(_Total)//% Processor Time"); 源实现: #include <windo…...
C++ 类和对象:面向对象编程基础
目录标题 1. 什么是类?2. 什么是对象?3. 如何定义一个类?4. 如何创建对象?5. 类的构造函数6. 类的析构函数7. 数据封装和访问修饰符8. 示例:一个简单的BankAccount类9. 使用g编译10. 再来一个简单的C程序11. 定义书籍类…...
linux 基础命令使用
命令 su 用于切换到另一个用户身份,通常是超级用户(root)。su命令可以用来在命令行下切换用户,也可以在脚本中使用。 语法: su [选项] [用户名] 选项: - -c:执行完命令后,立即退出su命令;…...
eve 导入linux
mkdir /opt/unetlab/addons/qemu/linux-centos7 cd /opt/unetlab/addons/qemu/linux-centos7 上传hda.qcow2 /opt/unetlab/wrappers/unl_wrapper -a fixpermissions Linux images - (eve-ng.net) Due to very high demand of this section and problems with how to crea…...
vivado新版本兼容老版本,vitis classic兼容sdk教程
new version: vivado版本2023.2 和vitisv classic 2023.2 old version: vivado 2018.3以及之前的版本 打开工程 自动升级到当前版本,选择OK 点击Yes,合并当前的目录架构 点击OK 点击Report IP status 勾选要升级的IP核,点击升级 在项目工程文件夹…...
02.02.返回倒数第k个节点
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。 注意:本题相对原题稍作改动 示例: 输入: 1->2->3->4->5 和 k 2 输出: 4 说明: 给定的 k 保证是有效的。 代码ÿ…...
MongoDB 从部署到掌握
一、docker部署MongoDB ## 通过docker安装MongoDB~~~shell #拉取镜像 docker pull mongo:4.0.3#创建容器 docker create --name mongodb-server -p 27017:27017 -v mongodb-data:/data/db mongo:4.0.3 --auth#启动容器 docker start mongodb-server#进入容器 docker exec -it …...
electron-vite工具打包后通过内置配置文件动态修改接口地址实现方法
系列文章目录 electronvitevue3 快速入门教程 文章目录 系列文章目录前言一、实现过程二、代码演示1.resources/env.json2.App.vue3.main/index.js4.request.js5.安装后修改 前言 使用electron-vite 工具开发项目打包完后每次要改接口地址都要重新打包,对于多环境…...
每日一练2024.5.9
题目: 给定一副牌,每张牌上都写着一个整数。 此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组: 每组都有 X 张牌。组内所有的牌上都写着相同的整数。 仅当你可选的 X > 2 时返回 tru…...
P2622 关灯问题
小小注解: 1. vis:表示到达该状态的步数(min)1, 因为我们是从开始状态 穷举,所以每次到一个新状态(之前没有到过的状态)就是最小步数。 如何判断是否是一个新状态呢,…...
从头开始的建材类电商小程序开发指南
在当今数字化时代,小程序已经成为了许多企业推广和销售的重要渠道。对于建筑材料行业来说,开发一个属于自己的小程序商城不仅可以提升产品曝光度,还可以提供更好的用户购物体验。下面,我们将逐步教你如何开发建筑材料行业小程序。…...
数据结构中的栈(C语言版)
一.栈的概念 栈是一种常见的数据结构,它遵循后进先出的原则。栈可以看作是一种容器,其中的元素按照一种特定的顺序进行插入和删除操作。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫做…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
