【算法与数据结构】数组
文章目录
- 前言
- 数组
- 数组的定义
- 数组的基本操作
- 增加元素
- 删除元素
- 修改元素
- 查找元素
- 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语言版)
一.栈的概念 栈是一种常见的数据结构,它遵循后进先出的原则。栈可以看作是一种容器,其中的元素按照一种特定的顺序进行插入和删除操作。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫做…...

(贪心05) 无重叠区间 划分字母区间 合并区间
一、无重叠区间 力扣第435题 第一种方法: 个人思路: 按照区间左边界排序,然后从左开始遍历,每遍历到一个区间就要保证该区间之前的集合为不重叠区间(贪心,局部最优解)。 难点在于如何把新遍历…...

简单网络管理协议(SNMP)入门
目录 概述 SMI(对象命名、数据类型、编码方法) 对象命名 数据类型 编码方法 MIB(版本、分组、对象定义、变量访问) 版本 分组 对象定义 变量访问 SNMP 实现机制与报文分析 协议操作 报文格式 实现机制 验证分析 SN…...

leetcode解题思路分析(一百五十七)1366 - 1372 题
通过投票对团队排名 现在有一个特殊的排名系统,依据参赛团队在投票人心中的次序进行排名,每个投票者都需要按从高到低的顺序对参与排名的所有团队进行排位。 排名规则如下: 参赛团队的排名次序依照其所获「排位第一」的票的多少决定。如果存在…...

药物代谢动力学学习笔记
一、基本概念 二、经典房室模型 三、非线性药物代谢动力学 四、非房室模型 五、药代动力学与药效动力学 六、生物等效性评价 七、生物样品分析方法 基本概念 生物样品:生物机体的全血、血浆、血清、粪便、尿液或其他组织的样品 特异性,specificity&…...

IDEA中git的常用操作(保姆级教学)
IDEA中git的常用操作(保姆级教学) 以下是git的工作原理,觉得繁琐的可以跳过不看 Workspace:工作区 (平时存放代码的地方) Index / Stage:暂存区(用于临时存放存放你的改动,事实上就是一个文件&…...

保研面试408复习 3——操作系统
文章目录 1、操作系统一、进程有哪几种状态,状态之间的转换、二、调度策略a.处理机调度分为三级:b.调度算法 标记文字记忆,加粗文字注意,普通文字理解。 为什么越写越少? 问就是在打瓦。(bushi) 1、操作系统 一、进程…...

【代码随想录37期】Day02 有序数组的平方、长度最小的子数组、螺旋矩阵Ⅱ(施工中)
有序数组的平方 977. 有序数组的平方 - 力扣(LeetCode) v1.0:直接暴力 4分半做出来,用sort api class Solution { public:vector<int> sortedSquares(vector<int>& nums) {vector<int> result;for(int i 0; i<…...

通俗的理解网关的概念的用途(三):你的数据包是如何到达下一层的
其实,这一章我写不好,因为这其中会涉及到一些计算和一些广播等概念,本人不善于此项。在此略述,可以参考。 每台设备的不同连接在获得有效的IP地址后,会根据IP地址的规则和掩码的规则,在操作系统和交换机&a…...

基于Springboot的校运会管理系统(有报告)。Javaee项目,springboot项目。
演示视频: 基于Springboot的校运会管理系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&a…...

USP技术提升大语言模型的零样本学习能力
大语言模型(LLMs)在零样本和少样本学习能力上取得了显著进展,这通常通过上下文学习(in-context learning, ICL)和提示(prompting)来实现。然而,零样本性能通常较弱,因为缺…...