C++学习笔记(Day17 容器的基本功能与分类、顺序容器)

容器的基本功能与分类

  • 容器类是容纳、包含一组元素或元素集合的对象。

  • 基于容器中元素的组织方式:顺序容器、关联容器

  • 按照与容器所关联的迭代器类型划分:可逆容器随机访问容器

容器的基本功能与分类

  • 容器

    • unorderedset (无序集合)、unorderedmultiset(无序多重集合)

    • unorderedmap(无序映射)、unordermultimap(无序多重映射)

    • set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)

    • array(数组)、vector(向量)、deque(双端队列)、forward_list(单链表)、list(列表)

    • 顺序容器

    • (有序)关联容器

    • 无序关联容器

容器的分类

容器的通用功能

  • 容器的通用功能

    • 用默认构造函数构造空容器

    • 支持关系运算符:==、!=、<、<=、>、>=

    • begin()、end():获得容器首、尾迭代器

    • clear():将容器清空

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

    • size():得到容器元素个数

    • s1.swap(s2):将s1和s2两容器内容交换

  • 相关数据类型(S表示容器类型)

    • S::iterator:指向容器元素的迭代器类型

    • S::const_iterator:常迭代器类型

对可逆容器的访问

  • STL为每个可逆容器都提供了逆向迭代器,逆向迭代器可以通过下面的成员函数得到:

    • rbegin() :指向容器尾的逆向迭代器

    • rend():指向容器首的逆向迭代器

  • 逆向迭代器的类型名的表示方式如下:

    • S::reverse_iterator:逆向迭代器类型

    • S::constreverseiterator:逆向常迭代器类型

随机访问容器

  • 随机访问容器支持对容器的元素进行随机访问

    • s[n]:获得容器s的第n个元素

 

顺序容器的基本功能

顺序容器

  • 向量(vector)

  • 双端队列(deque)

  • 列表(list)

  • 单向链表(forward_list) (以上四种在逻辑上可看作是一个长度可扩展的数组)

  • 数组(array)

  • 元素线性排列,可以随时在指定位置插入元素和删除元素。

  • 必须符合Assignable这一概念(即具有公有的拷贝构造函数并可以用“=”赋值)。

  • array对象的大小固定,forward_list有特殊的添加和删除操作

