【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

原文地址:https://www.cnblogs.com/larry-xia/p/9325882.html