C++复习(一):STL库之vector容器

vector可以看做一个顺序容器,它支持随机访问迭代器。

1、构造和赋值

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

//以下int,string等可替换成其他类型,若类型为struct和class时可能还需考虑操作符重载
vector<int> vec1;    //创建一个空vector。不能加括号,会出问题。
vector<int> vec2(5);    //创建一个大小为5、值均为0的vector
vector<string> vec3(5);    //创建一个大小为5、值均为空字符串的vector
vector<string> vec4(5, "hello");    //创建一个大小为5、值均为"hello"的vector
vector<int> vec5 = { 7,3,5,2 };    //创建一个vector并赋值{7,3,5,2}
vector<int> vec6(vec5);    //创建一个和vec5值相同的vector
vector<int> vec7(vec5.begin(), vec5.begin() + 3);    //通过迭代器赋值{7,3,5}

//下标赋值
vec5[2] = 6;    //vec5值为{7,3,6,2}

2、vector和数组相互转化

#include<algorithm>

//数组转化为vector
int arr1[4] = { 1,2,3,4 };
vector<int> vec8(arr1, arr1 + 4);    //vec8值为{1,2,3,4}

//vector转化为数组,暴力赋值或用algorithm库函数copy,以下为使用copy的方法
int* arr2=new int[vec8.size()];
copy(vec8.begin(), vec8.end(), arr2);    //arr2值为{1,2,3,4}

3、大小、容量、如何改变

大小、容量

vec5.size()    //返回vec5中元素的个数,即vec5的大小,应为4。
vec5.capcity()    //返回vec5当前能够容纳的元素数量,即vec5的容量,应为4。STL中只有vector和string有这个属性。一般没什么用。
vec5.max_size()    //返回容器所能容纳的最大元素数目。这是系统或者库所实施的限制,但是容器不一定保证能达到该大小,有可能在还未达到该大小的时候,就已经无法继续分配任何的空间了。这个函数似乎没有什么卵用。

改变大小或容量

这部分参考:https://www.cnblogs.com/dengwuxie/p/7275101.html

//改变大小
void resize(size_type n, const T& c = T());
/*
其中n是要保留的元素个数,如果是要新增元素的话,c则是新增元素的默认初始值。
对于n值的大小,分三种情况:
(1)如果n大于容器当前的大小(即容器的size,这里和capacity无关),则在容器的末尾插入n-size()个初始值为c的元素;如果没有指定初始值,那就元素类型的默认构造函数来初始化。
(2)如果n小于容器当前的大小,则删除末尾的size()-n个元素,这样就导致容器的大小变了,size 变小了。但是这种类型的容器在删除一个元素的时候并不会释放元素本身的内存空间【这也是为了保留这块空间以避免将来要插入新元素的时候又要进行存储空间重分配】,所以容器的容量即capacity其实是没有改变的。
(3)n等于容器当前的大小,则什么也不做。
*/

//增加容量
void reserve(size_type n);
/*
对于n值的大小,分两种情况:
(1)如果n大于容器现有的容量(capacity),比如你容器原来是100的容量,我现在指定n=200,那么就需要在自由内存区为整个容器重新分配一块新的更大的连续空间【因为vector是顺序容器,所以存储空间是连续的,如果之前的存储空间不够了,必须这样做】,然后将容器内所有的有效元素从旧位置全部复制到新位置,这个过程是调用拷贝构造函数,然后释放旧位置的所有存储空间,并调整容器的元素位置指示器。所以reserve的时候如果n比原来的大,结果只是让容器的冗余容量(即没有分配元素的存储区)变大,容器的实际大小,即元素个数并没有改变。
(2)如果n小于容器原来的容量,那么这个函数什么作用都没有。相当于白调用了。
*/

/*
显然,reserve和resize的共同点就是:都不缩减容器本身的容量。即对内存空间并没有影响。那么要是当你觉得容器的容量太多的时候,应该如何缩减容量呢。这时候需要用到一个利用swap函数的技巧,参见本文第8条。
*/

4、插入和删除

//尾部插入
vector<int> vec9;    //值为{}
vec9.push_back(3);    //值为{3}
vec9.push_back(2);    //值为{3,2}

//指定位置插入
vec9.insert(vec9.begin(), 7);    //值为{7,3,2}
vec9.insert(vec9.begin()+2, 5);    //值为{7,3,5,2}

//尾部删除
vec9.pop_back();    //值为{7,3,5}

//指定位置删除
vec9.erase(vec9.begin()+1);    //值为{7,5}

//指定位置插入另一个vector
vec9.insert(vec9.end(), vec5.begin(), vec5.end());    //vec9尾部插入vec5,值为{7,5,7,3,6,2}

//清空
vec9.clear();    //值为{}

5、遍历

//下标遍历
for (int i = 0; i < vec5.size(); i++) {
	cout << vec5[i] << " ";
}
cout<<endl;

//迭代器遍历
vector<int>::iterator it = vec5.begin();
for(; it != vec5.end(); ++it){
	cout << (*it) << " ";
}
cout<<endl;

6、vector中的迭代器和引用

//迭代器
vec5.begin();    //返回头部迭代器,指向第一个元素
vec5.end();    //返回尾部迭代器,指向最后一个元素的后一个位置
vec5.rbegin();    //反向迭代器,指向最后一个元素
vec5.rend();    //反向迭代器,指向第一个元素的前一个位置

