5.1 STL vector向量

96 阅读6分钟

STL-vector向量

[TOC]

vector数组是一个能 存放任意数据类型(类,结构,普通变量类型等)的动态数组

在数据结构中就相当于顺序储存的线性表,寻找元素非常快,但是插入元素的时间却很大。

与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效

和普通数组一样可以通过下标索引来进行访问

list是一个双向链表,在同一个为止插入大量的数据时速度很快,但是查找的速度就会慢很多

1.头文件

#include<vector>
using namespace std;

2.构造函数

vector<int> vec;       		// 空的vector,只是一个列表的头,里面没有元素
vector<string> vec;
vector<int> vec1 = {1,3,4,5,6};

vector<int> vec1(4, 100);   // 初始化一个具有4个元素的vector,每个元素的值都是100
vector<int> vec2 (vec.begin(), vec.end()); // 通过其他vector的迭代器的方式,进行拷贝复制初始化
vector<int> vec3 (vec);  	// 直接对其他vector的拷贝复制

//二维初始化
vector<vector<int>> vars(size, vector<int>(size, 0)); // (size,size)的矩阵,元素全部是0

//用vector构建二维数组
vector<vector<int>> matrix;
vector<int>a;
a.push_back(1);
a.push_back(3);
a.push_back(1);
matrix.push_back(a);
//或者用下面的方法
int i,j;
vector<vector<int>> array(5);
for (i = 0; i < array.size(); i++)
    array[i].resize(3);//这里一定要使用resize其相当于每行的元素数并已经初始化过了

3.索引存取元素

索引其元素和索引一般的数组元素相似,使用下标或者 at()

operator[index];//类似数组中的[],返回索引index所指向的数据
at(int index);//用at函数来返回索引index所指向的数据
front();//返回容器中的第一个数据
back();//返回容器中最后一个元素
vector<int> vec1 = {1,3,4,5,6};
vec1[1]; 		 		 
// 直接索引,针对多维度的也是一样
输出是3
vec1[1] = 0;			 
//直接可以修改
输出是0
vec1.at(1) = 1;  		 
// 也可以通过函数索引
输出是1
vec1.back(); 			 
// 获取vector的最后一个元素
输出是6


# 输出最小值及索引
*max_element(vec.begin(),vec.end());
*min_element(vec.begin(),vec.end());

# 输出最大最小值索引
max_element(vec.begin(),vec.end())-vec.begin();
min_element(vec.begin(),vec.end())-vec.begin();


4.遍历元素

方法一、索引遍历
vector<int> vars;
int vsize = vars.size();
for (int i = 0; i < vsize; ++i){
	cout << vars[i];
}
方法二、迭代器变量
vector<int> vars = {1,3,5,6,7,8};
for (vector<int>::iterator it = vars.begin(); it != vars.end(); it++){
    cout<< *it  <<""; // 遍历每一个元素
}
指定区间中的遍历;
vector<int> vars = {1,3,5,6,7,8};
for (vector<int>::iterator it = vars.begin()+1; it != vars.end()-1; ++it){
	*it = 10; // 遍历每一个元素
}
方法三、使用auto关键字
for (auto it = vars.begin(); it != vars.end(); ++it){
        cout << " "<< *it; // 遍历每一个元素
    }
//多维度
for (int i = 0; i < vec.size(); i++)
{
    for (int j = 0; j < vec[0].size(); j++)
        cout << vec[i][j] << " ";
    cout << endl;
}


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

int main(int argc, char const *argv[])
{
    vector<int> vars = {1, 3, 5, 6, 7, 8};

    vector<vector<int>> vec = {{1, 2, 3}, {4, 5, 6}};

    for (auto iter = vec.begin(); iter != vec.end(); iter++)
    {
        vector<int> vec_tmp = *iter;
        for (auto it = vec_tmp.begin(); it != vec_tmp.end(); it++)
        {
            cout << *it << " ";
        }

        cout << endl;
    }
    return 0;
}

4.capacity 相关

1、vec.size();    
//元素个数

2、vec.max_size();  
//vector 可允许的最大容量

3、vec.resize();  
// 改变容器可以容纳元素的个数,

4、vec.capacoty();    
//理论容量

5、vec.empty(); 
//返回是否为空,true, false;

6、vec.reserve();
// 使得capacity至少能容纳n个元素。

7、vec.shrink_to_fit();
//减小capacity,使其与容器大小相同

5.插入元素

vec.push_back(同类型量);作用是在vector的末尾插入新元素

insert()第一个参数为迭代器,作用为在迭代器前面插入新元素

insert()第一个参数为迭代器,作用为在迭代器前面插入新元素

尾插法

vector<int> vars ;
vars.push_back(10);

insert插入法

