C++STL(二)——vector容器

STL——vector容器

  • vector对象的概念
  • vector基本操作
  • vector对象的初始化、赋值
  • vector查找、替换(已在上一片 string类 博客总结过了,不再总结)
  • vector添加、弹出元素(头部、尾部)
  • vector容器的遍历(通过数组的方式、通过迭代器)
  • vector删除、插入操作(指定元素删除/插入、区间删除/插入、一次插入多个相同的元素)
  • 迭代器介绍(输入迭代器、输出迭代器、正向迭代器、双向迭代器)
  • vector举例应用

在这片文章中我参考了许多人的博客,甚至有一些部分是直接copy的,最终做了一个详细的vector用法总结
vector用法参考


vectot容器的简介

  1. vector 是一个将元素置于动态数组中加以管理的容器。
  2. vector 支持随机存取元素(支持索引值直接存取,用[]操作符或 at()方法,来下标来访问)
  3. vecotr 在尾部添加和移除元素非常快,但是在中间和头部添加和移除却很费事。
  4. vector存储数据时,会分配一个存储空间,如果继续存储,该分配的空间已满,就会分配一块更大的内存,把原来的数据复制过来,继续存储,这些性能也会一定程度上会有损耗

vector基本操作

(1). 容量
向量大小: vec.size();
向量最大容量: vec.max_size();
更改向量大小: vec.resize();
向量真实大小: vec.capacity();
向量判空: vec.empty();
减少向量大小到满足元素所占存储空间的大小: vec.shrink_to_fit(); //shrink_to_fit
(2). 修改

多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值
末尾添加元素: vec.push_back();
末尾删除元素: vec.pop_back();
任意位置插入元素: vec.insert();
任意位置删除元素: vec.erase();
交换两个向量的元素: vec.swap();
清空向量元素: vec.clear();

vector类的对象的构造

    //vector 采用模版类来实现 vector<T> vec;
    vector<int> v1 //从模版实例化出存放int类型元素的 v1 容器
    vector<double> v2 //从模版实例化出存放double类型元素的 v1 容器
    
    //vector 尖括号内可以实例化出 指针类(包括自定义的数据类型的指针)型和自定义的 数据类型的 容器
    vector<int *> v3// 定义存放 int型变量的地址的容器
    class A {};  // 自几定义数据类型 A
    vector<A> v4;  //定义存放A类型数据的容器
    vector<A *> v5;//定义存放 A类型变量的地址的容器
    
    //⚠️注意:由于容器元素的初始化/赋值是按值传递复制的进行的,所以此时 A类 必须提供拷贝构造函数,以保证 A类的对象之间拷贝正常

初始化

    v1.push_back(1); //向v1中添加一个 1
    v1.push_back(2); //向v2中添加一个 2
    v1.push_back(3); //向v3中添加一个 3
    int ar[3] = {1,3,5};
    vector<int> vec={1,3,5}; //用列表初始化
    vector<int>v2 = v1;  //用vector的拷贝构造函数
    vector<int>v3(v1);
    vector<int>v4(v1.begin(),v1.end());//区间初始化
    vector<int>v5(ar,ar+3); //用数组区间初始化
    vector<int>v6(5,0); //用五个0进行初始化


赋值


    //vector赋值
        //第一类赋值法
    v4.assign(10,0);  //给v4赋上10个零
    v3.assign(ar,ar+2);
    v2.assign(v1.begin(),v1.end());
        //第二类赋值法(⚠️运用下标法 [] 必须先给vector容器申请空间,以供下标访问否则出错,如果此时用push_back()将把元素插入到先前申请的空间之后)
    vector<int> v5(10);  //提前申请存储10元素的空间,此时10个元素的值均为0
    for(int i=0;i<10;i++)
        v5[i]=i+1;   
        //第三类赋值法,通过迭代器的方式去赋值
    for(vector<int>::iterator it =v5.begin();it<v5.end();it++)
        *it = 0;


