C++ 容器之Vector

本文详细介绍了C++标准库中的vector容器,包括其基本操作如初始化、插入、删除、查找、排序等。讲解了vector的front()、back()函数,以及如何通过assign函数赋值。还讨论了vector与find、count函数的配合使用,以及resize()、reserve()的区别。此外,文章阐述了vector在执行clear()后的内存状态,并对比了vector与数组的区别。最后,对比了vector与list的优缺点,总结了vector的反向迭代器及其应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

vector

vector基本操作

vector的front()和back()函数

vector中元素的删除

vector返回最后一个元素

assign函数

vector与find函数 count函数

vector指定位置元素的插入: 

swap()函数

vector执行clear()函数后内存的变化:

vector构建二维数组 

vector二维数组 排序函数sort()的使用

 resize()和reserve()函数的区别

vector遍历元素的新写法: 

vector之反向迭代器 

vector与list的对比

vector与数组的区别:

vector

vector即向量,可理解为“长度根据需要而自动改变的数组”

数组跟vector的区别在于:数组是静态分配空间,一旦分配了空间的大小,就不可以再改变了;

而vector是动态分配内存,随着元素的不断插入,它会按照自身的一套机制不断扩充自身的容量, vector容器的容量增长是按照容器现有容量的一倍进行增长。 先另外复制2倍的vector空间,此时vector占有的空间是原来的三倍,再删除原来1倍的vector空间。空间复杂度增大。

vector基本操作

#include <vector>
vector<int> vec;

几种初始化
vector<int> vec;
vector<int> a(10,1);//定义具有10个整型元素的向量,且给出的每个元素初值为1
vector<int> vec(a);//用已有vector数据a来初始化vec
vector<int> vec(a.begin(),a.begin()+2);
vector<int> vec{1,3,5};//常用在vector类型数据的返回,如:return vector<int> {1,2}
vector<int> vec={1,3,5};
vec.push_back();//尾端插入
vec.pop_back();//尾端弹出

vec.size();//vector内实际数据的个数
vec.capacity();//vector被重新分配内存前,可容纳数据的多少,即vector的容量

vec.clear();//清空vector内的数据,但不会释放内存

sort(vec.begin(),vec.end(),comp);//排序函数,comp可以是函数或函数对象

reverse(vec.begin(),vec.end());//反转函数,将vec内的元素倒序放置
                               //如(1,4,5,3) 变为 (3,5,4,1)

vector的front()和back()函数

vector<int> vec{1,3,4,5};
cout<<vec.front()<<endl;//返回第一个元素的值 1
cout<<vec.end()<<endl;//返回最后一个元素的值 5

vector中元素的删除

vec.erase(vec.begin()+i);//删除下标为i的元素
vec.erase(vec.begin()+i,vec.begin()+j);//删除下标为i到j的元素

TIPS: 

调用erase函数时,会返回一个iterator ,指向删除元素的下一个元素。即后面的元素会自动向前补位。所以在用for循环删除元素时,迭代器不用++指向下一个元素,erase()执行后,自动返回一个迭代器指向下一个元素。

vector返回最后一个元素

vector中的end()函数 返回一个迭代器,它指向容器的最后一个元素的下一个位置,即指向的是最后的结束符,所以不能用end()来返回最后一个元素。

 vector<int> vec;
方法一:
vector<T>::iterator it = vec.end()-sizeof(int);
 int result= *it;

方法二:
vec.back();

方法三:
* vec.rbegin();

assign函数

void assign(const_iterator first,const_iterator last)  相当于将vector数组中已有的一段拷贝复制给调用者,但是要注意,拷贝复制过来的不包括迭代器const_iterator last所表示的值,当然此函数也可以vector数组自己对自己调用。

vector<int> a1={1,2,3,4,5,6};
vector<int> a2;
a2.assign(a1.begin(),a1.begin()+5);//a2={1,2,3,4,5}
a2.assign(a2.begin()+1,a2.begin()+3);//a2={2,3}

vector与find函数 count函数

不同于map(map有find方法),vector本身是没有find这一方法,其find是依靠algorithm来实现的

vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    vec.push_back(4);
    vec.push_back(5);
    vec.push_back(6);
vector<int>::iterator it = find(vec.begin(), vec.end(), 6);
count(vec.begin(),vec.end(),target)//count函数

vector指定位置元素的插入: 

iterator insert( iterator loc, const TYPE &val ); 
在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器
void insert( iterator loc, size_type num, const TYPE &val );
在指定位置loc前插入num个值为val的元素 
void insert( iterator loc, input_iterator start, input_iterator end ); 
在指定位置loc前插入区间[start, end)的所有元素

示例 

//创建一个vector,置入字母表的前十个字符 
vector <char> alphaVector; 
for( int i=0; i < 10; i++ ) 
  alphaVector.push_back( i + 65 ); 

//插入四个C到vector中 
vector <char>::iterator theIterator = alphaVector.begin(); 
alphaVector.insert( theIterator, 4, 'C' ); 

//显示vector的内容 
for( theIterator = alphaVector.begin(); 
     theIterator != alphaVector.end(); theIterator++ ) 
  cout < < *theIterator; 

这段代码将显示:

CCCCABCDEFGHIJ

swap()函数

vector<int> vec_1;
vector<int> vec_2;

swap(vec_1[i],vec_1[j]);//互换vec_1中下标为i,j的两处数据
swap(vec_1[i],vec_2[j]);//互换vec_1中下标为i和vec_2中下标为j的数据

vec_1.swap(vec_2);//将两个vector的大小以及数据直接互换 可以用来释放空闲空间

vector执行clear()函数后内存的变化:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector <int >a;
	cout << a.empty() << endl;//输出   1  代表该vector此时是空
	a.push_back(1);
	a.push_back(2);
	cout << a[0] << " " << a[1] << endl;//输出1 2
	cout << a.empty() << endl;//输出 0 代表该vector此时非空
	cout << a.size() << endl;//输出2
	cout << a.capacity() << endl;//输出2
	cout << "***************" << endl;

	//a[0]=NULL;a[1]=NULL; 这是赋值为0,并不清空数据,也不释放内存。
	a.clear();
	cout << a[0] << " " << a[1] << endl;//仍然输出1 2,因为没有释放内存,
                                        //所以输出该地址的内容仍然与之前一样
	cout << a.empty() << endl;//输出1  代表该vector此时已经为空
	cout << a.size() << endl;//输出0,代表当前容器内存储元素个数是0,与.empty()类似,
                             //都告诉我们当前容器是空的意思
	cout << a.capacity() << endl;//输出2,代表当前该vector在重新分配存储空间前
                                 //所能容纳的元素数量并没有改变
	cout << "***************" << endl;

	/*
	下面这五行说明,.pop_back()与.clear()起到了相同的作用,都是清空数据,
    但是没有释放内存
	while(!a.empty()){
		a.pop_back();
	}
	cout<<a.empty()<<endl;//输出 1 代表该vector此时已经为空
	cout<<a[0]<<" "<<a[1]<<endl;//仍然输出为 1 2,因为没有释放内存,
                                //所以输出该地址的内容仍然与之前一样
	*/
	a.push_back(4);
	cout << a[0] << " " << a[1] << " " << a[2] << endl;//输出 4 2 0   
    //尽管没有释放内存,但是已经认为该vector已经被清空,所以再push_back();时,a[0]被覆盖。
	cout << a.size() << endl;//输出1,代表当前容器内存储元素个数是1,
                             //就是刚刚push_back();装进去的数起到的作用
	cout << a.capacity() << endl;//此时仍然输出2
	cout << "***************" << endl;

vector构建二维数组 

放代码:


//二维向量的定义
vector< vector<int> > b(10, vector<int>(5,0)); //创建一个10*5的int型二维向量b,初始值为0 
vector< vector<int> > b(5)//创建一个二维向量,只知道有5个int型vector,
                          //但每个vector所含元素个数未知

vector< vector<int> > b;//创建一个未知大小的int型二维向量b,
vector< vector< card > > cards( m, vector< card >(n,card)); //card为自定义结构体或类

vector< vector<int> > temp(b.begin(),b.end());//用已有的二维数组来初始化

int size_row = vec.size();  //获取行数
int size_col = vec[0].size();  //获取列数

vector二维数组 排序函数sort()的使用

默认排序:按每一个vector数组第一个元素进行由小到大排序

自定义排序函数  (目标:对 二维vector<vector> points中最后一个元素进行排序)

 static bool cmp(const vector<int>& a,const vector<int>& b){
    return a.back()<b.back();
 }
sort(points.begin(),points.end(),cmp);

Lambda 函数

sort( points.begin(),points.end(),
                    [](vector<int>a, vector<int>b){return a.back()<b.back();} );
//速度比方法1稍慢
// return a[0]<b[0] 实现二维数组中第一个关键字的排序

sort(people.begin(),people.end(),[](vector<int>&a,vector<int>&b){
                  return a[0]>b[0] || (a[0] == b[0] && a[1] < b[1]);} );
