您的位置:首页 > 编程语言 > C语言/C++

C++基础-vector容器

2017-09-30 12:37 281 查看

序言

在C语言编程中经常遇到这种情况:没有指定输入数据长度,只能定义很大的数组来存储数据,而且还不方便动态扩充数组大小。

C++中vector容器的存储机制就比较灵活地解决了这个问题,本文就来学习一下vector容器的常见用法。

1. 容器及vector容器

容器

容器是容纳某种数据结构的场所。

如常见数据结构:数组 + 链表 + 队列 + 树 + 栈 + 哈希表 + 集合set + 映射map等

容器分类

[1] 序列式容器。类似C里面所说的顺序存储结构

C++序列式容器包括:array(build-in) + list + stack + queue + deque + priority-queue

[2] 关联式容器。类似C里面所说的非顺序存储结构

C++关联式容器八廓:set + map + multiset + multimap + RB-tree

vector容器

STL提供的一种序列式容器,元素线性排列但未必有序

2. vector容器内存分配

vector容器与数组的区别

[1] 灵活性

数组(静态 + 动态)每次只能分配一定大小的空间,不方便动态扩充

vector容器是动态空间,原空间不够用会自行扩充

[2] 效率

数组是面向用户的,即“分配新空间 + 复制元素 + 释放旧空间”的操作需要用户自己完成

vector也要经过“分配新空间 + 复制元素 + 释放旧空间”的操作,用户不需要亲自处理空间运用问题,更加安全高效

vector容器内存分配

分配策略:以最小的代价连续存储元素。

分配原则:按照《STL源码剖析》中提供的vector源码,vector的内存配置原则为

如果vector原大小为0,则配置1,也即一个元素的大小。

如果原大小不为0,则配置原大小的两倍

(1)为了vector容器实现快速的内存分配,其实际分配的容量要比所需的空间多一些,这样不必每次都为新元素进行一次内存分配

(2)当元素超过容器capacity,此时再加入元素时vector的内存管理机制便会扩充容量至两倍,以此扩充至足够容量。

(3)容量扩张必须经历“重新配置、元素移动、释放原空间”这个浩大的工程

3. vector容器基本操作

[1] 头文件及初始化

//头文件:#include<vector>

//声明及初始化:
vector<int> a;          /* 声明一个int类型变量 */
vector<int> a(10);      /* 声明一个初始大小为10的变量 */
vector<int> a(10,1);    /* 声明一个大小为10,初值为1的向量 */

vector<int> b(a);                           /* 声明并用变量a初始化变量b */
vector<int> b(a.begin(), a.begin() + 3);    /* 将向量a的0,1,2三个元素作为向量b的初始值 */

int arr[] = {1, 2, 3, 4, 5, 6};
vector<int> a(n, n + 5);        /* 将数组arr的前5个元素作为向量ad哦初始值 */
vector<int> a(&n[2], &n[4]);    /* 将n[2]到n[4]的元素作为a的初值 */

vector<vector<int>> a(10, vector<int>(5));  /* 创建一个int型二维数组,相当于a[10][5] */


[2] 容量操作

vector<int> a;

a.size();               //向量大小
a.resize();             //更改向量大小
a.capacity();           //向量容量
a.empty();              //向量判断是否为空: 为空返回ture,否则返回false; 函数原型bool empty() const;
a.shrink_to_fix();      //减小向量大小到满足所占存储空间大小: 该语句跟在确定vec.size()之后,与内联函数一样,只是提出修改内存请求,是否实现编译器说了算


[3] 元素访问

vector<int> a;

a.front();      //返回第一个元素
a.back();       //返回最后一个元素,不检查这个数据是否存在

a[1];           //下标访问,并不会检查是否越界
a.at(1);        //at方法访问。at会检查是否越界,是则抛出out of range异常


[4] 元素修改

vector<int> a;

a.assign(5, 10);        //往a里放5个10
a.push_back(element);   //在尾部加入一个数据
a.insert(a.begin(), 1); //在a.begin()之前加入1,函数原型: a.insert(pos,elem); 在pos位置插入一个elem的拷贝,返回插入的值的迭代器
a.insert(v.begin(),2,20);   //a.insert(pos,n,elem)在pos位置插入n个elem的数据,无返回值
v.insert(v.begin(),v1.begin(),v1.begin()+2);
//a.insert(pos,beg,end)在pos位置插入v1在[beg,end)区间的数据,无返回值

a.pop_back();           //删除最后一个数据
a.erase(a.begin());     //将a/begin()的元素删除:a.erase(pos)删除pos位置的元素,返回下一个元素的位置
a.erase(a.begin() + 1, a.end());    //将第二个元素之后的元素均均删除。 a.erase(begin,end),删除[begin, end)区间内的数据,返回下一个数据的位置
a.clear();              //移除容器内所有数据


[5] 迭代器

vector<int> a;
a.begin();          //开始指针
a.end();            //末尾指针:指向最后一个元素的下一个位置

a.cbegin();         //指向常量的开始指针。意思就是不能通过这个指针来修改所指的内容,但还是可以通过其他方式修改的,而且指针也是可以移动的。
a.cend();           //指向常量的末尾指针。不能通过指针修改所指内容


[6] 遍历元素

vector<int> a;

//方式1:像数组一样以下标访问
for(int i = 0; i < a.size(); i++){
cout << a[i];
}

//方式2:以迭代器访问
vector<int>::iterator it;
for (it = a.begin(); it != a.end(); it++)
{
cout<<*it<<endl;
}


[7] 元素翻转

#include <algorithm>
...
reverse(a.begin(), a.end());


[7] 排序

#include <algorithm>
...
sort(a.begin(), a.end());               //默认按升序排序,即从小到大。

/* 如果想按降序排序 */
//方式1:可先sort()升序排序,再调用reverse()进行翻转
//方式2:采用与C语言中qsort()类似的方式
bool compare(const int &a, const int &b)
{
return a > b;   //'>'是降序
}
sort(a.begin(),a.end(),compare);

//qsort()使用区别:compare返回值必须为int,参数必须是const void *,'>'表示升序,'<'表示降序,与sort()中相反
int compare(const void *value1, const void *value2)
{
return *(int *)value1 - *(int *)value2 > 0 ? 1 : -1;    //这样是升序排序
return *(int *)value1 - *(int *)value2 > 0 ? -1 : 1;    //这样是降序排序
}

qsort(arr, num, sizeof(arr[0]), compare);


Acknowledgements:

http://www.cnblogs.com/QG-whz/p/4558147.html

http://www.cnblogs.com/zhonghuasong/p/5975979.html

http://www.cnblogs.com/YJthua-china/p/6550960.html

http://www.cnblogs.com/scandy-yuan/archive/2013/01/07/2849735.html(推荐)

2017.09.30
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: