C++中容器的使用

来源:互联网 发布:丹尼格林13总决赛数据 编辑:程序博客网 时间:2024/06/05 06:09

       C++中有两种类型的容器:顺序容器关联容器。顺序容器主要有vector、list、deque等。其中vector表示一段连续的内存,基于数组实现,list表示非连续的内存,基于链表实现,deque与vector类似,但是对首元素提供插入和删除的双向支持。关联容器主要有map和set。map是key-value形式,set是单值。map和set只能存放唯一的key,multimap和multiset可以存放多个相同的key。

       容器类自动申请和释放内存,因此无需new和delete操作。我们把 vector 称为容器,是因为它可以包含其他对象一个容器中的所有对象都必须是同一种类型的


下面介绍部分容器使用详细:

1.vector

   vector类型得到标准定义为:vector<T> v1;其中T为类型,这里可以是内置类型,如int等,也可以是结构体或者类类型。

   初始化

  vector<T> v1;    //v1是一个空的vector,它潜在的元素是T类型,执行默认初始化

   vector<T> v2(v1);  //v2中包含有v1的所有元素的副本

   vector<T> v2 = v1; //等价于v2(v1),v2中包含有v1所有元素的副本

   vector<T> v3(n, val); //v3包含了n个重复的元素,每个元素的值都是val

   vector<T> v4(n); //v4中包含了n个重复执行了值初始化的对象

   vector<T> v5{a,b,c,......}; //v5包含了初始值个数的元素,每个元素被赋予了相应的初始值

   vector<T> v5 = {a,b,c,.......}; //等价于上面的v5

  这里要区分是列表初始化还是值初始化

  vector<int> v1(10);          //v1有10个元素,每个元素的值都是0

  vector<int> v2{10};         //v2有1个元素,该元素的值为10

   vector<int> v3(10,1);      //v3有10个元素,每个元素的值都是1

   vector<int> v4{10,1};     //v4有2个元素,值分别为10和1

  其他操作

vector常用操作方法:

     vec1.push_back(100);            //尾部添加元素

     int size = vec1.size();         //元素个数

     bool isEmpty = vec1.empty();    //判断是否为空

     cout<<vec1[0]<<endl;        //取得第一个元素

     vec1.insert(vec1.end(),5,3);    //vec1.back位置插入5个值为3的元素

     vec1.pop_back();              //删除末尾元素

     vec1.erase(vec1.begin(),vec1.begin()+2);//删除vec1[0]-vec1[2]之间的元素,不包括vec1[2]其他元素前移

    cout<<(vec1==vec2)?true:false;  //判断是否相等==、!=>=<=...

     vector<int>::iterator iter = vec1.begin();    //获取迭代器首地址

    vector<int>::const_iterator c_iter = vec1.begin();   //获取const类型迭代器

    vec1.clear();                 //清空元素

  

遍历之一:下标法

    int length = vec1.size();

     for(int i=0;i<length;i++)

     {

        cout<<vec1[i];

     }

     cout<<endl<<endl;

遍历之二:迭代器法

    vector<int>::iterator iter = vec1.begin();

     for(;iter != vec1.end();iter++)

     {

        cout<<*iter;

     }

2.list

  这里list和vector基本操作相同,这里就说说它们之间的区别,便于我们选择用哪一种容器更好,区别如下:

(1)  vector是顺序表,表示的是一块连续的内存,元素被顺序存储;list是双向连接表,在内存中不一定连续。

(2)当数值内存不够时,vector会重新申请一块足够大的连续内存,把原来的数据拷贝到新的内存里面;list因为不用考虑内存的连续,因此新增开销比vector小。

(3)list只能通过指针访问元素,随机访问元素的效率特别低,在需要频繁随机存取元素时,使用vector更加合适。

(4)当向vector插入或者删除一个元素时,需要复制移动待插入元素右边的所有元素;因此在有频繁插入删除操作时,使用list更加合适。

注释:下面介绍一个list和vector中的插入。

     vector中可以使用push_back()向容易的尾端插入指定的数据,但是不能使用push_front,该函数是向容器的首端插入指定的元素,这里我们就可以使用insert()函数来实现插入操作,insert包括两个参数,一个参数是迭代器,用于指出插入元素的位置,这里即使是尾端迭代器也可以,所以insert完成的是向该迭代器所指位置的前一个位置插入指定的元素,如:

   vector<string> vec;

   list<string> lst;

   lst.insert(lst.begin(), "Hello"); //向list类型容器的lst的首端插入”Hello“

   vec.insert(vec.begin(), "Hello"); //同上

   insert除了上述接收两个参数的形式外,还可以接收三个参数,如:

   vec.insert(vec.begin(), 10, "Hello");  //添加10个Hello字符串到vec的首端

   vector<string> v = {"quasi", "simba", "frollo", "scar"};

   vec.insert(vec.begin(), v.end()-2, v.end()); //将v的最后两个插入vec的首端

   lst.insert(lst.end(), {"shese", "words", "will", "go”, "at", "the", "end"}); //将后面的列表中的字符串插入lst的尾部

 注:迭代器表示要拷贝的范围,不能指向与目的位置相同的容器,如:

   lst.insert(lst.begin(), lst.begin(), lst.end());// 这里要插入的迭代器容器是lst,但是要拷贝的范围也是lst,所以运行时会出现错误。

3.map

   map是属于关联容器这一类的,包括两个参数,第一个参数是关键字,第二个参数的该关键字对应的值。

   对map的一个经典例子是单词计数器程序:

   map<string, size_t> word_count; //string 到size_t的空map

   string word;

   while(cin >> word)

         ++word_count[word];   //提取word的计数器并将其加1

   for(const auto &w : word_count)   //使用基于范围的for语句依次访问map中的数据

        cout << w.first << "occurs" << w.second << ((w.second > 1) ? "times" : "time") << endl;

一般很多时候,我们会将map和set连起来一起用,如下面的例子是改进的上面的单词计数器的例子,本例子中只统计不在exclude中的单词

  map<string, size_t> word_count;

  set<string> exclude = {"the", "But", "And", "At", "A", "An"};

  string word;

  while(cin >> word)

      if (exclude.find(word) == exclude.end())

          ++word_count[word];

待续......