添加、弹出元素(头部、尾部)

    vector<int> v1;
    //vector 的增添、弹出、删除元素
        //添加
    v1.push_back(1); //向v1中添加一个 1
    v1.push_back(2); //向v2中添加一个 2
    v1.push_back(3); //向v3中添加一个 3
    print(v1);
        //弹出
    v1.pop_back();   //弹出尾部的一个元素
    print(v1);
        //尾元素的访问与修改
    cout<<v1.back(); //通过back()函数去访问v1的尾元素
    cout<<v1.front();//通过front()函数去访问v1的首元素
    v1.back() = 10;  //由于back()函数返回值为引用,所以可以通过back(),来改变尾元素的值
    v1.front() = 20; // 与⬆️同理

遍历

    vector<int> v1={1,3,5};
    //vector的遍历
        //1.用for循环
    for(int i=0;i<3;i++)
        cout<<v1[i];
        //2.用基于范围的for循环
    for(int &i:v1)
    {
        cout<<i;
        i = 10;  //有 i 被声明的时候是以引用的方式,所以可以通过 i 来改变v1中元素的值
    }
        //3.用迭代器
    for(vector<int>::iterator it = v1.begin();it<v1.end();it++)
    {
        cout<<*it;
        * it = 10; //通过it指针去改变v1的值
    }

删除,插入操作

    int ar[3] = { 1, 3, 5};
    vector<int> v1={1,2,3};
    vector<int> vec={1,3,5};
    //删除操作
        注意⚠️:用erase()删除完后元素后,它的返回值是一个指向下一个元素(挨着最后一个被删除的元素的元素)的迭代器
    vec.erase(vec.begin(),vec.end());  //删除[vec.begin(),vec.end())区间的元素
    vec.erase(vec.begin());  //删除vec.begin()这个位置的元素
    //插入
    vec.insert(vec.begin(), 0); //在vec.begin() 位置之前 插入元素
    vec.insert(vec.end(), v1.begin(),v1.end());  //在vec.end() 之前插入在[v1.begin(),v1.end())区间内的元素
    vec.insert(vec.begin(),10,0);  //在vec.begin()之前插入10个0元素
    vec.insert(vec.begin(),ar,ar+3);![ebd4c8678baf58da184575ee8ca5b528.png](evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p334)
    

迭代器


迭代器的介绍:

  • 迭代器类似于指针类型,它只想一个特定的位置,它也提供了对对象的间接访问
  • 指针是C语言中就有的东西,而迭代器是C++中才有的
  • 使用迭代器:和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员,比如,容器都有的成员begin和end,其中begin成员负责返回指向容器第一个元素的迭代器,如:auto b = v.begin();end成员则负责返回指向容器的尾元素的下一个位置的迭代器,也就是说指向的是容器的一个本不存在的尾部。如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。
  • 迭代器提供一个对容器对象或者string对象访问的方法,并且定义了容器范围

输入、输出迭代器

  • 输入迭代器:又叫“只读迭代器“,它只能从容器中读取元素,一次读出一个迭代器向前移,同一个输入迭代器不能遍历两次容器
  • 输出迭代器:又叫“只写迭代器”,它只能从容器总写入元素,一次写入一个迭代器向前移,同一个输出迭代器不能遍历两次容器

正向迭代器、双向迭代器

  • 正向迭代器:所谓正向迭代器指的是只能正向走,而不能反向走,一个在一个指着(停留在)一个元素多次,而且一次移动多个位置,可以通过 ++ += (不可以通过 – -= 运算符)
  • 双向迭代器:所谓正向迭代器指的是可以可以正反两个方向走,支持随机访问容器,一次移动多个位置,可以通过 ++ – += -= 运算符来完成

