• C++ 之 标准模板库(STL)的容器与迭代器


    标准模板库

    泛型程序设计(generic programming)的思想 : 模板机制,以及标准模板库STL 。

    标准模板库 (STL,Standard Template Libaray)
      一些常用数据结构和算法的模板的集合。将一些常用的数据结构(比如链表,数组,二叉树)和算法(比如排序,查找)写成模板,以后则不论数据结构里放的是什么对象,算法针对什么样的对象,则都不必重新实现数据结构,重新编写算法。

    容器概述

    可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构,都是类模版,分为三种:

    1. 顺序容器
      vector,deque,list
    2. 关联容器(排序的,查找速度更快)
      set,multiset,map,multimap
    3. 容器适配器
      stack,queue,priority_queue

    对象被插入容器中时,被插入的是对象的一个复制品。许多算法,比如排序,查找,要求对容器中的元素进行比较,有的容器本身就是排序的,所以,放入容器的对象所属的类,往往还应该重载 ==< 运算符。

    顺序容器

    容器并非排序的,元素的插入位置同元素的值无关。有 vector,deque,list三种。

    vector 头文件 <vector>

      动态数组。元素在内存连续存放。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能(大部分情况下是常数时间)。

    --- A0 A1 A2 --- --- --- --- --- --- --- An ---
    begin end

    deque 头文件 <deque>

      双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(但次于vector)。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。

    --- --- A0 A1 A2 A3 A4 A5 --- --- --- --- --- --- ---
    begin end

    list 头文件 <list>
    双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。
    在这里插入图片描述

    关联容器

    • 元素是排序的
    • 插入任何元素,都按相应的排序规则来确定其位置
    • 在查找时具有非常好的性能
    • 通常以平衡二叉树方式实现,插入和检索的时间都是O(log(N))

    set/multiset 头文件 <set>

      set 即集合。set中不允许相同元素,multiset中允许存在相同的元素。

    map/multimap 头文件 <map>
      map与set的不同在于map中存放的元素有且仅有两个成员变量,一个名为first,另一个名为second,map根据first值对元素进行从小到大排序,并可快速地根据first来检索元素。那first 则相当于关键字,second 则存储的是值;
      map同multimap的不同在于是否允许相同first值的元素,即关键字可重复与否;

    容器适配器

    stack:头文件<stack>
      栈。是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项(栈顶的项)。后进先出
    在这里插入图片描述
    queue头文件<queue>
      队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。先进先出
    在这里插入图片描述
    priority_queue 头文件<queue>
      优先级队列。最高优先级元素总是第一个出列

    顺序/关联容器中均有的成员函数

    • begin 返回指向容器中第一个元素的迭代器
    • end 返回指向容器中最后一个元素后面的位置的迭代器
    • rbegin 返回指向容器中最后一个元素的迭代器
    • rend 返回指向容器中第一个元素前面的位置的迭代器
    • erase 从容器中删除一个或几个元素
    • clear 从容器中删除所有元素

    顺序容器常用函数

    • front:返回容器中第一个元素的引用
    • back:返回容器中最后一个元素的引用
    • push_back:在容器末尾增加新元素
    • pop_back:删除容器末尾的元素。
    • erase:删除迭代器指向的元素(可能会使该迭代器失效),或删除一个区间,返回被删除元素后面的那个元素的迭代器

    迭代器

    定义一个容器类的迭代器的方法可以是:

    容器类名::iterator 变量名;
    容器类名::const_iterator 变量名;
    
    容器类名::reverse_iterator 变量名;
    容器类名::const_reverse_iterator 变量名;
    

    访问一个迭代器指向的元素:*选代器变量名。

    • 用于指向顺序容器和关联容器中的元素
    • 迭代器用法和指针类似
    • 有const和非const两种
    • 通过迭代器可以读取它指向的元素
    • 通过非const选代器还能修改其指向的元素

      迭代器上可以执行++操作,以使其指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,此时再使用它,就会出错,类似于使用NULL或未初始化的指针一样。

    双向迭代器

    • 若p和p1都是双向迭代器,则可对p、p1可进行以下操作:
    • ++p,p++使p指向容器中下一个元素
    • --p,p-使p指向容器中上一个元素
    • *p取p指向的元素
    • p=p1赋值
    • p==p1,p!=p1判断是否相等、不等

    随机访问迭代器

    • 双向迭代器的所有操作
    • p+=i 将p向后移动i个元素
    • p-=i 将p向向前移动i个元素
    • p+i 值为:指向p后面的第i个元素的迭代器
    • p-i 值为:指向p前面的第i个元素的迭代器
    • p[i] 值为:p后面的第i个元素的引用
    • p<p1,p<=p1,p>p1,p>=p1

    容器容器上的迭代器类别

    • vector 随机访问
    • deque 随机访问
    • list 双向
    • set/multiset 双向
    • map/multimap 双向
    • stack 不支持选代器
    • queue 不支持迭代器
    • nriority aueue不支持迭代器

    有的算法,例如sort,binary_search需要通过随机访问迭代器来访问容器中的元素,那么list以及关联容器就不支持该算法!

    容器详解

    顺序容器

    Vector

    • 可变长的动态数组
    • 必须包含头文件 #include <vector>
    • 支持随机访问迭代器
      • 根据下标随机访问某个元素时间为常数
      • 在尾部添加速度很快
      • 在中间插入慢

    成员函数:

    成员函数 作用
    vector(); 无参构造函数,将容器初始化成空的
    vector(int n); 将容器初始化成有n个元素
    vector(int n,const T&val); 假定元素类型是T,将容器初始化成有n个元素,每个元素的值都是Val
    vector(iterator first,iterator last); 将容器初始化为与别的容器上区间[first,last)一致的内容
    void pop_back(); 删除容器末尾的元素
    void push_back(const T&val); 将val添加到容器末尾
    int size(); 返回容器中元素的个数
    T&font(); 返回容器中第一个元素的引用
    T&back(); 返回容器中最后一个元素的引用

    List

    • 在任何位置插入/删除都是常数时间
    • 不支持根据下标随机存取元素
    • 具有所有顺序容器都有的成员函数

    成员函数:

    成员函数 作用
    push_front 在链表最前面插入
    pop_front 删除链表最前面的元素
    sort 排序(list不支持STL的算法sort)
    remove 删除和指定值相等的所有元素
    unique 删除所有和前一个元素相同的元素
    merge 合并两个链表,并清空被合并的链表
    reverse 颠倒链表
    splice 在指定位置前面插入另一链表中的一个或多个元素,并在另一链表中删除被插入的元素

    Deque

    双向队列

    必须包含头文件#include <deque>

    成员函数:

    • 所有适用于vector的操作都适用于deque
    • deque还有 push_front(将元素插入到容器的头部)和pop_front(删除头部的元素)操作

    关联容器

    set,multiset,map,multimap

    • 内部元素有序排列,新元素插入的位置取决于它的值,查找速度快。
    • 除了各容器都有的函数外,还支持以下成员函数:
      • find:查找等于某个值的元素(x小于y和y小于x同时不成立即为相等)
      • lower bound:查找某个下界
      • upper_bound:查找某个上界
      • equal_range:同时查找上界和下界
      • count:计算等于某个值的元素个数(x小于y和y小于x同时不成立即为相等)
      • insert:用以插入一个元素或一个区间

    map/multimap容器里放着的都是pair模版类的对象,且按first从小到大排序

    template<class _T1, class _T2>
    struct pair{
    typedef_T1 first type; 
    typedef_T2 second_type; 
    T1 first; 
    T2 second; 
    pair(): first(), second(){}
    pair(const _T1&a, const_T2&b) : first(_a), second(b){}
    template<class _U1, class _U2>
    pair(const pair<_U1,_U2>&p) : first(p. first), second(p. second){}
    

    Multiset

    实现 :

    template<class Key,class Pred=less<Key>,class A=allocator<Key>>
    class multiset{.....};
    
    • Pred类型的变量决定了multiset中的元素,“一个比另一个小”是怎么定义的。
      multiset运行过程中,比较两个元素x,y的大小的做法,就是生成一个Pred类型的变量,假定为op,若表达式op(x,y)返回值为true,则x比y小。
      Pred的缺省类型是less<Key>。

    • 其中less模板定义:

    template<class T>
    struct less:public binary_function<T,T,bool>
    {bool operator()(const T& x,const T& y){returnx<y;}const;};
    

    成员函数 :

    成员函数 作用
    iterator find(const T&val); 在容器中查找值为val的元素,返回其迭代器.如果找不到,返回end().
    iterator insert(const T&val); 将val插入到容器中并返回其迭代器.
    void insert(iterator first,iterator last); 将区间[first,last)插入容器.
    int count(const T&val); 统计有多少个元素的值和val相等.
    iterator lower bound(const T&val); 查找一个最大的位置it,使得[begin(),it),中所有的元素都比val小.
    iterator upper bound(const T&val); 查找一个最小的位置t,使得[t,end())中所有的元素都比val大.
    pair<iterator,iterator>equal_range(const T&val); 同时求得lower_bound和upper_bound.
    iterator erase(iterator it); 删除it指向的元素,返回其后面的元素的迭代器(Visual studio2010上如此,但是在cpp标准和Dev cpp中,返回值不是这样).

    Set

    实现 :

    template<class Key,class Pred=less<Key>,class A=allocator<Key>>
    class set{...}
    

    插入set中已有的元素时,忽略插入,重复的定义 : (a<b)||(b<a)=0

    插入函数的不同

    template<typename T>
    pair<std::set<T>::iterator,bool> insert(const T&val); 将val插入到容器中并返回其迭代器。
    

    Multimap

    实现 :

    template<class Key,class T,class Pred=less<Key>,classA=allocator<T>>
    class multimap{
    ..
    typedef pair<const Key,T> value_type;
    ...…
    };//Key代表关键字的类型
    
    • multimap中的元素由〈关键字,值〉组成,每个元素是一个pair对象,关键字就是first成员变量,其类型是Key
    • multimap中允许多个元素的关键字相同.元素按照first成员变量从小到大排列,缺省情况下用less<Key>定义关键字的"小于"关系.

    示例:

    # include <iostream>
    # include<map>
    using namespace std; 
    int main(){
    typedef multimap<int, double, less<int>>mmid; 
    mmid pairs; 
    pairs.insert(mmid: value_type(15,2.7);
    cout<<"含有15元素个数:"<<pairs.count(15)<< endl; 
    

    Map

    实现 :

    template<class Key,class T,class Pred=less<Key>, class A=allocator<T>>
    class map{
    ... ...
    typedef pair<const Key,T> value_type;
    ... ...
    };
    
    • map中的元素都是pair模板类对象.关键字(first成员变量)各不相同.元素按照关键字从小到大排列,缺省情况下用less<Key>, 即"<"定义"小于"。

    若pairs为map模版类的对象

    • pairs[key]
      返回对关键字等于key的元素的值(second成员变量)的引用。若没有关键字为key的元素,则会往pairs里插入一个关键字为key的元素,其值用无参构造函数初始化,并返回其值的引用。
      如:
      map<int,double>pairs;pairs[50]=5;会修改pairs中关键字为50的元素,使其值变成5。
      若不存在关键字等于50的元素,则插入此元素,并使其值变为5。

    实用类模板bitset

    实现

    bitset template<size_tN>
    class bitset
    {
    ......
    };
    

    特性

    • 实际使用的时候,N是个整型常数如:
      bitset<40>bst;
    • bst是一个由40位组成的对象
    • 用bitset的函数可以方便地访问任何一位

    成员函数

    • bitset&operator&=(const bitset&rhs);
    • bitset&operatorl=(const bitset&rhs);
    • bitset&operatorA=(const bitset&rhs);
    • bitset&operator<<=(size_tnum);
    • bitset&operator>>=(size_tnum);
    • bitset&set();/全部设成1
    • bitset&set(size_t pos,bool val=true);//设置某位
    • bitset&reset();//全部设成0
    • bitset&reset(size_t pos);/某位设成0
    • bitset&flip();//全部翻转
    • bitset&flip(size_t pos);//翻转某位
    • reference operator[](size_t pos);//返回对某位的引用。
    • bool operator[](size_t pos)const;//判断某位是否为1
    • reference at(size_t pos);
    • bool at(size_t pos)const;
    • unsigned long to_ulong()const;//转换成整数
    • string to_string()const;//转换成字符串
    • size_t count()const;//计算1的个数
    • size_t size()const;
    • bool operator==(const bitset&rhs)const;
    • bool operator!=(const bitset&rhs)const;

    容器适配器详解

    可以用某种顺序容器来实现
    (让已有的顺序容器以栈/队列的方式工作)

    1. stack:头文件
      栈--后进先出
    2. queue:头文件
      队列--先进先出
    3. priority_queue:头文件
      优先级队列--最高优先级元素总是第一个出列R

    都有3个成员函数:

    • push:添加一个元素;
    • top:返回栈顶部或队头元素的引用
    • pop:删除一个元素容器适配器上没有迭代器
      STL中各种排序,查找,变序等算法都不适合容器适配器

    Stack

    实现 :

    template<class T,class Cont=deque<T>>
    class stack{
    ...
    };
    
    • stack 是后进先出的数据结构
    • 只能插入,删除,访问栈顶的元素
    • 可用 vector,,list,deque来实现
      • 缺省情况下,用deque实现
      • 用vector和deque实现,比用list实现性能好
    • push,pop,top函数均在栈顶

    Queue

    实现 :

    template<class T,class Cont=deque<T>>
    class queue{
    };
    
    • 和stack 基本类似,可以用list和deque实现
    • 缺省情况下用deque实现
    • push在队尾,pop,top函数均在队头

    Priority_queue

    • 和queue类似,可以用vector和deque实现
    • 缺省情况下用vector实现
    • priority_queue 通常用堆排序技术实现,保证最大的元素总是在最前面
      • 执行pop操作时,删除的是最大的元素
      • 执行top操作时,返回的是最大元素的引用
    • 默认的元素比较器是less<T>
    任世事无常,勿忘初心
  • 相关阅读:
    操作系统 实验一 命令解释程序的编写
    软件工程 《构建之法》1、2、3章读后感
    软件工程实验一 复利计算 第四次实验
    软件工程实验一 复利计算(第三次实验实验总结)
    软件工程实验一 复利计算
    实验0 了解和熟悉操作系统
    团队工作总结及自评 & 补上来的用户调研
    四则运算安卓版ver.mk2
    安卓版四则运算
    每日更新
  • 原文地址:https://www.cnblogs.com/FlameBlog/p/14715412.html
Copyright © 2020-2023  润新知