zoukankan      html  css  js  c++  java
  • 【C++标准库】STL基础

    STL是C++标准库的核心,STL组件中最关键的是容器迭代器算法。容器是用来管理某类对象的集合;迭代器为所有各式各样的容器提供了一组共通的接口;算法用于处理集合内的元素。

    STL的基本概念是将数据和操作分离,数据由容器加以管理,操作则由可定制的算法定义,迭代器在二者之间充当粘合剂。

    容器

    • 序列式容器 array、vector、deque双端队列、list双向链表、forward_list单向链表
    • 关联式容器 set、multiset、map、multimap
    • 无序容器 unordered_set、unordered_multiset、unordered_map、unordered_multimap

    关联式容器是由二叉树实现出来,可以快速的找出一个具有某特定value的元素。set元素依据value自动排序,元素不允许重复;multiset元素依据value自动排序,元素允许重复;map每个元素都是key/value对,其中key为排序准则,key不允许重复;multimap每个元素都是key/value对,其中key为排序准则,key允许重复.

    #include "stdafx.h"
    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        multimap<int, string> coll;
        coll = {
            {5,"tagged"},{2,"a"},{1,"this"},{4,"of"},{6,"strings"},{1,"is"},{3,"multimap"}
        };
        for (const auto& elem : coll)
        {
            cout << elem.second << " ";   //--> this is a multimap of tagged strings
        }
        cout << endl;
        return 0;
    }

     无序容器常以hash table实现出来,无序容器的主要优点是,当你打算查找出一个某特定值的元素,其速度甚至可能快过关联式容器。

    容器适配器Container Adapter

    容器适配器是根据基本容器实现而成,用于满足特定的需求。包括stack、queue、priority queue

     迭代器Iterator

    迭代器是一个可遍历STL容器全部或者部分元素的对象。迭代器具有遍历复杂数据结构的能力,每一种容器都必须提供自己的迭代器,事实上每一种容器都将迭代器以嵌套的形式定义于class内部。因此各种迭代器的接口虽然相同,但其内部实现确各自不同

     所有容器类型都提供了一些基本的成员函数,使得可以取得迭代器并以之遍历容器元素。

    begin()  返回一个迭代器,指向容器第一个元素

    end()  返回一个迭代器,返回容器最后一个元素的下一个元素(尾后迭代器)

    空区间的begin()等于end()

    任何容器都定义有两种迭代器类型:

    • container::iterator 以“读写”模式遍历元素
    • container::const_iterator 以“只读”方式遍历元素

    自C++11起,容器提供了cbegin()和cend(),它们返回类型为container::const_iterator的对象。

     算法 Algorithm

    算法并非是容器的成员函数,而是一种搭配迭代器使用的全局函数。这样做的优势在于所有算法只需要实现一份,就可以对所有容器运作。为了操作容器元素的某个子集,需要将区间首尾作为参数传入算法,调用者需要确保指定的区间是有效的。所有算法处理的都是半开区间。

    min_element() 返回容器最小元素的位置

    max_element() 返回容器最大元素的位置

    sort() 排序

    find() 查找元素,查找成功则返回一个迭代器指向目标元素,查找失败则返回第二个实参指示的区间末端

    reverse() 将区间内元素反转

    有些算法需要处理多个区间,通常必须设定第一个区间的起点和终点,其他区间只需设定起点即可,终点通常可由第一个区间的元素数量推导出来。必须确保第二个(其他)区间的元素个数至少和第一个区间元素个数一样多。可以(1)确保目标区间内有足够元素,(2)使用插入迭代器

     迭代器之适配器 Iterator Adapter

    1. Insert Iterator 安插型迭代器

    Insert Iterator可以使算法以插入而非覆写的方式运作,促使目标区间的大小按照需要增长。有三种Insert Iterator:

     1 #include "stdafx.h"
     2 #include <iostream>
     3 #include <list>
     4 #include <string>
     5 #include <vector>
     6 #include <set>
     7 #include <deque>
     8 #include <iterator>
     9 #include <algorithm>
    10 using namespace std;
    11 
    12 int main()
    13 {
    14     list<int> coll1 = { 1,2,3,4,5,6,7,8,9 };
    15     //copy elements by appending them
    16     vector<int> coll2;
    17     copy(coll1.cbegin(), coll1.cend(), back_inserter(coll2));
    18     for (auto elem:coll2)
    19     {
    20         cout << elem << " ";
    21     }
    22     cout << endl;
    23     //copy elements by inserting them at the front
    24     deque<int> coll3;
    25     copy(coll1.cbegin(), coll1.cend(), front_inserter(coll3));
    26     for (auto elem : coll3)
    27     {
    28         cout << elem << " ";
    29     }
    30     cout << endl;
    31     //works for associative collections
    32     set<int> coll4;
    33     copy(coll1.cbegin(), coll1.cend(), inserter(coll4, coll4.begin()));
    34     for (auto elem : coll4)
    35     {
    36         cout << elem << " ";
    37     }
    38     cout << endl;
    39     return 0;
    40 }

     back_inserter 安插于容器最末端,其内部是调用push_back()

    front_inserter 安插于容器最前端,其内部调用push_front()

    inserter 内部调用insert(),在“初始化时接收的第二个实参位置的前方插入元素”

     2. Stream Iterator 串流迭代器

    3. Reverse Iterator 反向迭代器

    所有提供双向或者随机访问迭代器的容器(即forward_list之外的所有序列式容器和所有关联容器)都可以通过其成员函数rbegin()和rend()产生一个反向迭代器,通过crbegin()和crend()产生只读反向迭代器。

    #include "stdafx.h"
    #include <iostream>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    using namespace std;
    
    int main()
    {
        vector<int> coll;
        for (int i = 1;i <= 9;++i)
        {
            coll.push_back(i);
        }
        copy(coll.crbegin(), coll.crend(), ostream_iterator<int>(cout, " "));  //9 8 7 6 5 4 3 2 1
        cout << endl;
        return 0;
    }
    View Code

     4. Move Iterator 搬移迭代器

    函数作为算法的实参

    有些算法可以接受用户自定义的函数作为实参,以提高算法的弹性和能力。

     1 #include "stdafx.h"
     2 #include <iostream>
     3 #include <vector>
     4 #include <iterator>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 void print(int elem)
     9 {
    10     std::cout << elem << " ";
    11 }
    12 int main()
    13 {
    14     vector<int> coll;
    15     for (int i=1;i<=9;++i)
    16     {
    17         coll.push_back(i);
    18     }
    19     //print all elements
    20     for_each(coll.cbegin(), coll.cend(), print);  //1 2 3 4 5 6 7 8 9
    21     cout << endl;
    22     return 0;
    23 }
    View Code

    使用判断式 Predicate

    predicate是一种特殊的辅助函数,其返回bool值,常被用于指定作为排序准则或者查找准则。

    Lambda表达式

    Lambda表达式完整声明格式如下:

    [capture list] (params list) mutable exception-> return type { function body }

    其中:

    1. capture list:捕获外部变量列表
    2. params list:形参列表
    3. mutable指示符:用来说用是否可以修改捕获的变量
    4. exception:异常设定
    5. return type:返回类型
    6. function body:函数体
    #include "stdafx.h"
    #include <iostream>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;
    
    
    int main()
    {
        vector<int> coll = { 3,2,5,4,1,8};
        sort(coll.begin(), coll.end(), [](int a, int b)->bool {return a < b;});
        for (auto elem : coll)
        {
            cout << elem << " ";  //1 2 3 4 5 8
        }
        cout << endl;
        return 0;
    }
    View Code

     函数对象Function Object(仿函数functor)

     1 #include "stdafx.h"
     2 #include <iostream>
     3 #include <vector>
     4 #include <string>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 class PrintInt
     9 {
    10 public:
    11     void operator()(int elem) const //使用operator()定义函数对象
    12     {
    13         std::cout << elem << " ";
    14     }
    15 };
    16 int main()
    17 {
    18     vector<int> coll;
    19     for (int i = 1;i <= 9;++i)
    20     {
    21         coll.push_back(i);
    22     }
    23     for_each(coll.cbegin(), coll.cend(), PrintInt()); //1 2 3 4 5 6 7 8 9
    24     cout << endl;
    25     return 0;
    26 }

     C++标准库内有若干预定义的函数对象,涵盖了许多基础运算。定义于头文件functional中。

    #include "stdafx.h"
    #include <iostream>
    #include <deque>
    #include <string>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    int main()
    {
        deque<int> coll = { 1,2,3,5,7,11,13,17,19 };
        for (auto elem : coll) { cout << elem << " "; }
        cout << endl;
        transform(coll.cbegin(), coll.cend(), coll.begin(), negate<int>());
        for (auto elem : coll) { cout << elem << " "; }
        cout << endl;
        //square elements in coll
        transform(coll.cbegin(), coll.cend(), //first source
            coll.cbegin(), //second source
            coll.begin(),  //destination
            multiplies<int>()); //operation
        for (auto elem : coll) { cout << elem << " "; }
        cout << endl;
        return 0;
    }
    View Code

     Binder 将预定义的函数对象和其他数值结合为一体。

    #include "stdafx.h"
    #include <iostream>
    #include <set>
    #include <deque>
    #include <iterator>
    #include <algorithm>
    #include <functional>
    using namespace std;
    using namespace std::placeholders; //占位符
    int main()
    {
        set<int, greater<int>> coll1 = { 1,2,3,4,5,6,7,8,9 };
        deque<int> coll2;
        for (auto elem : coll1) { cout << elem << " "; } //9 8 7 6 5 4 3 2 1
        cout << endl;
        //transform elements to coll2 by multiplying with 10
        transform(coll1.cbegin(), coll1.cend(), back_inserter(coll2), bind(multiplies<int>(), _1, 10));  // _1占位符
        for (auto elem : coll2) { cout << elem << " "; } //90 80 70 60 50 40 30 20 10
        cout << endl;
        //replace 70 with 42
        replace_if(coll2.begin(), coll2.end(), bind(equal_to<int>(), _1, 70), 42);
        for (auto elem : coll2) { cout << elem << " "; } //90 80 42 60 50 40 30 20 10
        cout << endl;
        return 0;
    }
    View Code

    bind()将低层的函数对象和占位符合成高层的函数对象,占位符为“带有前缀下划线”的数值标识符。

    bind(multiplies<int>(),_1,10) 便定义出一个函数对象,将第一个实参乘以10

  • 相关阅读:
    java的final变量理解
    springMVC如何判断入参是默认参数还是请求传过来的参数?
    java反射新的应用
    冒烟测试和回归测试的区别
    git变基、冲突解决
    mockServer学习
    mongodb查询之模糊查询
    springxml配置构造函数入参
    mockito学习
    solr官方文档翻译系列之schema.xml配置介绍
  • 原文地址:https://www.cnblogs.com/larry-xia/p/9325882.html
Copyright © 2011-2022 走看看