• <<C++标准程序库>>中的STL简单学习笔记


    0. 内容为个人学习笔记, 仅供参考, 如有错漏, 欢迎指正!

    1. STL中的所有组件都是由模板构成的, 所以其元素可以是任意型别的. 组件有:

      - 容器: 管理某类对象的集合. 不同的容器有各自的优缺点.

      - 迭代器: 用来在一个对象集群(Collection of Objects) 的元素上进行遍历. 这个CoB可以是容器/容器的一部分. 每种容器都提供了自己的迭代器.

      - 算法(Algorithm): 用来处理集群内的元素(比如: 查询,修改,排序等).

      - 适配器(adapter)

      - 仿函数(functors or function objects)

    2. STL基本观念是将数据和操作分离, 数据交给容器进行管理, 操作(算法)可以定制算法, 使用迭代器来提供两者间统一的接口.

      - STL 的概念有点儿和OOP的最初思想矛盾, 然而这个小框架提供了很好的容器/算法弹性.

      - STL 是泛型编程的出色范例, 容器和算法对任意型别和类别而已已经一般化了.

      - STL 提供了适配器和仿函数可以实现对算法的: 补充, 约束 和定制, 从而满足不同的需求.

    3. 容器

      - 序列式容器(Sequence container): 可序集群.(3个)  ---- vector/deque/list (为什么queue,stack 和 string不是呢?)

        - 可以将string 和 array 也当作是一种序列式容器(why?)

        - array 是C/C++语言核心所支持的一个型别(type), 而不是(class). 具有静态大小和动态大小. 但它也并不是STL容器. 因为没有类似size(),empty()等成员函数. 但是STL的设计又允许它调用STL算法. 当我们以static arrays作为初始化行时特别有用.

        - 没有必要直接编写dynamic array了, 因为可以用vector实现.

      - 关联式容器(Association container): 已序集群(4个). 排序和元素值,插入顺序无关. ---- set/multiset/map/multimap

        - 自动会对元素进行排序. 默认情况下是使用 operator < 进行比较.

        - 一般关联容器由二叉搜索树实现 , 各容器的主要差别在于元素的类型已经处理重复元素的方式.

        - set: 按内部元素的值进行排序, 不允许重复.

        - multiset: 和set相同, 但允许重复

        - map: key/values , 键不允许重复.

        - multimap: 和map一样, 但键允许重复.可以用来当做字典.

    4. 容器适配器

      - stack: FILO

      - queue: FIFO

      - priority_queue: 下一个出队的元素永远是具有最高优先级的元素  ( 默认比较是 operator < 所以数值越小,优先级越高? ).

    5. 迭代器(基本操作)

      - operator */++/==/!=/=

      - 每种容器都必须提供自己的内部类, 事实上每种容器都将其适配器定义为内部类.

      - 任何一种容器都有2种类别的迭代器

        - container::iterator

        - container::const_iterator

     6. 关联式容器的一些应用

      -  typedef set<int> IntSet;  /  typedef set<int, greater<int> >IntSet;  greater<> 是一个预先定义的仿函数.

      - 所有的关联容器都有一个insert()方法, 但是没有序列式容器的push_back(),push_front()方法 , 因为你没有权力指定新元素的位置.

      - map 允许使用  operator []  来安插元素. 而multimap不允许使用下标操作符(因为key可以重复哦).

      - 存取multimap或map的元素时, 必须用pair结构的first和second成员才能访问到具体key/value

     1 #include <iostream>
     2 #include <map>
     3 #include <string>
     4 using namespace std;
     5 int main(){
     6     typedef map<string,float> StringFloatMap;
     7     StringFloatMap coll;
     8     coll["VAT"] = 0.15;
     9     coll["pi"] = 3.14;
    10     coll["This is a string"] = 3.4;
    11     coll["NULL"] = 0;
    12     StringFloatMap::iterator it = coll.begin(); // map 是不能手动排序,但是并不是没有序
    13     for(;it!=coll.end();++it){ // 使用++it效率高于 it++
    14         cout<<it->first<<" : "<<it->second<<endl;
    15     }
    16     return 0;
    17 }
    View Code

    7. 迭代器分类(2种)

      - 双向迭代器(Bidirectional iterator): list/set/multiset/map/multiset提供的属于此类.

      - 随机存取迭代器(Random access iterator): vector/deque/string提供的属于此类. 随机访问迭代器可以支持  operator < 

    8. 算法

      - 不是容器的成员函数, 而是搭配迭代器使用的全局函数. 

      -  pos = min_element(coll.begin(),coll.end())   /   pos = max_element(coll.begin(),coll.end())  

      -  sort(coll.begin(),coll.end()[,comp]); 

      -  pos = find(coll.begin(),coll.end(),value); 

      -  reserve(pos,coll.end()) 

      - 处理多个区间

        -  equal(coll1.begin(),coll1.end(), coll2.begin() ); //必须设定第一个区间的起点和终点, 至于其他区间, 只需设置起点即可, 终点通常由第一区间的元素数量推断出来.  

        -  copy(coll1.begin(),coll1.end(),coll2.begin()); //处理多个区间时注意区间的大小, 否则可能会读写到其他地方造成错误,如果不是STL安全版本不会有异常. 

        - 可以使用resize()改变目标容器的大小, 适用于序列式容器.

    9. 迭代器适配器(Iterator Adapters)

      - 迭代器是接口, 任何类别(class)只要具备这个接口就可以实现迭代.  C++标准库提供了几个预定义的特殊迭代器, 即迭代器适配器(以下3种).

      - Insert Iterator: 可以使算法以插入而非覆写的方式运作. 插入的位置(最前/最后/特定位置), 根据3重不同的Insert Iterator而异.

        - back_inserter: copy(coll1.begin(),coll1.end(),back_inserter(coll2)); 

          - 只有在提供push_back()的容器中才能用. (vector/deque/list)

        - front_inserter:  copy(coll1.begin(),coll1.end(),front_inserter(coll3)); 

          - 容器要满足有push_front(). (deque/list)

        - inserter:  copy(coll1.begin(),coll1.end(),inserter(coll2,coll2.begin()); //只有inserter可以在关联容器上工作(非关联容器上应该也可以吧). 上面两种不行. 

          - 所有的STL容器都提供有insert(), 对于关联式容器而言, 提供一个开始搜寻的位置. 

      - Stream Interator: 一种用来读写流的迭代器, 提供了必要的抽象性, 使得来自键盘的输入像是个集群.

        -  copy(istream_iterator<string> (cin), istream_iterator<string>(), back_inserter(coll)); 

          - istream_iterator<string>(cin) : 会产生一个从标准输入流cin读取数据的stream Iterator,读取string类型, 每当算法处理下一个元素时, 就转化为:cin>>string

          - ostream_iterator<string>(): 调用istream iterator的default构造函数, 产生一个代表"流结束符"的迭代器. 

        -  unique_copy(coll.begin(),coll.end(),ostream_iterator<string>(cout," ")); 

          - 第二个参数是可选的元素分隔符.

      - Reverse Iterator:  提供逆向操作. 可以通过 rbegin()/rend()来产生逆向迭代器.

        -  copy(coll.rbegin(), coll.rend(), ostream_iterator<int>(cout," ")); 

        - 可以将一般的迭代器转换为逆向迭代器, 反之亦然.

    10. 更易型算法(manipulating algorithm)

      - remove(): 移除元素, 但是容器的size(),返回的end() 没有改变, 因为是用容器后面的元素覆盖了删除的元素.

      - remove()会返回删除元素后新的迭代器的位置, 而不改变原来容器迭代器的位置.  list<int>::iterator end = remove(coll.begin(),coll.end(),value); 

     1 #include <iostream>
     2 #include <map>
     3 #include <string>
     4 #include <iterator>
     5 #include <list>
     6 #include <algorithm>
     7 using namespace std;
     8 int main(){
     9     list<int> coll; //list提供双向迭代器, 是双向链表.
    10     for(int i=1;i<=6;++i){
    11         coll.push_front(i);
    12         coll.push_back(i);
    13     }
    14     copy(coll.begin(),coll.end(), ostream_iterator<int>(cout," "));
    15     cout<<endl;
    16     list<int>::iterator end = remove(coll.begin(),coll.end(),3);
    17     copy(coll.begin(),end,ostream_iterator<int>(cout," "));
    18     cout<<endl;
    19     cout<<distance(end,coll.end())<<endl;
    20     coll.erase(end,coll.end());
    21     copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
    22     cout<<endl;
    23     return 0;
    24 }
    View Code

       - 辅助函数 distance(), 返回迭代器之间的距离, 可以用于随机存取迭代器(还可以使用算术运算)和双向迭代器.

      -  coll.erase(end,coll.end()); 删除区间内的所有元素. 

      - 更易型算法不适用于关联式容器. 关联式的所有迭代器均被声明为指向常量. 更易关联式容器中的元素会产生编译错误.

      - 不能使用算法函数 remove() 来移除关联式容器的元素, 但是可以通过调用关联式容器的方法erase()移除元素,返回被删除元素个数.

    11. 算法函数和成员函数

      - 容器本身可能提供功能相似算法函数而性能更佳的成员函数, 成员函数更了解具体容器的具体需要, 因此应该优先考虑成员函数.

      - 有的容器操作, 使用成员函数和算法函数都可以. 但是成员函数性能更高.

    12. 自定义泛型函数

    13. 函数作为算法的参数

      - 算法函数:  for_each(coll.begin(),coll.end(), print) ;// print 是一个函数 

            std::transform(coll1.begin(),coll1.end(),std::back_inserter(coll2),square); //square 是一个函数 

              pos = find_if(coll.begin(),coll.end(), isPrime); 

      - 判断式

        - 判断式通常用来指定排序准则和搜索准则, 不允许改变参数的状态. 如 isPrime

        - 如果元素本身不支持 operator < ,那么一般会使用二元判断式(2个参数).

    14. 仿函数(function object: 函数对象)

      - 定义:  可以这么理解, 任何东西只要能像函数一样调用 , 就说它是个函数, 因此一般的对象如果重载了operator (), 那么就能像函数一样调用, 成为一个函数对象. 

      - 例子:

     1 #include <iostream>
     2 #include <map>
     3 #include <string>
     4 #include <iterator>
     5 #include <list>
     6 #include <algorithm>
     7 #include <vector>
     8 using namespace std;
     9 class PrintInt{
    10 public:
    11     void operator()(int elem) const{
    12         cout<<elem<<endl;
    13     }
    14 };
    15 int main(){
    16     vector<int> coll;
    17     for(int i=1;i<=9;++i){
    18         coll.push_back(i);
    19     }
    20     for_each(coll.begin(),coll.end(),PrintInt());
    21     cout<<endl;
    22     return 0;
    23 }
    View Code

      - 函数对象的优点:

        - 是智能型函数:

          - 函数对象有自己的类型, 可以拥有其他成员函数和成员变量, 意味着函数对象可以拥有状态. 

          - 可以在执行期间初始化它们.

        - 每个函数对象有自己的型别:

          - 一般函数只有当signature不同时才算型别不同, 而函数对象即使签名相同, 也可以有不同的类型.

          - 可以设计仿函数继承体系, 完成其他事情.

        - 仿函数比一办函数快

          - 对template而言 , 更多的细节在编译期就已确定, 所以运行更佳.

          - 例子

     1 #include <iostream>
     2 #include <iterator>
     3 #include <list>
     4 #include <algorithm>
     5 using namespace std;
     6 //function object that adds the value with witch it is initialized.
     7 class AddValue{
     8 private:
     9     int theValue;  // the value to add
    10 public:
    11     AddValue(int v):theValue(v){}
    12     void operator()(int& elem) const{
    13         elem += theValue;
    14     }
    15 };
    16 
    17 int main(){
    18     list<int> coll;
    19     for(int i=1;i<=9;++i){
    20         coll.push_back(i);
    21     }
    22     copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
    23     cout<<endl;
    24     for_each(coll.begin(),coll.end(),AddValue(10));
    25     copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
    26     cout<<endl;
    27     for_each(coll.begin(),coll.end(),AddValue(*coll.begin()));
    28     copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
    29     cout<<endl;
    30     return 0;
    31 }
    View Code

      - STL中预定义的仿函数

        -  less<int>() //默认的排序准则 

        -  negate<int>(); // 处理数值, 转换为相反值.   transform(coll.begin(),coll.end(),coll.begin(), negate<int>()); // 求相反数并回写. 

        -  multiplies<int>(); // 处理数值, 相乘   transform(coll.begin(),coll.end(),coll.begin(),coll.begin(),multiplies<int>()); // 3个集群相同, 求的是平方, 保存回去. 

        -  mem_fun_ref(&Person::save) //调用它所作用的元素的某个成员函数,参数可以是Person的派生类.    for_each(coll.begin(), coll.end(), mem_fun_ref(&Person::save));  

        - 仿函数和适配器结合使用, 更加灵活; 而且这样这些仿函数都是inline, 性能更佳.

     1 #include <iostream>
     2 #include <iterator>
     3 #include <set>
     4 #include <queue>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 int main(){
     9     // 可以在创建set的时候指定set内的排序规则.(?)
    10     set<int,greater<int> > coll1;  // 为什么不是 greater<int>()呢, greater不是一个类吗? 
    11     deque<int> coll2;
    12     for(int i=1;i<=9;++i)
    13         coll1.insert(i);
    14     copy(coll1.begin(),coll1.end(),ostream_iterator<int>(cout," "));
    15     cout<<endl;
    16     //使用适配器 bind2nd() 将预先定义的仿函数和其他数值组合在一起.
    17     // bind2nd会将10当成内部数值保存下来,当算法以实际集群元素为参数, 
    18     //调用bind2nd时, bind2nd会把该元素当成第一参数, 10当成第二参数,调用bind2nd的第一参数(仿函数).
    19     transform(coll1.begin(),coll1.end(),back_inserter(coll2),bind2nd(multiplies<int>(),10));//这里是multiplies<int>(),有括号呀?
    20     copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));
    21     cout<<endl;
    22     replace_if(coll2.begin(),coll2.end(),bind2nd(equal_to<int>(),70),42);
    23     copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));
    24     cout<<endl;
    25     coll2.erase(remove_if(coll2.begin(),coll2.end(), // range
    26         bind2nd(less<int>(),50)), // 删除标准
    27         coll2.end());
    28     copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));
    29     cout<<endl;
    30     return 0;
    31 }
    View Code
  • 相关阅读:
    uniGUI学习之ExtJS之xtype容器内创建元素的简便方法(52)
    uniGUI学习之ExtJS事件(51)
    uniGUI学习之自定义CSS之如何找控件属性(50)
    uniGUI学习之自定义CSS(49)
    CANoe CAPL 之 Checksum and Counter
    PYTHON3 之 IVI的CAN总线自动化测试
    CAP原则(CAP定理)、BASE理论
    iOS 项目运行pod install报错 could not find compatible versions
    Xcode 11.7 安装报Failed to find a suitable device for the type IBSimDeviceTypeiPad2x
    Flutter 异常捕获框架catcher
  • 原文地址:https://www.cnblogs.com/roger9567/p/4888770.html
Copyright © 2020-2023  润新知