//引用,好像没什么卵用,赋值可以直接通过下标赋值
vec5.at(2);    //返回位置2元素的引用
vec5.front();    //返回首元素的引用
vec5.back();    //返回尾元素的引用

7、查找,排序和反转

//查找,排序和反转都要用到algorithm库
//用find函数查找。这种查找方式为顺序查找,在需要查找大量数据时最好还是用set或者hashmap比较快。
find(vec5.begin(), vec5.end(),3)    //查找vec5中3的位置,返回一个迭代器
//若找不到则返回vec5.end(),可用下行代码判断3是否在vec5中
if(find(vec5.begin(), vec5.end(),3)==vec5.end())    //若为true,则3不在vec5中
//若找到则返回vec5中第一个3的迭代器
vector<int>::iterator it = find(vec5.begin(), vec5.end(),3);
if(it!=vec5.end())
    cout<<*it<<endl;    //输出迭代器中的值

//用sort函数排序
sort(vec5.begin(), vec5.end())    //对vec5从小到大排序,值为{2,3,6,7}
sort(vec5.begin(), vec5.end(), less<int>())    //对vec5从小到大排序,值为{2,3,6,7}
sort(vec5.begin(), vec5.end(), greater<int>())    //对vec5从大到小排序,值为{7,6,3,2}

//反转
//用reverse函数排序
reverse(vec5.begin(), vec5.end())    //对vec5反转,值为{2,3,6,7}

//用vector的反向迭代器rbegin()和rend()反转
//TODO:以后补充,基本也不会用这个方法进行反转

8、其他常用函数

//判断是否为空
vec9.empty()    //返回vec9是否为空,应为true

//判断两个vector是否相等,直接用==、!=来判断
if(vec5==vec9)

//甚至可以用<、>来判断两个vector的大小,按字典序排序
//但不是严格弱序的,即vector无法作为std::map.find()的key值无法满足a1<a2,a2<a3-->a1<a3的场景。
//没怎么看懂什么意思。链接在这https://www.cnblogs.com/deityde1127/p/11937377.html
if(vec5<vec9)

//交换两个vector的数据
//会影响capacity属性,可以用来释放内存,可参考https://www.cnblogs.com/mazhenyu/p/8295316.html。
vec5.swap(vec9)    //vec5和vec9交换数据。

9、有趣的简单操作(不限于vector,仅用vector举例)

求vector<int> v中最大最小值

//max_element和min_element在algorithm库函数中
int max = *max_element(v.begin(),v.end()); 
int min = *min_element(v.begin(),v.end());

求vector<int> v所有元素的和

#include<numeric>
//accumulate的返回值类型为第三个参数的类型,每次累加会先把vector中元素转成第三个参数的类型再累加,所以当vector元素类型为double时,第三个参数应写成0.0,而不是0。若vector类型为stirng,则用此函数可实现所有元素的连接。
int sum = accumulate(v.begin(),v.end(), 0);    //第三个参数为累加的初值

对vector<int> arr排序并记录排序前的下标。

struct Node {
	int val, index;
	bool operator<(const Node& b){
		if (this->val < b.val)
			return true;
		return false;
	}
};

vector<int> arr={9,5,2,7};    //arr的定义
vector<Node> vec;
for (int i = 0; i < arr.size(); i++) {
	Node tmp;
	tmp.val = arr[i];
	tmp.index = i;
	vec.push_back(tmp);
}
sort(vec.begin(), vec.end());
for (int i = 0; i < vec.size(); i++) {
	int index = vec[i].index;    //至此,访问到排序后下标为i数据的原下标index。
}

统计vector<int> arr中各个元素出现的次数

#include<map>

vector<int> arr={2,2,3,1,3};    //arr的定义
map<int, int> m;
for (i = 0; i < arr.size(); i++){
    if (m.end() != m.find(arr[i]))    //查找m中是否有arr[i]
        m[arr[i]]++;    //有的话,计数+1
    else
        m.insert(pair<int, int>(arr[i], 1));    //没有的话,将arr[i]加入m,并计数为1。
}
for (auto it : m){    //用迭代器访问m中所有元素
    cout << it.first << " " << it.second << endl;
}

10、内存释放

主要参考https://blog.csdn.net/hellokandy/article/details/78500067

vector其中一个特点:内存空间只会增长,不会减小。STL实现者在对vector进行内存分配时,其实际分配的容量要比当前所需的空间多一些。就是说,vector容器预留了一些额外的存储区,用于存放新添加的元素,这样就不必为每个新元素重新分配整个容器的内存空间。

即使使用clear(),vector所占用的内存空间依然如故,无法保证内存的回收。

如果需要空间动态缩小,可以考虑使用deque。如果vector,可以用swap()来帮助你释放内存。

vector<int>().swap(arr);    //将arr与空的vector交换数据及内存。
//这个之前生成的匿名的vector在这行代码结束后内存就应该被释放了。

11、二维数组简单操作

//构造二维数组{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
//方法一
vector<vector<int>> vec2d = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
//方法二
vector<vector<int>> vec2d;
for(int i = 0; i < 3; i++){
    vector<int> vec1d;
    vec1d.push_back(3 * i + 1);
    vec1d.push_back(3 * i + 2);
    vec1d.push_back(3 * i + 3);
    vec2d.push_back(vec1d);
}

//遍历上述数组
for(int i = 0; i < 3; i++){
    for(int j = 0; j < 3; j++){
        cout<< vec2d[i][j] << " ";
    }
    cout<<endl;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章