一、数组定义
一种线性表数据结构。数组在连续内存空间中存储相同类型的元素。顺序结构存储
1.数组的下标是从0开始的
2.数组内存空间是连续的
3.数组不能删除,只能覆盖
4.数组中的数据元素可随机访问
注意:区分元素与索引;区分访问与搜索
PS:数组和指针都可以像标准库的vector一样顺序地遍历一组数据,然而他们与vecto相比却能更直接地接触到计算机的内存,因此在高效的同时也会有更大的风险。所以在一般情况下,推荐使用vector。 vector 的push_back()操作可以无限的添加元素,因此vector 是动态的,而数组是一种完全静态的数据结构,在初始化的时候要给数组指定大小,并且不能修改。
vector与array:vector的底层实现是array,严格来讲vector是容器,不是数组。
二、算法复杂度
访问(Access)-O(1)
搜索(Search)-O(N)
插入(Insert)-O(N)
删除(Delete)-O(N)
三、常用操作
创建数组
1.array
一维:数据类型 数据名[x];
二维:数据类型 数组名[x][y];
初始化:一维数组的初始化,需要给出用逗号隔开的从第一个元素开始的若干个元素的初值,并用大括号括住。后面未被赋初值的元素默认为0
在多数情况下,C++将数组名解释为数组第一个元素的地址 二维数组名是地址的地址,必须两次取值才可以取出数组中存储的数据
2.vector
vector<int>nums;//创建整型一维数组
vector<int>nums(n);//指定长度为n
vector<int>nums(5,3);//创建[3 3 3 3 3]
vector<vector<int>>nums;//创建数组
vector<vector<int>>nums(3);//创建三行的数组
vector<vector<int>>nums(3,vector<int>(5,0)); //创建三行五列的数组,初始值为0
注意:vector 在创建的时候需要元素类型和名称两个信息,大小可以在初始化的时候指定,也可以不指定。 由于数组是静态的一定要为其指定大小,称作数组的维度。
访问/修改元素
访问元素思路-下标访问
1.判断是否在合法区间
2.由给定下标得到元素的值
修改元素思路-访问后直接赋值
遍历数组
1.array-for循环遍历
for (int i = 0; i < a.size(); i++) {
cin >> a[i];
}
2.vector
//第一种遍历方式,下标
cout << "第一种遍历方式,下标访问" << endl;
for (int i = 0; i<m_testPoint.size(); ++i)
{
cout << m_testPoint[i].x << " " << m_testPoint[i].y << endl;
}
//第二种遍历方式,迭代器
cout << "第二种遍历方式,迭代器访问" << endl;
for (vector<Point>::iterator iter = m_testPoint.begin(); iter != m_testPoint.end(); iter++)
{
cout << (*iter).x << " " << (*iter).y << endl;
}
//第三种遍历方式,auto关键字
cout << "C++11,第三种遍历方式,auto关键字" << endl;
for (auto iter = m_testPoint.begin(); iter != m_testPoint.end(); iter++)
{
cout << (*iter).x << " " << (*iter).y << endl;
}
//第四种遍历方式,auto关键字的另一种方式
cout << "C++11,第四种遍历方式,auto关键字" << endl;
for (auto i : m_testPoint)
{
cout << i.x << " " << i.y << endl;
}
查找元素
查找元素思路-循环
1.建立基于下标的循环,比较val与nums[i]
2.找到元素返回元素下标
3.遍历完找不到则返回特殊值
for i in range(len(nums)):
if nums[i] == val:
return i
添加/插入元素
1.array
定义时就已经在栈上分配空间大小,运行时不改变,不能直接添加/插入,但可以赋值。
nums[0]=1;
数组增加元素的思路:
- 建一个新的数组,数组长度为原数组的长度加一。
- 将需要增加的元素值赋给数组的最后一个元素。
- 将新的数组赋给原来的数组
//参考代码:在一个数组的第x个位置插入一个新的数y
#include <iostream>
using namespace std;
int main() {
int n, x, y, a[11];
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
cin >> x;
cin >> y;
x--;
for (int i = n - 1; i >= x; i--) {
a[i + 1] = a[i];
}
a[x] = y;
n++;
for (int i = 0; i <= n - 1; i++) {
cout << a[i] << " ";
}
}
2.vector
nums.push_back(a);//在数组末尾添加a
num[i]=2;//直接赋值
//整体赋值:3种方法
//1.等号直接赋值
vector<int>nums1;
nums1=nums;
//2.assign函数赋值
nums1.assign(nums.begin().nums.end());//也可以用迭代器
//3.for循环赋值
vector<int> :: iterator iter;
for(iter=nums.begin();iter!=nums.end();iter ++){
nums1.push_back(*iter);
}
assign函数原型
void assign(const_iterator first,const_iterator last);
void assign(size_type n,const T& x = T());
/*
功能:
第一个相当于拷贝函数,把first到last的值赋值给调用者,注意区间的闭合,即:将区间 [first,last) 的元素赋值到当前的 vector 容器中;
第二个是把n个x赋值给调用者,即:赋 n 个值为 x 的元素到 vector 容器中,并且清除掉 vector 容器中以前的内容。
*/
注意:vector容器是不能够通过下标操作添加元素的,只有已经存在的元素才能用下标索引,否则会报错。参见【C++ Error】runtime error -vector的初始化问题-CSDN博客
删除元素
1.array 定义时就已经在栈上分配空间大小,运行时不改变,不能直接删除,但可以覆盖。
数组删除的思路
- 创建一个新数组,数组长度为原来数组的长度减一
- 定义需要删除的元素下标
- 将删除下标之前的元素赋给新数组的下标值,删除下标之后的元素赋给新数组下标值-1
//代码待补充
2.vector
//删除最后一个元素
nums.resize(nums.size()-i);//减少i个元素
nums.pop_back();//括号里面不用加东西,删除最后一个元素
//删除某段元素或某位上的元素
#include <algorithm> // [注意] :remove位于algorithm函数库中
a.erase(remove(a.begin(),a.end(),2),a.end());//erase里面放迭代器
//基于条件删除元素-循环查找元素后删除,同样erase
remove函数本质上其实并没有完成元素的完全删除工作,因为容器的大小都没有改变,它只是将所有被删除的元素用下一个不被删除的元素进行覆盖,同时返回一个迭代器,在该迭代器之前的所有元素,保留原容器的顺序,并且不存在被删除的元素,也就是你想要的容器内容,而该迭代器到容器的末尾则不变,也就是说,原容器的大小没有发生变化,被删除的元素也确实没有了,但容器末尾的一些元素(个数等于被删除元素个数)又会多出来一份,这是我们不愿意看到的,因此需要借助上面提到的erase函数。所以说remove需要和erase搭配使用才能实现完整的删除功能。
注意:vector容器是不能够通过下标操作添加元素的,只有已经存在的元素才能用下标索引,否则会报错。参见【C++ Error】runtime error -vector的初始化问题-CSDN博客
数组的长度
//一维
nums.size();//数组的长度
cout << nums[0] << endl;//输出第一个元素
cout << nums[nums.size()-1] << endl;//输出最后一个元素
nums.resize(m);//长度改为m
//二维
m=A.size();//row
n=A[0].size();//column
是否为空,清空
1.array
int nums[] = {1,2,3};
//先计算数组长度
nums_length = sizeof(nums)/sizeof(nums[0]);
//再判断是否为0
2.vector
nums.empty(); //判断是否空
nums.clear(); //清空
vector<int>().swap(nums); //清空,将容器与空容器交换从而删除容器数据并收回内存
nums.shrink_to_fit(); // 将vector 容器的容量缩减至和实际存储元素的个数相等
排序、翻转、合并
#include<algothrim>
sort(nums.begin(),nums.end());//从小到大排序
sort(nums.begin(),nums.begin()+3);//排序前面三个数
reverse(nums.begin(),nums.end());//翻转
//将nums1和nums2合并
vector<int>nums1(m),nums2(n);
vector<int>nums;
nums.resize(m+n);
merge(nums1.begin(),nums1.end(),nums2.begin(),nums2.end(),nums);
四、参考
vector容器v1、v2之间相互赋值的三种方法及易错点详解_两个vector赋值-CSDN博客
01. 数组基础知识 | 算法通关手册(LeetCode) (itcharge.cn)
C++ Vector遍历的几种方式_遍历vector-CSDN博客