顺序容器的接口(不包含单向链表(forward_list)和数组(array)

  • 构造函数

  • 赋值函数

    • assign

  • 插入函数

    • insert, pushfront(只对list和deque), pushback,emplace,emplace_front

    • 删除函数

    • erase,clear,popfront(只对list和deque) ,popback,emplace_back

  • 首尾元素的直接访问

    • front,back

  • 改变大小

    • resize

 例10-4 顺序容器的基本操作

#include <iostream>
#include <list>
#include <deque>
#include <iterator>
using namespace std;

//输出制定的顺序容器的元素
template <class T>
void printContainer(const char* msg,const T& s){
    cout << msg << ": ";
    copy(s.begin(),s.end(),ostream_iterator<int>(cout," "));
    cout << endl;
}
int main(){
    deque<int> s;
    for(int i=0;i<10;i++){
        int x;
        cin >> x;
        s.push_front(x);
    }
    printContainer("deque ai first",s);
    //用s容器的内容的逆序构造列表容器l
    list<int> l(s.rbegin(),s.rend());
    printContainer("list at first",l);
    //将列表容器l的每相邻两个元素顺序颠倒
    list<int>::iterator iter = l.begin();
    while(iter !=l.end()){
        int v = *iter;
        iter = l.erase(iter);
        l.insert(++iter,v);
    }
    printContainer("list at last",l);
    //用列表容器l的内容给s赋值,将s输出
    s.assign(l.begin(),l.end());
    printContainer("deque at last",s);
    return 0;
}

顺序容器的特性

  • 顺序容器:向量、双端队列、列表、单向链表、数组

  • 向量(Vector)

  • 向量的容量
    • 容量(capacity):实际分配空间的大小

    • s.capacity() :返回当前容量

    • s.reserve(n):若容量小于n,则对s进行扩展,使其容量至少为n

  • 特点

    • 一个可以扩展的动态数组

    • 随机访问、在尾部插入或删除元素快

    • 在中间或头部插入或删除元素慢

  • 双端队列(deque)

    • 在两端插入或删除元素快

    • 在中间插入或删除元素慢

    • 随机访问较快,但比向量容器慢

    • 特点

例10-5 奇偶排序

先按照从大到小顺序输出奇数,再按照从小到大顺序输出偶数。

// 头部分省略
int main() {
    istream_iterator<int> i1(cin), i2;  //建立一对输入流迭代器
    vector<int> s1(i1, i2); //通过输入流迭代器从标准输入流中输入数据
    sort(s1.begin(), s1.end()); //将输入的整数排序
    deque<int> s2;
    //以下循环遍历s1
    for (vector<int>::iterator iter = s1.begin(); iter != s1.end(); ++iter) 
    {
         if (*iter % 2 == 0)    //偶数放到s2尾部
             s2.push_back(*iter);
         else       //奇数放到s2首部
             s2.push_front(*iter);
    }
    //将s2的结果输出
    copy(s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    return 0;
}

列表(list)

  • 特点

    • 在任意位置插入和删除元素都很快

    • 不支持随机访问

  • 接合(splice)操作

    • s1.splice(p, s2, q1, q2):将s2中[q1, q2)移动到s1中p所指向元素之前

      // 头部分省略
      int main() {
          string names1[] = { "Alice", "Helen", "Lucy", "Susan" };
          string names2[] = { "Bob", "David", "Levin", "Mike" };
          //用names1数组的内容构造列表s1
          list<string> s1(names1, names1 + 4); 
          //用names2数组的内容构造列表s2
          list<string> s2(names2, names2 + 4); 
      
          //将s1的第一个元素放到s2的最后
          s2.splice(s2.end(), s1, s1.begin());
          list<string>::iterator iter1 = s1.begin(); //iter1指向s1首
          advance(iter1, 2); //iter1前进2个元素,它将指向s1第3个元素
          list<string>::iterator iter2 = s2.begin();  //iter2指向s2首
          ++iter2; //iter2前进1个元素,它将指向s2第2个元素
          list<string>::iterator iter3 = iter2; //用iter2初始化iter3
          advance(iter3, 2); //iter3前进2个元素,它将指向s2第4个元素
          //将[iter2, iter3)范围内的结点接到s1中iter1指向的结点前
          s1.splice(iter1, s2, iter2, iter3); 
      
          //分别将s1和s2输出
          copy(s1.begin(), s1.end(), ostream_iterator<string>(cout, " "));
          cout << endl;
          copy(s2.begin(), s2.end(), ostream_iterator<string>(cout, " "));
          cout << endl;
          return 0;
      }

单向链表(forward_list)

  • 单向链表每个结点只有指向下个结点的指针,没有简单的方法来获取一个结点的前驱;

  • 未定义insert、emplace和erase操作,而定义了insertafter、emplaceafter和erase_after操作,其参数与list的insert、emplace和erase相同,但并不是插入或删除迭代器p1所指的元素,而是对p1所指元素之后的结点进行操作;

  • 不支持size操作。

数组(array)

  • array是对内置数组的封装,提供了更安全,更方便的使用数组的方式

  • array的对象的大小是固定的,定义时除了需要指定元素类型,还需要指定容器大小。

  • 不能动态地改变容器大小

顺序容器的比较

  • STL所提供的顺序容器各有所长也各有所短,我们在编写程序时应当根据我们对容器所需要执行的操作来决定选择哪一种容器。

    • 如果需要执行大量的随机访问操作,而且当扩展容器时只需要向容器尾部加入新的元素,就应当选择向量容器vector;

    • 如果需要少量的随机访问操作,需要在容器两端插入或删除元素,则应当选择双端队列容器deque;

    • 如果不需要对容器进行随机访问,但是需要在中间位置插入或者删除元素,就应当选择列表容器list或forward_list;

    • 如果需要数组,array相对于内置数组类型而言,是一种更安全、更容易使用的数组类型。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值