//对于二维数组vector 按第一个元素由大到小排序,如果遇到第一个元素相等的情况,
//按第二个元素由小到大排序

 resize()和reserve()函数的区别

见代码:

#include "iostream"
#include<vector>
using namespace  std;
void printresult(vector<int> &vec){
	for (int i = 0; i < vec.size(); i++)
		cout << vec[i];
	cout <<endl<< "size" << vec.size() << endl;
	cout << "capacity" << vec.capacity() << endl;
}
int main(){
	vector<int> vec(6, 1);
	printresult(vec);
	vec.resize(5, 3);
	printresult(vec);
	vec.resize(7, 2);
	printresult(vec);
	vec.resize(10);
	printresult(vec);
	vec.reserve(12);
	printresult(vec);
    vec.reserve(15);
	printresult(vec);	
	return 0;
}

输出结果如下 

111111
size6            //vector<int> vec(6,1)构建vector类型数据
capacity6
————————————
11111
size5           //执行resize(5,3)之后,vector的长度变成了5,容量大小没有变
capacity6
————————————
1111122
size7          //执行resize(7,2)之后,vector扩容,长度为7,容量变为9,这与vector内存的                    
capacity9      //分配机制有关,vector的动态内存分配是一段一段的分配的
————————————
1111122000
size10         //同理,执行完resize(10)后,默认扩容数据为0,长度为10,容量为13
capacity13
————————————
1111122000
size10         //执行reserve(12),因为原来vector容量大于12,所以容量不变
capacity13
————————————
1111122000
size10        //执行reserve(15),长度不变,容量变为15
capacity15

vector遍历元素的新写法: 

for(declaration : expression)
    statement

expression部分是一个序列,可以是用花括号括起来的初始值列表,数组,vector,string等类型的对象,这些类型的特点是拥有能返回迭代器的begin和end成员。

declaration定义一个变量,序列expression中的每个元素都要能转换成该变量的类型,采用auto类型说明符来确保类型相容。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。vector的遍历如下:

    vector< TheType > vec;
	for (auto num : vec)
	{
		cout<<num;
	}
    //相当于
    for(int i=0;;i<vec.size();i++) {
        cout<<vec[i];
    }

如果想在遍历时对vec内的元素进行修改,则需要把declaration定义为引用类型

 for (auto & num : vec)
	 {
		 cout<<num++;
	 }

vector之反向迭代器 

对反向迭代器的自加操作,相当于对该迭代器前移。

反向迭代器之间能够进行加或减的操作,但不能对反向迭代器和迭代器进行加减操作。

vector<int> vec = { 1,2,3,4,5 };
vector<int>::reverse_iterator it;
it = find(vec.rbegin(), vec.rend(), 4);
//直接写成auto it=find(vec.rbegin(), vec.rend(), 4)也可
cout << *it << endl;//输出4
cout << *(it+1) << endl;//输出3
cout << *(it-1) << endl;//输出5

vector与list的对比

  • vector是连续存储结构:vector是可以实现动态增长的对象数组,支持对数组高效率的访问和在数组尾端的删除和插入操作,在中间和头部删除和插入相对不易,需要挪动大量的数据。它与数组最大的区别就是vector不需程序员自己去考虑容量问题,库里面本身已经实现了容量的动态增长,而数组需要程序员手动写入扩容函数进形扩容。
  • list是非连续存储结构:list是一个双链表结构,支持对链表的双向遍历。每个节点包括三个信息:元素本身,指向前一个元素的节点(prev)和指向下一个元素的节点(next)。因此list可以高效率的对数据元素任意位置进行访问和插入删除等操作。由于涉及对额外指针的维护,所以开销比较大
  • vector的随机访问效率高,但在插入和删除时(不包括尾部)需要挪动数据,不易操作。
  • List的访问要遍历整个链表,它的随机访问效率低。但对数据的插入和删除操作等都比较方便,改变指针的指向即可。

vector与数组的区别:

1、内存中的位置

C++中数组为内置的数据类型,存放在栈中,其内存的分配和释放完全由系统自动完成;vector,存放在堆中,由STL库中程序负责内存的分配和释放,使用方便。

2、大小能否变化

数组的大小在初始化后就固定不变,而vector可以通过push_back或pop等操作进行动态扩容。

3、初始化

数组不能将数组的内容拷贝给其他数组作为初始值,也不能用数组为其他数组赋值;而向量可以。

4、执行效率

数组>vector向量。主要原因是vector的扩容过程要消耗大量的时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值