vector<int> vars = {1,2,3,4,5};
vars.insert(vars.begin(), 100);
// 插入单个元素,在vars的第0元素位置插入100,位置用迭代器表示
vars.insert(vars.begin(), 2, 100);
// 插入多个相同的元素,此处插入2个100

vector<int> cop = {6,7,8};
vars.insert(vars.end(), cop.begin(), cop.end()); 
// 也可以进行vector之间的拼接

6.删除元素

pop_back()删除最后一个元素。

erase() 删除指定位置元素.(其中的参数要是指针变量,比如begain(),end(),以及迭代器值) 例如vec.erase(vec.begin()+2);删除第3个元素

clear() 清除所有元素。

empty() )判断该数组是否为空

vector<int> vars = {1,2,3,4,5,6};
vars.pop_back(); 
// 弹出最后一个元素,注意只是弹出,不返回其值,用vector.back()返回其值
vars.clear(); // 清空vector
auto iter = vars.erase(vars.begin()+1); 
// 删除单个元素,指定迭代器,删除后vector的大小减1,但是容量不变。
// 其返回一个迭代器,指向被删除元素后的第一个元素。

删除从一个位置到另一个位置
auto iter = vars.erase(vars.begin(), vars.begin()+2); // 删除一个范围内的值,指定开头,结尾的迭代器即可。

7.排序和翻转

#include<algorithm>
//采用的是从小到大的排序 
sort(vec.begin(),vec.end());

// 将元素翻转,即逆序排列
reverse(vec.begin(),vec.end());

8.底层原理

底层原理:动态数组

动态增长的数组,里面有一个指针指向一片连续的内存空间,当空间装不下要容纳的数据的时候会自动申请一片更大的空间(空间配置器)将原来的数据拷贝到新的空间,然后就会释放旧的空间。当释放或者删除(vec.clear())的数据时候并不会释放只是清空了里面的数据。

vector中有三个迭代器first,last,end, 分别指向了数组的开头, 数组的结尾+1以及数组的最大容量结尾,迭代器这里可以理解为是指针

int first,last,end;		
unsigned int size(){		
    //通过首尾 很容易得出size
	return last-first;
}
bool empty(){	
    //可以直接判断是否为空
	return last==first;
}
unsigned int capacity(){	
    //得到当前数组的容量
	return end-begin;
}

vector 容器扩容:

  • 完全弃用现有的内存空间,重新申请更大的内存空间;
  • 将旧内存空间中的数据,按原有顺序移动到新的内存空间中;
  • 最后将旧的内存空间释放。

扩容的倍数关系:在VS中, 该倍数为1.5 而在GCC中, 该倍数为2

reserve是直接扩充到已经确定的大小,可以减少多次开辟、释放空间的问题

resize()可以改变有效空间的大小,也有改变默认值的功能。capacity的大小也会随着改变。resize()可以有多个参数。

9.特殊记忆

互换容器

v1.swap(v2);//将v2的元素与v1元素互换
# 针对二维vector的处理
/ 第一维度从小到大, (第一维度相同时,按第二维度从大到下)

sort(envelopes.begin(),envelopes.end(),[](const auto&a,const auto&b){
	if(a[0]!=b[0]){
		return a[0]<b[0];
	}else{return a[1]>b[1];}
});

函数总结

函数成员函数功能
成员函数operator[ ]重载了 [ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素。
成员函数assign()用新元素替换原有内容。
容量size()返回实际元素个数。
容量max_size()返回元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。
容量empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
容量capacity()返回当前容量。
元素访问at()使用经过边界检查的索引访问元素。
元素访问front()返回第一个元素的引用。
元素访问back()返回最后一个元素的引用。
元素访问data()返回指向容器中第一个元素的指针。
修改器resize()改变实际元素的个数。
修改器reserve()增加容器的容量。
修改器push_back()在序列的尾部添加一个元素。
修改器pop_back()移出序列尾部的元素。
修改器insert()在指定的位置插入一个或多个元素。
修改器erase()移出一个元素或一段元素。
修改器clear()移出所有的元素,容器大小变为 0。
修改器swap()交换两个容器的所有元素。
迭代器begin()返回指向容器中第一个元素的迭代器。
迭代器end()返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。
迭代器rbegin()返回指向最后一个元素的迭代器。
迭代器rend()返回指向第一个元素所在位置前一个位置的迭代器。
迭代器cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
迭代器cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
迭代器crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
迭代器crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
emplace()在指定的位置直接生成一个元素。
emplace_back()在序列尾部生成一个元素。

参考资料

C++STL【容器】详解

www.w3schools.cn/cpp_standar…

www.apiref.com/cpp-zh/cpp/…

c.biancheng.net/view/6749.h…

www.cnblogs.com/LyShark/p/1…