C++STL的学习——1.Vector的功能用法

理解vector首先先理解iterator——iterator是一个迭代器,类似于一个地址的作用,相当于指针的泛化。我们可以将其接近的理解为指针的作用,用于连续的访问一个容器中的逻辑意义上连续的元素。

背景:指针可以用来遍历存储空间连续的数据结构,但是对于存储空间非连续的,就需要寻找一个行为类似指针的类,来对非数组的数据结构进行遍历。
定义:迭代器是一种检查容器内元素并遍历元素的数据类型。
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。
迭代器(Iterator)是指针(pointer)的泛化,它允许程序员用相同的方式处理不同的数据结构(容器)。
(1)迭代器类似于C语言里面的指针类型,它提供了对对象的间接访问。
(2)指针是C语言中的知识点,迭代器是C++中的知识点。指针较灵活,迭代器功能较丰富。
(3)迭代器提供一个对容器对象或者string对象的访问方法,并定义了容器范围。

迭代器和指针的区别:
容器和string有迭代器类型同时拥有返回迭代器的成员。如:容器有成员begin和end,其中begin成员复制返回指向第一个元素的迭代器,而end成员返回指向容器尾元素的下一个位置的迭代器,也就是说end指示的是一个不存在的元素,所以end返回的是尾后迭代器。

  1. 关于vector中内存的释放和内存的分配方式问题

c++中vector的一个特点是: 内存空间只会增长,不会减小。即为了支持快速的随机访问,vector容器的元素以连续方式存放,每一个元素都挨着前一个元素存储。设想,如果每次vector添加一个新元素时,为了满足连续存放这个特性,都需要重新分配空间、拷贝元素、撤销旧空间,这样性能就会非常慢,所以,实际上分配时其容量要比当前所需容量更多,即vector预留了一些额外的存储区,这样就不必单独为每个新元素重新分配内存空间,减少开销。 另外,在vector中内存只增不减体现在 - 比如首先分配了10000个字节,然后erase掉后面9999个,留下一个有效元素,但是实际上内存占用仍然为10000个,所有内存空间是在vector析构的时候才能被系统回收。所以,即使使用clear,vector所占用的内存空间依然如故,无法保证内存的回收。

当然,对于数据量很小的vector,完全没有必要进行主动释放,就比如200 * 200的网格计算,就是没有必要的,但是如果是1000 * 1000,那么就是前者的25倍了,这时就需要进行主动内存释放了。

另外,既然要进行内存释放,我们不得不掌握size()和capacity()方法的区别,前者是实际的vector元素个数,后者是实际占用内存的个数,一般来说,capacity()是大于或等于size()的。

所以,我们可以使用swap()来帮助释放内存,具体方法如下:

#include <iostream>
#include <windows.h>
#include <vector>
using namespace std;
struct GrainRho
{
    int key;
    double rho;
};

int main() {
    static vector<struct GrainRho> rhovec;

    static vector<struct GrainRho>::iterator itrho;

    GrainRho grainRho;
    
    for (int i = 0; i < 100; i++) {
        grainRho = {i, 0.5 + double(i)};
        rhovec.push_back(grainRho);
    }

    rhovec.clear();
    cout << "rhovec.size(): " << rhovec.size() << endl;
    cout << "rhovec.capacity(): " << rhovec.capacity() << endl;

    vector<struct GrainRho>().swap(rhovec);

    grainRho = {1995, 6.28};
    rhovec.push_back(grainRho);
    cout << "rhovec.size(): " << rhovec.size() << endl;
    cout << "rhovec.capacity(): " << rhovec.capacity() << endl;

    system("pause");
}

如上所示,首先我们给这个rhovec存入了很多元素,然后调用clear()函数,但是实际上内存还是没有释放而是继续占用的,所以,我们使用 “vector().swap(rhovec)” 来释放内存,最后又存入一个grainRho,所以最终结果只有一个grainRho占用内存。

最终结果如下所示:

rhovec.size(): 0
rhovec.capacity(): 128
rhovec.size(): 1
rhovec.capacity(): 1
如上所示,我们就很好的解决了内存占用问题!

  1. 关于基本函数的使用与和algorithm中的一些函数搭配使用。
    (1):首先是关于构造函数的实现:
    vector():创建一个空vector
    vector(int nSize):创建一个vector,元素个数为nSize
    vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
    vector(const vector&):复制构造函数
    vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
    其中关于最后一条中的begin和end都是iterator型的一个迭代器。
    具体实现:
#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
int main()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(3);
    v.push_back(2);
    v.push_back(55);
    v.push_back(-1);
    v.push_back(0);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    vector<int> p(v.begin()+5,v.end());//区间复制
    vector<int> p1(v);//复制构造函数

    for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout<<endl;
    for(vector<int>::iterator it = p.begin(); it != p.end(); ++it)
    {
        cout << *it << " ";
    }
    } 

