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

  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/larry-xia/p/9325882.html
Copyright © 2011-2022 走看看