zoukankan      html  css  js  c++  java
  • C++vector容器


    我们在声明数组的时候,采用的是datatype array[len]的形式,数组在分配之后,不能调整大小,删除和插入数据时操作十分的繁琐,虽然可以采用链表,但是链表的操作更麻烦,我们希望有更简单的方法。

    与string类一样, 向量vector 同属于STL(Standard Template Library,标准模板库)中的定义的类, vector是一个封装了动态数组的顺序容器(Sequence Container),它能够存放各种类型的数据和对象。

    可以简单的认为vector容器是一个能够存放任意类型的动态数组,与数组相比,vector容器的优点在于它能够根据需要自动调整的大小,随时放入更多的元素。此外, vector也提供了成员函数对自身进行操作。

    一、容器的定义

    首先,如果要在程序中使用vector容器,必须包含头文件 <vector>。如下:

    #include <vector>
    

    vector类是一个模板类,位于std命名空间内,为方便使用还需要增加:

    using namespace std;
    

    声明一个容器很简单:

    vector<int> vi;              // 定义用于存放整数的容器
    vector<double> vd;         // 定义用于存放浮点数的容器
    vector<string> vs;           // 定义用于存放string字符串的容器
    vector<struct st_girl> vgirl;  // 定义用于存放超女结构体的容器
    vector<CGirl> vGirl;         // 定义用于存放超女类的容器
    

    vector容器可以存放C语言的基本数据类型,可以存放结构体,还可以存放类,这正是我们想要的简单的方法,链表?我已经有二十年没有用它了。

    二、容器的使用

    vector的功能强大,成员函数很多,我不想按普通教程的方式来介绍它,那样会太烦锁,我根据实际开发中应用的场景,采用示例程序介绍vector常用的用法。

    1、存放整数

    示例(book220.cpp)

    /*
     * 程序名:book220.cpp,此程序用于演示C++容器存放整数
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    #include <vector>      // vector需要的头文件
    #include <algorithm>   // sort函数需要的头文件
    
    int main () 
    { 
      int height=0;             // 存放从键盘输入的超女身高
      std::vector<int> vheight; // 存放超女身高的容器
    
      while (true)
      {
        printf("请输入超女身高(0-结束输入):");
        scanf("%d",&height);         // 接受键盘输入的数据
        if (height==0) break;        // 0-结束输入
        vheight.push_back(height);   // 把数据追加入容器
      }
    
      for (int ii=0;ii<vheight.size();ii++) // 显示排序前容器中的记录
      { 
        printf("vheight[%d]=%d
    ",ii,vheight[ii]);
      }
    
      sort(vheight.begin(),vheight.end());  // 容器中的记录排序
    
      for (int ii=0;ii<vheight.size();ii++) // 显示排序后容器中的记录
      { 
        printf("vheight[%d]=%d
    ",ii,vheight[ii]);
      }
    
      // vheight.clear();  // 清空容器,可以不写。
    }
    

    运行效果

    在这里插入图片描述

    程序解释如下:

    std::vector<int> vheight;   // 声明容器用于存放整数,超女身高,单位是cm。
    

    void push_back(const T& x)成员函数:向容器尾部增加一个元素x,x就是您要向容器中增加的变量,在本示例中是一个整数,注意,参数x是一个引用,要用变量的名称,不是变量的地址,如vheight.push_back(height);。

    int size()成员函数:返回容器中数据的元素总数。

    像数组一样访问容器:容器像数组一样,可以用数组的下标访问,vheight[0]表示容器的第1个元素,vheight[n]表示容器的第n+1个元素。注意,采用下标方式放问容器的时候,下标不要越界,否则可能会引起内存溢出。

    iterator begin()成员函数:返回容器头指针,指向第一个元素。

    iterator end()成员函数:返回容器尾指针,指向容器最后一个元素的下一个位置。

    容器中的元素排序:采用sort()函数对容器中的元素进行排序。如sort(vheight.begin(),vheight.end());表示对容器中全部的元素进行排序。

    void clear():清空容器中的全部元素,注意两点:1)容器被声明的时候,本来就是空的;2)容器是类,有析构函数,析构函数中会自动清空容器中的元素,释放内存资源,不需要程序员担心。但是,程序员也可以调clear()函数手工清空容器中的元素。

    示例book220.cpp程序展示了vector容器10%的功能和成员函数,但是,在实际开发中,对容器的操作,95%的内容就是这些。

    2、存放字符串

    示例(book222.cpp)

    /*
     * 程序名:book222.cpp,此程序用于演示C++容器存放字符串
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    #include <string.h>    
    #include <string>       // string需要的头文件
    #include <vector>       // vector需要的头文件
    
    int main () 
    { 
      char strtmp[50];                // 存放姓名的临时变量
      std::string name;               // 存放从键盘输入的超女姓名
      std::vector<std::string> vname; // 存放超女姓名的容器
    
      while (true)
      {
        printf("请输入超女姓名(0-结束输入):");
        scanf("%s",strtmp);               // 接受键盘输入的数据
        if (strcmp(strtmp,"0")==0) break; // 0-结束输入
        vname.push_back(strtmp);          // 把数据追加入容器
      }
    
      for (int ii=0;ii<vname.size();ii++) // 显示容器中的记录
      { 
        printf("vname[%d]=%s
    ",ii,vname[ii].c_str());
      }
    }
    

    运行效果

    在这里插入图片描述

    注意几个问题:

    1)用容器存放字符串,数据类型用string,不是C语言用0结尾的字符数组char [],string是一个变量,char []是一组变量。

    2)用vname.push_back()成员函数把数据追加到容器中,参数的类型可以是string,也可以是char[],但是,这并不是vector的特征,而是string的特征,容器声明的是string类型,string的构造函数支持char [],表面上看push_back()进去的是char [],实际上会被转换为string。

    3、存放结构体

    示例(book225.cpp)

    /*
     * 程序名:book225.cpp,此程序用于演示C++容器存放结构体
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    #include <string.h>    
    #include <vector>       // vector需要的头文件
    
    struct st_girl       // 超女数据结构
    {
      char name[50];     // 姓名
      int  age;          // 年龄
    };
    
    int main () 
    { 
      struct st_girl stgirl;             // 超女数据结构
      std::vector<struct st_girl> vgirl; // 存放超女结构体的容器
    
      strcpy(stgirl.name,"西施"); stgirl.age=18;
      vgirl.push_back(stgirl);
    
      strcpy(stgirl.name,"杨玉环"); stgirl.age=28;
      vgirl.push_back(stgirl);
    
      // 采用数组下标访问容器中的记录
      for (int ii=0;ii<vgirl.size();ii++) 
      { 
        printf("vgirl[%d].name=%s,vgirl[%d].age=%d
    ",
                ii,vgirl[ii].name,ii,vgirl[ii].age);
      }
    
      // 把容器中的记录复制到结构体
      for (int ii=0;ii<vgirl.size();ii++) 
      { 
        memcpy(&stgirl,&vgirl[ii],sizeof(struct st_girl));
        printf("stgirl.name=%s,stgirl.age=%d
    ",stgirl.name,stgirl.age);
      }
    }
    

    运行结果

    在这里插入图片描述

    总的来说,存放结构体的容器和数组的用法基本相同。

    在book225.cpp中,采用了memcpy函数,它是C语言的库函数,用于内存中的数据复制,声明如下:

    void *memcpy(void *dest, const void *src, size_t n);
    

    dest:指向用于存储复制内容的目标地址,类型强制转换为 void* 指针。

    src:指向要复制的数据源地址,类型强制转换为 void* 指针。

    n:要被复制的字节数。

    该函数返回dest。

    4、存放类

    示例(book222.cpp)演示的存放字符串,string就是类。

    三、其它成员函数

    vector的成员函数比较多,为了不增加各位的学习负担,我只介绍常用的。

    1、定位的函数

    iterator begin():返回容器头的指针,指向容器第一个元素的位置。

    iterator end():返回容器尾的指针,指向容器最后一个元素的下一个位置。

    iterator是跌代器,这个名字让人难以理解,那就先不要管它,以下我会举例说明用法,一般来说,begin()和end()成员函数用于其它成员函数的参数中。

    2、增加元素的函数

    void push_back(const T& x):向容器的尾部增加一个元素x。

    iterator insert(iterator it,const T& x):向容器中指定位置(it)前插入一个元素x。

    strcpy(stgirl.name,"王昭群"); stgirl.age=22;
    vgirl.insert(vgirl.begin()+1,stgirl);  // 在第2个元素前插入一个元素。
    

    3、删除元素的函数

    iterator erase(iterator it):删除容器中指定位置(it)的元素。

    vgirl.erase(vgirl.begin()+2);  // 删除容器中第3个元素。
    void pop_back():删除容器中最后一个元素。
    void clear():清空容器中全部的元素。
    

    4、判断容器的大小

    bool empty():判断容器是否为空。

    int size():返回容器中元素的个数。

    四、容器的排序

    在实际开发中,往往需要对vector容器中的元素进行排序,sort函数可以实现排序功能。

    sort(begin,end,cmp);
    

    sort函数包含在头文件为#include <algorithm>的c++标准库中,调用排序方法不必知道其内部是如何实现的,只要出现我们想要的结果就行。

    sort函数有三个参数:

    (1)第一个是要排序的数组的起始地址。

    (2)第二个是结束的地址。

    (3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时缺省的排序方法是从小到大排序。如果vector容器中元素的数据类型不是基本数据类型,sort函数必须指定排序方法函数。

    示例(book227.cpp)

    /*
     * 程序名:book227.cpp,此程序用于演示C++容器的排序
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    #include <string.h>    
    #include <vector>      // vector需要的头文件
    #include <algorithm>   // sort函数需要的头文件
    
    struct st_girl       // 超女数据结构
    {
      char name[50];     // 姓名
      int  age;          // 年龄
    };
    
    // 自定义排序函数,按超女姓名排序
    bool sortbyname(const st_girl &p1,const st_girl &p2)
    {
      if (strcmp(p1.name,p2.name)<=0) return true;
      return false;
    }
    
    // 自定义排序函数,按超女年龄排序
    bool sortbyage(const st_girl &p1,const st_girl &p2)
    {
      if (p1.age<p2.age) return true;
      return false;
    }
    
    int main () 
    { 
      struct st_girl stgirl;             // 超女数据结构
      std::vector<struct st_girl> vgirl; // 存放超女结构体的容器
    
      strcpy(stgirl.name,"西施"); stgirl.age=18;
      vgirl.push_back(stgirl);
    
      strcpy(stgirl.name,"杨玉环"); stgirl.age=28;
      vgirl.push_back(stgirl);
    
      //sort(vgirl.begin(),vgirl.end());   // 如果不指定排序函数,编译将报错
      //sort(vgirl.begin(),vgirl.end(),sortbyname); // 按超女的姓名排序
      sort(vgirl.begin(),vgirl.end(),sortbyage);  // 按超女的年龄排序
    
      for (int ii=0;ii<vgirl.size();ii++) 
      { 
        printf("vgirl[%d].name=%s,vgirl[%d].age=%d
    ",
                ii,vgirl[ii].name,ii,vgirl[ii].age);
      }
    }
    

    五、课后作业

    1)编写示例程序,类似本章节的book220.cpp、book222.cpp、book225.cpp、book227.cpp,编译并运行它,记住,程序员是写出来的,不是看出来的,熟能生巧,您每天的付出都有意义。

    2)编写示例程序,测试一下vector容器其它成员函数的用法,玩一下就行了,有些成员函数以后可能有用。

    3)丰富您的函数库,写一个类,封装随机数功能,类的声明如下:

    class CRand
    {
    public:
      vector<int> m_val;  // 用于存放生成好的随机数
      CRand();
     ~CRand();
      void Rand(const int minvalue,const int maxvalue,bool brep=true);
    }
    

    注意:

    (1)随机数的种子不能只用time(0)的秒,还可以利用微秒,同一秒内取到的随机数将不同。

    (2)Rand(const int minvalue,const int maxvalue,bool brep=true)生成指定范围的随机数,minvalue是最小值,maxvalue是最大值,brep是否允许重复。

    4)vector容器的排序在实际开发中应用比较多,必须掌握。

    5)vector容器存放超女类,能不写排序函数吗?如果存放string类,能不写排序函数吗?为什么?

    六、版权声明

    C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
    来源:C语言技术网(www.freecplus.net)
    作者:码农有道

    如果文章有错别字,或者内容有错误,或其他的建议和意见,请您留言指正,非常感谢!!!

  • 相关阅读:
    求树的直径算法
    二叉排序树BST+求树深度算法
    HDU1114Piggy-Bank(完全背包)
    HDU1102(最小生成树Kruskal算法)
    NYoj289苹果(0-1背包)
    NYOJ201作业题
    C#发送邮件附件
    JS用户登录保存账号密码
    远程连接服务器
    博客园页面更新了
  • 原文地址:https://www.cnblogs.com/wucongzhou/p/12498259.html
Copyright © 2011-2022 走看看