(2):是关于增加元素的一些函数:
void push_back(const T& x):向量尾部增加一个元素X
iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
其中关于insert的插入位置其实还是有区别的:
贴这一段代码:如果insert中的iterator是用

#include<vector> //导入vector
 
vector<int> v; //定义int 类型的 vector
 
v.push_back(3); //向vector数组尾部插入3 相当于v[0] = 3;
v.push_back(2); //尾部插入2  相当于v[1] = 2;
 
 
v.insert(v.begin(),111);//在第一个元素之前插入111  
 
v.insert(v.end(),222);//在最后一个元素之后插入222 
 
v.insert(v.end()-1,333);//在倒数第二个元素之后插入333
 
v.insert(v.begin()+1,444);//在第二个元素之前插入444

如果是iterator以begin为表示法的话,就会插入到所表示位置的前面
如果是以eng为表示法的话,就会插入到所表示位置的后面去

3.遍历的方法:
普通方法:与数组类似,写法也类似
可以直接v[i]来遍历位置
同时也可以采用iterator的方法来遍历
写法相对固定可以记住作为直接使用。

for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

其中vector所对应的函数begin()和end(),的返回值都是iterator。由于vector的地址是连续的,所以我们可以直接加减iterator来实现对于地址的变换。
4.vector的删除元素的方法
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素

v.erase(arr.begin());//删除用法 同insert 表示删除第一个元素
 
v.erase(arr.begin(),arr.begin()+5); //删除开头第1-5的元素

v.pop_back();//删除向量中最后一个元素

v.clear();//清空向量中所有元素

4.遍历函数
reference at(int pos):返回pos位置元素的引用
pos的是一个int类型的是顺序容器的下标,也可以简单理解为数组的下标,返回的是一个vector所申明的类型的一个引用。
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
front(),back()和begin(),end()可以成对的记忆,第一组返回的是第一个和最后一个元素的引用,而后一组返回的是第一个元素和最后一个元素后一位的iterator。
至于这个reverse的话…反向的迭代器用的比较少…
5.大小函数和其他函数
nt size() const:返回向量中元素的个数
int capacity() const:返回当前向量张红所能容纳的最大元素值
int max_size() const:返回最大可允许的vector元素数量值
void swap(vector&):交换两个同类型向量的数据
void assign(int n,const T& x):设置向量中第n个元素的值为x
void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素
5.和vector经常搭配使用的一些其他函数
sort()在头文件algorithm中,用来排序,默认排序是从小到大,如果想要从大到小排序,可以通过定义函数来实现
具体实现方法:
普通升序:

sort(v.begin(),v.end());

降序的话:

bool Comp(const int &a,const int &b)
{
    return a>b;
}
int main()
{
vector<int> v;
sort(v.begin(),v.end(),Comp);

}

特别的如果vector的类型是自定义的类型的话,直接使用sort需要重载运算符<
或者直接定义一个用于比较的函数也是可以的。

reverse函数也是在algorithm库中,可以用于实现对于vector的倒置,实现方法:
reverse(iterator first,iterator end);
reverse函数的输入参数是迭代器类型的,相当于传进去所需要转置容器的头尾的指针参数。

##总结


:vector中常用的成员函数
成员函数 作 用
vector() 无参构造函数,将容器初始化为空
vector(int n) 将容器初始化为有 n 个元素
vector(int n, const T & val) 假定元素的类型是 T,此构造函数将容器初始化为有 n 个元素,每 个元素的值都是 val
vector(iterator first, iterator last) first 和 last 可以是其他容器的迭代器。一般来说,本构造函数初始化的结果就是将 vector 容器的内容变成与其他容器上的区间 [first, last) —致
void clear() 删除所有元素
bool empty() 判断容器是否为空
void pop_back() 删除容器末尾的元素
void push_back( const T & val) 将 val 添加到容器末尾
int size() 返回容器中元素的个数
T & front() 返回容器中第一个元素的引用
T & back() 返回容器中最后一个元素的引用
iterator insert(iterator i, const T & val) 将 val 插入迭代器 i 指向的位置,返回 i
iterator insert( iterator i, iterator first, iterator last) 将其他容器上的区间 [first, last) 中的元素插入迭代器 i 指向的位置
iterator erase(iterator i) 删除迭代器 i 指向的元素,返回值是被删元素后面的元素的迭代器
iterator erase(iterator first, iterator last) 删除容器中的区间 [first, last)
void swap( vector & v) 将容器自身的内容和另一个同类型的容器 v 互换

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值