迭代器理解

  • 迭代器的类型:
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xP89GMwr-1574571844427)(evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p332)]
  • 1vector::iterator it;//it可以读写vector的元素
  • 2string::iterator it2;//it2可以读写string对象中的字符
  • 3vector::const_iterator it3;//it3只能读元素,不能写元素
  • 4string::const_iterator it4;//it4只能读字符,不能写字符

  • 迭代器的区别
    const_iterator和常量指针差不多,能读取但不能修改它所指的元素值,而iterator可读可写。如果容器或string对象是一个常量,只能使用const_iterator,如果不是常量,那么既能使用iterator又能使用const_iterator。
    如果容器或对象只需读操作而无需写操作的话最好使用常量类型(const_iterator),为了便于获取常量迭代器,C++11新引入了两个新函数,分别是cbegin和cend,类似于begin和end,不同之乎在于只能返回const_iterator.
    注意:但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素

  • 迭代器运算

1iter + n 迭代器加上一个数值仍得一个迭代器,所指位置向前移动n个元素
2iter - n 迭代器减去一个数值仍得一个迭代器,所指位置向后移动n个元素
3iter += n 等价于iter + n
4iter -= n 等价于iter - n
5iter1 - iter2 两个迭代器相减的结果是他们之间距离,其类型是名为difference_type的带符号整数
6 >、>=、<、<= 位置离begin近的元素较小


迭代器的应用

    //迭代器的应用
        //1. 迭代器的声明
    vector<int> v1{1,3,5};
    vector<int>::iterator it1 = v1.begin();  //声明一个双向迭代器,(begin())并赋值为v1元素的首地址
    vector<int>::const_iterator it2 = v1.cbegin(); //只能读容器的值,而不能改变容器的值,cbegin(),是一个指向容器首元素的地址常量,cend()同理如此
    vector<int>::reverse_iterator it3 = v1.rbegin();  //声明一个反向迭代器,(rbegin()指向最后一个元素,rend()指向容器第一个元素位置之前)
    for( ;it2 < v1.cend();it2++)
    {
        cout<<*it2;
        //*it2 = 10; 这一条错误 因为 it2 是常量迭代器
    }
    for( ;it3 < v1.rend();it3++)
    {
        cout<<*it3<<endl;  //输出结果:3 2 1
        *it3 = 10;        //通过指针去赋值
        cout<<*it3<<endl;
    }
  • 对rbegin()和rend()的理解
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h1dfhtf2-1574571844431)(evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p334)]

vector与迭代器 举例应用

//关于STL中vector容器的学习,编译运行后边看代码,边看执行结果效果更佳,不过看别人的代码一百遍,不如自己动手写一遍 
#include <vector>//头文件
#include <iostream>
#include <algorithm>
using namespace std;

void print(vector <int> v);
bool mycmpare(const int &a, const int &b){
    return a>b;
}
int main ()
{
    //创建vector对象三种常用的方式,此处存储元素类型是int,还可以是double、char、long long等基本数据类型,甚至是string基本字符序列容器 
    vector <int> v1;//不指定容器的元素个数的定义一个用来存储整型的向量容器
    cout<<"v1:"<<endl; 
    print(v1);
    /*运行结果
        v1:
    大小为:0
    */ 
    
    vector <int> v2(5);//指定容器的元素个数的定义一个大小为10的用来存储整型的向量容器,默认初始化为0
    cout<<"v2:"<<endl;
    print(v2);
    /*运行结果
    v2:
    大小为:5
    0 0 0 0 0
    */
    
    vector <int> v3(5,1);//也可指定初始值,此处指定为1
    cout<<"v3:"<<endl;
    print(v3); 
    /*运行结果
    v3:
    大小为:5
    1 1 1 1 1
    */
    
    //另外事先指定不指定大小都无所谓,指定了大小也可以随时使用push_back()对vector容器进行尾部扩张
    v1.push_back(1);//向空的vector容器尾部扩张,追加元素为1
    cout<<"v1:"<<endl; 
    print(v1); 
    v3.push_back(2);//向已有元素的vector容器尾部扩张,追加元素为2
    cout<<"v3:"<<endl;
    print(v3);
    /*运行结果
    v1:
    大小为:1
    1
    
    v3:
    大小为:6
    1 1 1 1 1 2
    */
    
    //插入元素使用insert()方法,要求插入的位置是迭代器的位置,而不是元素的下标
    v3.insert(v3.begin(),3);//在最前面插入3
    cout<<"v3:"<<endl;
    print(v3);
    
    v3.insert(v3.end(),3);//在末尾追加3,此处等同于push_back()
    cout<<"v3:"<<endl;
    print(v3);
    /*运行结果
    v3:
    大小为:7
    3 1 1 1 1 1 2
    
    v3:
    大小为:8
    3 1 1 1 1 1 2 3
    */
     
    int i;
    for(i=0;i < v3.size();i++){//只可赋值到已扩张位置 
        v3[i]=i;
    }
    //要删除一个元素或者一个区间中的所有元素时使用erase()方法
    v3.erase(v3.begin()+2);//删除第2个元素,从0开始计数
    cout<<"v3:"<<endl;
    print(v3); 
    /*运行结果
    v3:
    大小为:7
    0 1 3 4 5 6 7
    */
    v3.erase(v3.begin()+1,v3.begin()+3);//删除第1个到第3个元素区间的所有元素
    cout<<"v3:"<<endl;
    print(v3);
    /*运行结果
    v3:
    大小为:5
    0 4 5 6 7
    */
    //由结果可知,erase()方法同insert()方法一样,操作的位置都只是迭代器的位置,而不是元素的下标
    
    //要想清空vector(),使用clear()方法一次性删除vector中的所有元素
    cout<<"v2:"<<endl;
    print(v2);
    /*运行结果
    v2:
    大小为:5
    0 0 0 0 0
    */
    v2.clear();
    if(v2.empty()) cout<<"v2经过使用clear()方法后为空\n"; 
    print(v2);
    /*运行结果
    v2经过使用clear()方法后为空
    大小为:0
    */
    
    //要想将向量中某段迭代器区间元素反向排列,则使用reverse()反向排列算法,需要添加algorithm头文件 
    cout<<"v3反向排列前:"<<endl;
    print(v3);
    reverse(v3.begin(),v3.end());//全部反向排列 
    cout<<"v3反向排列后:"<<endl;
    print(v3); 
    /*运行结果
    v3反向排列前:
    大小为:5
    0 4 5 6 7
    
    v3反向排列后:
    大小为:5
    7 6 5 4 0
    */
    
    //要想将向量中某段迭代器区间元素进行排序,则使用sort()算法
    cout<<"v3升序排列前:"<<endl;
    print(v3); 
    sort(v3.begin(),v3.end());//默认升序排列
    cout<<"v3升序排列后:"<<endl;
    print(v3);
    /*运行结果
    v3升序排列前:
    大小为:5
    7 6 5 4 0
    
    v3升序排列后:
    大小为:5
    0 4 5 6 7
    */
    
    //自定义排序比较函数,此处降序
    cout<<"v3降序排列前:"<<endl;
    print(v3);
    sort(v3.begin(),v3.end(),mycmpare); 
    cout<<"v3降序排列后:"<<endl;
    print(v3);
    /*运行结果
    v3降序排列前:
    大小为:5
    0 4 5 6 7
    
    v3降序排列后:
    大小为:5
    7 6 5 4 0
    */
} 

void print(vector <int> v) 
{
    //cout<<"下标方式访问:"<<endl;
    cout<<"大小为:"<<v.size()<<endl; 
    int i;
    for(i=0;i< v.size();i++){
        cout<<v[i]<<' ';
    }
    cout<<endl<<endl;
    
    /*cout<<"用迭代器访问:"<<endl;
    //定义迭代器变量it,类型与容器元素类型保持一致 
    vector<int>::iterator it; 
    for(it=v.begin(); it != v.end(); it++){
        cout<<*it<<' ';
    }
    cout<<endl<<endl;*/
}
发布了73 篇原创文章 · 获赞 100 · 访问量 2719

猜你喜欢

转载自blog.csdn.net/qq_34261446/article/details/103223474
今日推荐