侯捷STL课程及源码剖析学习1

1.C++标准库和STL

  C++标准库以header files形式呈现:

  1. C++标准库的header files不带后缀名(.h),例如#include <vector>
  2. 新式C header files 不带后缀名.h,例如#include<cstdio>
  3. 旧式C header files (带有后缀名.h)仍然可用,例如#include <stdio.h>
  4. 新式headers内的组件封装于namespace “std”。     using namespace std;或者以 using std::cout;的形式
  5. 旧式headers 内的组件不封装于namespace "std"

  在标准库中,标准模板库STL(Standard Template Library),占据了标准库70%,80%以上的内容。

C++ 标准库的范围大于STL的范围。STL的核心思想是泛型编程(Generic Programming)。

重要资源:

网站:

书籍:

  • The C++ standard Library second edition;
  • STL 源码剖析

2.STL 六大组件

STL分为六大组件:

  • 容器(container):常用数据结构,大致分为两类,序列容器,如vector,list,deque,关联容器,如set,map。在实现上,是类模板(class template)
  • 迭代器(iterator):一套访问容器的接口,行为类似于指针。它为不同算法提供的相对统一的容器访问方式,使得设计算法时无需关注过多关注数据。(“算法”指广义的算法,操作数据的逻辑代码都可认为是算法)
  • 算法(algorithm):提供一套常用的算法,如sort,search,copy,erase … 在实现上,可以认为是一种函数模板(function template)。
  • 配置器(allocator):为容器提供空间配置和释放,对象构造和析构的服务,也是一个class template。
  • 仿函数(functor):作为函数使用的对象,用于泛化算法中的操作。
  • 配接器(adapter):将一种容器修饰为功能不同的另一种容器,如以容器vector为基础,在其上实现stack,stack的行为也是一种容器。这就是一种配接器。除此之外,还有迭代器配接器和仿函数配接器。

image

STL 六大组件的交互关系

  • Container 通过 Allocator 取得数据储存空间
  • Algorithm 通过 Iterator 存取 Container 内容
  • Functor 可以协助 Algorithm 完成不同的策略变化
  • Adapter 可以修饰或套接 FunctorIterator
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>

using namespace std;

int main()
{
    int ia[6] = { 27, 210, 12, 47, 109, 83 };
        vector<int, allocator<int>> vi(ia, ia + 6);

    cout << count_if(vi.begin(), vi.end(),
        not1(bind2nd(less<int>(), 40)));

    return 0;
}

上述这段代码用到了STL的六大部件:

allocator 是分配器,vector 是容器,count_if 是算法

vi.begin() 是迭代器

not1,bind2nd是适配器

less<int> 是仿函数

  • 理解容器的前闭后开的设计。迭代器类似于指针,很多操作和指针差不多++,--运算。vec.begin(),vec.end()指向容器最后一个元素的下一个位置,解引用*(vec.end())错误!
  • auto关键字的应用

 c++知识点

临时对象

 1 //临时对象的产生与运用
 2 #include <vector>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 template <typename T>
 8 class print
 9 {
10 public:
11   void operator()(const T& elem) // operator()重载
12   {
13     cout<<elem<<' ';
14   }
15 };
16 
17 int main()
18 {
19     int ia[6] = {0,1,2,3,4,5};
20     vector<int> iv(ia, ia+6);
21 
22     // print<int>() 是一个临时对象,不是函数调用
23     for_each(iv.begin(), iv.end(), print<int>());
24 
25     cout<<endl;
26 
27   return 1;
28 }
temp obj

静态整数成员变量

 1 //静态常量整数初始化
 2 #include <iostream>
 3 using namespace std;
 4 
 5 template <typename T>
 6 class testClass
 7 {
 8 
 9 public:
10 
11     static const int _datai = 5;
12     static const long _datal = 3L;
13     static const char _datac = 'c';
14 };
15 
16 int main()
17 {
18     cout<<testClass<int>::_datai<<endl;
19     cout<<testClass<long>::_datal<<endl;
20     cout<<testClass<char>::_datac<<endl;
21 
22     return 0;
23 }
static constant

重载自增、自减、操作符

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class INT
 5 {
 6     friend ostream& operator<<(ostream& os, const INT& i);
 7 
 8 public:
 9     INT(int i) : m_i(i) { };
10 
11     //  prefix : increment and then fetch
12     //  ++INT
13     INT& operator++()
14     {
15         ++(this->m_i);
16         return *this;
17     }
18 
19     //  postfix : fetch and then increment
20     //  INT++
21     const INT operator++(int)
22     {
23         INT temp = *this;
24         ++(*this);
25         return temp;
26     }
27 
28     //  prefix  :   decrement and then fetch
29     //  --INT
30     INT& operator--()
31     {
32         --(this->m_i);
33         return *this;
34     }
35 
36     //  prefix  :   fetch and then decrement
37     const INT operator--(int)
38     {
39         INT temp = *this;
40         --(*this);
41         return temp;
42     }
43 
44     int& operator*() const
45     {
46         return (int&)m_i;
47     }
48 
49 private:
50     int m_i;
51 };
52 
53 ostream& operator<<(ostream& os, const INT& i)
54 {
55     os <<'[' <<i.m_i <<']';
56     return os;
57 }
58 
59 int main()
60 {
61     INT I(5);
62     cout <<I++ <<endl;
63     cout <<++I <<endl;
64     cout <<I-- <<endl;
65     cout <<--I <<endl;
66     cout <<*I <<endl;
67 
68   return 1;
69 }
View Code

operator() 重载

 1 #include <cstdlib>
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 int fcmp(const void *elem1, const void *elem2);
 7 
 8 int main( )
 9 {
10     int ia[] = {32, 92, 67, 58, 10, 4, 25, 52, 59, 54};
11 
12     for(int i = 0; i < 10; i++)
13     {
14         cout <<ia[i] <<" ";
15     }
16     cout <<endl;
17 
18     qsort(ia, sizeof(ia)/sizeof(ia[0]), sizeof(ia[0]), fcmp);
19 
20 
21     for(int i = 0; i < 10; i++)
22     {
23         cout <<ia[i] <<" ";
24     }
25     cout <<endl;
26 
27 }
28 
29 int fcmp(const void *elem1, const void *elem2)
30 {
31     const int *i1 = (const int *)elem1;
32     const int *i2 = (const int *)elem2;
33 
34     return (*i1 - *i2);
35 }
qsort

仿函数,函数对象

 1 #include <iostream>
 2 using namespace std;
 3 
 4 //  由于将operator()重载了, 因此plus成了一个仿函数
 5 template <class T>
 6 struct myplus
 7 {
 8     T operator()(const T& x, const T& y) const
 9     {
10         return x + y;
11     }
12 };
13 
14 //  由于将operator()重载了, 因此minus成了一个仿函数
15 
16 template <class T>
17 struct myminus
18 {
19     T operator()(const T& x, const T& y) const
20     {
21         return x - y;
22     }
23 };
24 
25 int main()
26 {
27     //  创建仿函数对象
28     myplus<int> plusobj;
29     myminus<int> minusobj;
30 
31     cout<<plusobj(3,5)<<endl;
32     cout<<minusobj(3,5)<<endl;
33 
34     cout<<myplus<int>()(43,50)<<endl;
35     cout<<myminus<int>()(43,50)<<endl;
36 
37     return 1;
38 }
functor

3.容器的相关知识

3.1容器的结构与分类

容器按在内存中的存储结构分为三种:顺序容器(Sequence Container)、关联容器(Associative Container)、和无序容器(Unordered Container)。其中的无序容器是C++ 11提出的,实际上无序容器也属于关联容器,使用哈希表构成。

  • Array数组容器,大小固定的
  • Deque:两段都可以进行插入删除操作,但是从内存上讲不通,怎么实现的要从后面的学习知道。
  • List:是一个双向的循环链表,注意是双向的。
  • Forward-List:单向链表,当能用单向链表的时候尽量用,可以减少内存空间,一个指针在32位pc上占4个字节,当数据量很多上百万,不可忽略!
  • Set键值都一样,MultiSet允许元素有重复。
  • Set/Map用红黑树实现,RB-tree是自平衡的二叉树。
  • Unorder Containers:是C++标准库里卖的内容。
  • 根据这些图例,可以知道这些容器在内存用到的数据结构是什么样的。
  • HashTable实现方法很多,但基本都用Separate Chaining(分离链地址法实现)。

容器测试辅助函数 

 1 using std::cin;
 2 using std::cout;
 3 using std::string;
 4 
 5 long get_a_target_long()
 6 {
 7     long target = 0;
 8 
 9     cout << "target (0~" << RAND_MAX << "): ";
10     cin >> target;
11     return target;
12 }
13 
14 string get_a_target_string()
15 {
16     long target = 0;
17     char buf[10];
18 
19     cout << "target (0~" << RAND_MAX << "): ";
20     cin >> target;
21     snprintf(buf, 10, "%d", target);
22     return string(buf);
23 }
24 
25 int compareLongs(const void* a, const void* b)
26 {
27     return (*(long*)a - *(long*)b);
28 }
29 
30 int compareStrings(const void* a, const void* b)
31 {
32     if (*(string*)a > *(string*)b)
33         return 1;
34     else if (*(string*)a < *(string*)b)
35         return -1;
36     else
37         return 0;
38 }
View Code

 注:Windows环境下 应使用函数:_snprintf(buf, 10, "%d", target);

3.2顺序容器

顺序容器:它将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素。

标准库提供了一下几种顺序容器:array、vector、list、forward_list、slist、deque、stack和queue,他们的差别在于访问元素访问元素的方式,以及添加或删除元素相关操作的运行代价。array是C++11的新内容,功能比内置数组更加强大,可以以对象为单位存储数据,vector支持快速随机访问,list支持快速插入/删除,deque是一个双端队列,queue和stack在STL中都是基于deque来实现。

顺序容器类型

vector

  • 可变大小数组;
  • 支持快速随机访问;
  • 在尾部之外的位置插入或删除元素可能很慢;       

deque

  • 双端队列;
  • 支持快速随机访问;
  • 在头尾位置插入/删除速度很快;

list

  • 双向链表;
  • 只支持双向顺序访问;
  • 在list中任何位置进行插入/删除操作速度都很快;

forward_list

  • 单向链表;
  • 只支持单向顺序访问;
  • 在链表任何位置进行插入/删除操作速度都很快;

array

  • 固定大小数组;
  • 支持快速随机访问;
  • 不能添加或删除元素;

string

  • 与vector相似的容器,但专门用于保存字符;
  • 随机访问快;
  • 在尾部插入/删除速度快;
  • array 测试代码
 1 #include <array>
 2 #include <iostream>
 3 #include <ctime> 
 4 #include <cstdlib> //qsort, bsearch, NULL
 5 #include <cstdio>  
 6 namespace jj01
 7 {
 8     void test_array()
 9     {
10         cout << "
test_array().......... 
";
11  
12         array<long, ASIZE> c;
13  
14         clock_t timeStart = clock();
15         for (long i = 0; i< ASIZE; ++i) {
16             c[i] = rand();
17         }
18         cout << "milli-seconds : " << (clock() - timeStart) << endl;  //
19         cout << "array.size()= " << c.size() << endl;
20         cout << "array.front()= " << c.front() << endl;
21         cout << "array.back()= " << c.back() << endl;
22         cout << "array.data()= " << c.data() << endl;
23  
24         long target = get_a_target_long();
25  
26         timeStart = clock();
27         ::qsort(c.data(), ASIZE, sizeof(long), compareLongs);
28         long* pItem = (long*)::bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
29         cout << "qsort()+bsearch(), milli-seconds : " << (clock() - timeStart) << endl;   //    
30         if (pItem != NULL)
31             cout << "found, " << *pItem << endl;
32         else
33             cout << "not found! " << endl;
34     }
35 }
array

  注:array 为c++11 新增容器,档测试数据 ASIZE 较大时,在vs2013运行时报出堆栈溢出错误,需要在工程属性中更改堆栈默认大小(默认为1M)。

测试结果

test_array()..........
milli-seconds : 32
array.size()= 500000
array.front()= 41
array.back()= 29794
array.data()= 0x47970
target (0~32767): 123
qsort()+bsearch(), milli-seconds : 263
found, 123
View Code
  • vector 测试
 1 #include <vector>
 2 #include <stdexcept>
 3 #include <string>
 4 #include <cstdlib> //abort()
 5 #include <cstdio>  //snprintf()
 6 #include <iostream>
 7 #include <ctime> 
 8 #include <algorithm>     //sort()
 9 namespace jj02
10 {
11     void test_vector(long& value)
12     {
13         cout << "
test_vector().......... 
";
14 
15         vector<string> c;
16         char buf[10];
17 
18         clock_t timeStart = clock();
19         for (long i = 0; i< value; ++i)
20         {
21             try {
22                 snprintf(buf, 10, "%d", rand());
23                 c.push_back(string(buf));
24             }
25             catch (exception& p) {
26                 cout << "i=" << i << " " << p.what() << endl;
27                 //曾经最高 i=58389486 then std::bad_alloc
28                 abort();
29             }
30         }
31         cout << "milli-seconds : " << (clock() - timeStart) << endl;
32         cout << "vector.max_size()= " << c.max_size() << endl;    //1073747823
33         cout << "vector.size()= " << c.size() << endl;
34         cout << "vector.front()= " << c.front() << endl;
35         cout << "vector.back()= " << c.back() << endl;
36         cout << "vector.data()= " << c.data() << endl;
37         cout << "vector.capacity()= " << c.capacity() << endl << endl;
38 
39 
40         string target = get_a_target_string();
41         {
42             timeStart = clock();
43             auto pItem = find(c.begin(), c.end(), target);
44             cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
45 
46             if (pItem != c.end())
47                 cout << "found, " << *pItem << endl << endl;
48             else
49                 cout << "not found! " << endl << endl;
50         }
51 
52         {
53             timeStart = clock();
54             sort(c.begin(), c.end());
55             cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl;
56 
57             timeStart = clock();
58             string* pItem = (string*)::bsearch(&target, (c.data()),
59                 c.size(), sizeof(string), compareStrings);
60             cout << "bsearch(), milli-seconds : " << (clock() - timeStart) << endl;
61 
62             if (pItem != NULL)
63                 cout << "found, " << *pItem << endl << endl;
64             else
65                 cout << "not found! " << endl << endl;
66         }
67 
68         c.clear();
69         test_moveable(vector<MyString>(), vector<MyStrNoMove>(), value);
70     }
71 }
vector

 ::find()模板函数,加冒号表明是全局函数,当没有冒号时,编译器在当前没有找到,到全局去找。

测试结果

how many elements: 1000000

test_vector()................
milli-seconds : 750
vetor.max_size() = 576460752303423487
vector.size() = 1000000
vector.front() = 41
vetor.back() = 12679
vector.data() = 0x42c0040
vector.capacity()= 1048576

target (0~32767): 23456
std::find(),milli-seconds : 5
find , 23456

sort(), milli-seconds : 6069
bsearch(), milli-seconds : 1
found, 23456
View Code
  • list 测试
 1 #include <list>
 2 #include <stdexcept>
 3 #include <string>
 4 #include <cstdlib> //abort()
 5 #include <cstdio>  //snprintf()
 6 #include <algorithm> //find()
 7 #include <iostream>
 8 #include <ctime> 
 9 namespace jj03
10 {
11     void test_list(long& value)
12     {
13         cout << "
test_list().......... 
";
14 
15         list<string> c;
16         char buf[10];
17         
18         clock_t timeStart = clock();
19         for (long i = 0; i< value; ++i)
20         {
21             try {
22                 snprintf(buf, 10, "%d", rand());
23                 c.push_back(string(buf));                
24             }
25             catch (exception& p) {
26                 cout << "i=" << i << " " << p.what() << endl;
27                 abort();
28             }
29         }
30         cout << "milli-seconds : " << (clock() - timeStart) << endl;
31         cout << "list.size()= " << c.size() << endl;
32         cout << "list.max_size()= " << c.max_size() << endl;    //357913941
33         cout << "list.front()= " << c.front() << endl;
34         cout << "list.back()= " << c.back() << endl;
35 
36         string target = get_a_target_string();
37         timeStart = clock();
38         auto pItem = find(c.begin(), c.end(), target);
39         cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
40 
41         if (pItem != c.end())
42             cout << "found, " << *pItem << endl;
43         else
44             cout << "not found! " << endl;
45 
46         timeStart = clock();
47         c.sort();
48         cout << "c.sort(), milli-seconds : " << (clock() - timeStart) << endl;
49         
50     }
51 }
list

 测试结果

test_list()..........
milli-seconds : 496
list.size()= 1000000
list.max_size()= 38430716820228232
list.front()= 21384
list.back()= 1461
target (0~32767): 23456
std::find(), milli-seconds : 1
found, 23456
c.sort(), milli-seconds : 4701
View Code
  • forward_list 测试 
 1 #include <forward_list>
 2 #include <stdexcept>
 3 #include <string>
 4 #include <cstdlib> //abort()
 5 #include <cstdio>  //snprintf()
 6 #include <iostream>
 7 #include <ctime> 
 8 namespace jj04
 9 {
10     void test_forward_list(long& value)
11     {
12         cout << "
test_forward_list().......... 
";
13 
14         forward_list<string> c;
15         char buf[10];
16 
17         clock_t timeStart = clock();
18         for (long i = 0; i< value; ++i)
19         {
20             try {
21                 snprintf(buf, 10, "%d", rand());
22                 c.push_front(string(buf));
23             }
24             catch (exception& p) {
25                 cout << "i=" << i << " " << p.what() << endl;
26                 abort();
27             }
28         }
29         cout << "milli-seconds : " << (clock() - timeStart) << endl;
30         cout << "forward_list.max_size()= " << c.max_size() << endl;  //536870911
31         cout << "forward_list.front()= " << c.front() << endl;
32 
33 
34         string target = get_a_target_string();
35         timeStart = clock();
36         auto pItem = find(c.begin(), c.end(), target);
37         cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
38 
39         if (pItem != c.end())
40             cout << "found, " << *pItem << endl;
41         else
42             cout << "not found! " << endl;
43 
44         timeStart = clock();
45         c.sort();
46         cout << "c.sort(), milli-seconds : " << (clock() - timeStart) << endl;
47 
48         c.clear();
49     }
50 }
forward_list

 测试结果

how many elements: 1000000

test_forward_list()..........
milli-seconds : 701
forward_list.max_size()= 461168601842738790
forward_list.front()= 12679
target (0~32767): 23456
std::find(), milli-seconds : 4
found, 23456
c.sort(), milli-seconds : 5310
View Code
  • slist 测试 (非c++标准) 

Gnu C之前的单链表,forward-list是C++11才出现的

#include<extslist>头文件

 1 #include <extslist>
 2 //注意, 上一行并没有引发警告讯息如 #include <exthash_set> 所引发者: 
 3 //...4.9.2includec++ackwardackward_warning.h    
 4 //[Warning] ...
 5 
 6 #include <stdexcept>
 7 #include <string>
 8 #include <cstdlib> //abort()
 9 #include <cstdio>  //snprintf()
10 #include <iostream>
11 #include <ctime> 
12 namespace jj10
13 {
14     void test_slist(long& value)
15     {
16         cout << "
test_slist().......... 
";
17 
18         __gnu_cxx::slist<string> c;
19         char buf[10];
20 
21         clock_t timeStart = clock();
22         for (long i = 0; i< value; ++i)
23         {
24             try {
25                 snprintf(buf, 10, "%d", rand());
26                 c.push_front(string(buf));
27             }
28             catch (exception& p) {
29                 cout << "i=" << i << " " << p.what() << endl;
30                 abort();
31             }
32         }
33         cout << "milli-seconds : " << (clock() - timeStart) << endl;
34     }
35 }
slist
  •  deque 测试 
 1 #include <deque>
 2 #include <stdexcept>
 3 #include <string>
 4 #include <cstdlib> //abort()
 5 #include <cstdio>  //snprintf()
 6 #include <iostream>
 7 #include <ctime> 
 8 namespace jj05
 9 {
10     void test_deque(long& value)
11     {
12         cout << "
test_deque().......... 
";
13 
14         deque<string> c;
15         char buf[10];
16 
17         clock_t timeStart = clock();
18         for (long i = 0; i< value; ++i)
19         {
20             try {
21                 snprintf(buf, 10, "%d", rand());
22                 c.push_back(string(buf));
23             }
24             catch (exception& p) {
25                 cout << "i=" << i << " " << p.what() << endl;
26                 abort();
27             }
28         }
29         cout << "milli-seconds : " << (clock() - timeStart) << endl;
30         cout << "deque.size()= " << c.size() << endl;
31         cout << "deque.front()= " << c.front() << endl;
32         cout << "deque.back()= " << c.back() << endl;
33         cout << "deque.max_size()= " << c.max_size() << endl;    //1073741821    
34 
35         string target = get_a_target_string();
36         timeStart = clock();
37         auto pItem = find(c.begin(), c.end(), target);
38         cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
39 
40         if (pItem != c.end())
41             cout << "found, " << *pItem << endl;
42         else
43             cout << "not found! " << endl;
44 
45         timeStart = clock();
46         sort(c.begin(), c.end());
47         cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl;
48 
49         c.clear();
50         test_moveable(deque<MyString>(), deque<MyStrNoMove>(), value);
51     }
52 }
deque

 测试结果

how many elements: 100000

test_deque()..........
milli-seconds : 49
deque.size()= 100000
deque.front()= 41
deque.back()= 1629
deque.max_size()= 576460752303423487
target (0~32767): 3456
std::find(), milli-seconds : 9
found, 3456
sort(), milli-seconds : 668
View Code
  • stack 测试 
 1 #include <stack>
 2 #include <stdexcept>
 3 #include <string>
 4 #include <cstdlib> //abort()
 5 #include <cstdio>  //snprintf()
 6 #include <iostream>
 7 #include <ctime> 
 8 namespace jj17
 9 {
10     void test_stack(long& value)
11     {
12         cout << "
test_stack().......... 
";
13 
14         stack<string> c;
15         char buf[10];
16 
17         clock_t timeStart = clock();
18         for (long i = 0; i< value; ++i)
19         {
20             try {
21                 snprintf(buf, 10, "%d", rand());
22                 c.push(string(buf));
23             }
24             catch (exception& p) {
25                 cout << "i=" << i << " " << p.what() << endl;
26                 abort();
27             }
28         }
29         cout << "milli-seconds : " << (clock() - timeStart) << endl;
30         cout << "stack.size()= " << c.size() << endl;
31         cout << "stack.top()= " << c.top() << endl;
32         c.pop();
33         cout << "stack.size()= " << c.size() << endl;
34         cout << "stack.top()= " << c.top() << endl;
35 
36 
37         {
38             stack<string, list<string>> c;        //以 list 为底层 
39             for (long i = 0; i< 10; ++i) {
40                 snprintf(buf, 10, "%d", rand());
41                 c.push(string(buf));
42             }
43             cout << "stack.size()= " << c.size() << endl;
44             cout << "stack.top()= " << c.top() << endl;
45             c.pop();
46             cout << "stack.size()= " << c.size() << endl;
47             cout << "stack.top()= " << c.top() << endl;
48         }
49 
50         {
51             stack<string, vector<string>> c;    //以 vector 为底层 
52             for (long i = 0; i< 10; ++i) {
53                 snprintf(buf, 10, "%d", rand());
54                 c.push(string(buf));
55             }
56             cout << "stack.size()= " << c.size() << endl;
57             cout << "stack.top()= " << c.top() << endl;
58             c.pop();
59             cout << "stack.size()= " << c.size() << endl;
60             cout << "stack.top()= " << c.top() << endl;
61         }
62 
63         {
64             stack<string, set<string>> c;    //以 set 为底层 
65             /*!
66             for(long i=0; i< 10; ++i) {
67             snprintf(buf, 10, "%d", rand());
68             c.push(string(buf));
69             }
70             cout << "stack.size()= " << c.size() << endl;
71             cout << "stack.top()= " << c.top() << endl;
72             c.pop();
73             cout << "stack.size()= " << c.size() << endl;
74             cout << "stack.top()= " << c.top() << endl;
75 
76             //[Error] 'class std::set<std::basic_string<char> >' has no member named 'push_back'
77             //[Error] 'class std::set<std::basic_string<char> >' has no member named 'back'
78             //[Error] 'class std::set<std::basic_string<char> >' has no member named 'pop_back'
79             */
80         }
81 
82         //!stack<string, map(string>> c5;    ////以 map 为底层, [Error] template argument 2 is invalid
83         //!stack<string>::iterator ite1;      //[Error] 'iterator' is not a member of 'std::stack<std::basic_string<char> >'
84 
85     }
86 }
stack
  •  queue 测试 
 1 #include <queue>
 2 #include <stdexcept>
 3 #include <string>
 4 #include <cstdlib> //abort()
 5 #include <cstdio>  //snprintf()
 6 #include <iostream>
 7 #include <ctime> 
 8 namespace jj18
 9 {
10     void test_queue(long& value)
11     {
12         cout << "
test_queue().......... 
";
13 
14         queue<string> c;
15         char buf[10];
16 
17         clock_t timeStart = clock();
18         for (long i = 0; i< value; ++i)
19         {
20             try {
21                 snprintf(buf, 10, "%d", rand());
22                 c.push(string(buf));
23             }
24             catch (exception& p) {
25                 cout << "i=" << i << " " << p.what() << endl;
26                 abort();
27             }
28         }
29         cout << "milli-seconds : " << (clock() - timeStart) << endl;
30         cout << "queue.size()= " << c.size() << endl;
31         cout << "queue.front()= " << c.front() << endl;
32         cout << "queue.back()= " << c.back() << endl;
33         c.pop();
34         cout << "queue.size()= " << c.size() << endl;
35         cout << "queue.front()= " << c.front() << endl;
36         cout << "queue.back()= " << c.back() << endl;
37 
38 
39         {
40             queue<string, list<string>> c;        //以 list 为底层 
41             for (long i = 0; i< 10; ++i) {
42                 snprintf(buf, 10, "%d", rand());
43                 c.push(string(buf));
44             }
45             cout << "queue.size()= " << c.size() << endl;
46             cout << "queue.front()= " << c.front() << endl;
47             cout << "queue.back()= " << c.back() << endl;
48             c.pop();
49             cout << "queue.size()= " << c.size() << endl;
50             cout << "queue.front()= " << c.front() << endl;
51             cout << "queue.back()= " << c.back() << endl;
52         }
53 
54         {
55             queue<string, vector<string>> c;    //以 vector 为底层 
56             for (long i = 0; i< 10; ++i) {
57                 snprintf(buf, 10, "%d", rand());
58                 c.push(string(buf));
59             }
60             cout << "queue.size()= " << c.size() << endl;
61             cout << "queue.front()= " << c.front() << endl;
62             cout << "queue.back()= " << c.back() << endl;
63             //!c.pop();  //[Error] 'class std::vector<std::basic_string<char> >' has no member named 'pop_front'
64             cout << "queue.size()= " << c.size() << endl;
65             cout << "queue.front()= " << c.front() << endl;
66             cout << "queue.back()= " << c.back() << endl;
67         }
68 
69         {
70             queue<string, set<string>> c;        //以 set 为底层 
71             /*!
72             for(long i=0; i< 10; ++i) {
73             snprintf(buf, 10, "%d", rand());
74             c.push(string(buf));
75             }
76             cout << "queue.size()= " << c.size() << endl;
77             cout << "queue.front()= " << c.front() << endl;
78             cout << "queue.back()= " << c.back() << endl;
79             c.pop();
80             cout << "queue.size()= " << c.size() << endl;
81             cout << "queue.front()= " << c.front() << endl;
82             cout << "queue.back()= " << c.back() << endl;
83             //[Error] 'class std::set<std::basic_string<char> >' has no member named 'push_back'
84             //[Error] 'class std::set<std::basic_string<char> >' has no member named 'front'
85             //[Error] 'class std::set<std::basic_string<char> >' has no member named 'pop_front'
86             */
87         }
88 
89         //! queue<string, map<string>> c5;    //以 map 为底层, [Error] template argument 2 is invalid
90         //! queue<string>::iterator ite1;      //[Error] 'iterator' is not a member of 'std::queue<std::basic_string<char> >'    
91     }
92 }
queue

3.3关联容器

  在STL中关联容器使用红黑树来实现,因为不是顺序结构,因而不能使用上面提到的push和pop函数,使用insert和erase函数来实现元素的插入删除操作。

  关联容器支持通过键来高效地查找和读取元素,两个基本的关联容器类型是map和set。map的元素以键-值(key-value)对的形式组织:键用于元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。map可理解为字典,set可理解为一类元素的集合。

关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。

set 和 map 类型的对象所包含的元素都具有不同的键,不允许为同一个键添加第二个元素。如果一个键必须对应多个实例,则需使用 multimap 或 multiset,这两种类型允许多个元素拥有相同的键。

  • multiset ,set测试 
 1 void test_multiset(long& value)
 2     {
 3         cout << "
test_multiset().......... 
";
 4 
 5         multiset<string> c;
 6         char buf[10];
 7         clock_t timeStart = clock();
 8         for (long i = 0; i< value; ++i)
 9         {
10             try {
11                 snprintf(buf, 10, "%d", rand());
12                 c.insert(string(buf));
13             }
14             catch (exception& p) {
15                 cout << "i=" << i << " " << p.what() << endl;
16                 abort();
17             }
18         }
19         cout << "milli-seconds : " << (clock() - timeStart) << endl;
20         cout << "multiset.size()= " << c.size() << endl;
21         cout << "multiset.max_size()= " << c.max_size() << endl;    //214748364
22 
23         string target = get_a_target_string();
24         {
25             timeStart = clock();
26             auto pItem = find(c.begin(), c.end(), target);    //比 c.find(...) 慢很多
27             cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
28             if (pItem != c.end())
29                 cout << "found, " << *pItem << endl;
30             else
31                 cout << "not found! " << endl;
32         }
33 
34         {
35             timeStart = clock();
36             auto pItem = c.find(target);        //比 std::find(...) 快很多
37             cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
38             if (pItem != c.end())
39                 cout << "found, " << *pItem << endl;
40             else
41                 cout << "not found! " << endl;
42         }
43 
44 //        c.clear();
45 //        test_moveable(multiset<MyString>(), multiset<MyStrNoMove>(), value);
46     }
47 
48 void test_set(long& value)
49     {
50         cout << "
test_set().......... 
";
51 
52         set<string> c;
53         char buf[10];
54 
55         clock_t timeStart = clock();
56         for (long i = 0; i< value; ++i)
57         {
58             try {
59                 snprintf(buf, 10, "%d", rand());
60                 c.insert(string(buf));
61             }
62             catch (exception& p) {
63                 cout << "i=" << i << " " << p.what() << endl;
64                 abort();
65             }
66         }
67         cout << "milli-seconds : " << (clock() - timeStart) << endl;
68         cout << "set.size()= " << c.size() << endl;
69         cout << "set.max_size()= " << c.max_size() << endl;       //214748364
70 
71         string target = get_a_target_string();
72         {
73             timeStart = clock();
74             auto pItem = find(c.begin(), c.end(), target);    //比 c.find(...) 慢很多
75             cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
76             if (pItem != c.end())
77                 cout << "found, " << *pItem << endl;
78             else
79                 cout << "not found! " << endl;
80         }
81 
82         {
83             timeStart = clock();
84             auto pItem = c.find(target);        //比 std::find(...) 快很多
85             cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
86             if (pItem != c.end())
87                 cout << "found, " << *pItem << endl;
88             else
89                 cout << "not found! " << endl;
90         }
91     }
set
  • multimap,map 测试 
 1 void test_unordered_map(long& value)
 2     {
 3         cout << "
test_unordered_map().......... 
";
 4 
 5         unordered_map<long, string> c;
 6         char buf[10];
 7 
 8         clock_t timeStart = clock();
 9         for (long i = 0; i< value; ++i)
10         {
11             try {
12                 snprintf(buf, 10, "%d", rand());
13                 c[i] = string(buf);
14             }
15             catch (exception& p) {
16                 cout << "i=" << i << " " << p.what() << endl;
17                 abort();
18             }
19         }
20         cout << "milli-seconds : " << (clock() - timeStart) << endl;
21         cout << "unordered_map.size()= " << c.size() << endl;    //357913941
22         cout << "unordered_map.max_size()= " << c.max_size() << endl;
23 
24         long target = get_a_target_long();
25         timeStart = clock();
26         //! auto pItem = find(c.begin(), c.end(), target);    //map 不适用 std::find()
27         auto pItem = c.find(target);
28 
29         cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
30         if (pItem != c.end())
31             cout << "found, value=" << (*pItem).second << endl;
32         else
33             cout << "not found! " << endl;
34     }
35 
36 void test_map(long& value)
37     {
38         cout << "
test_map().......... 
";
39 
40         map<long, string> c;
41         char buf[10];
42 
43         clock_t timeStart = clock();
44         for (long i = 0; i< value; ++i)
45         {
46             try {
47                 snprintf(buf, 10, "%d", rand());
48                 c[i] = string(buf);
49             }
50             catch (exception& p) {
51                 cout << "i=" << i << " " << p.what() << endl;
52                 abort();
53             }
54         }
55         cout << "milli-seconds : " << (clock() - timeStart) << endl;
56         cout << "map.size()= " << c.size() << endl;
57         cout << "map.max_size()= " << c.max_size() << endl;        //178956970
58 
59         long target = get_a_target_long();
60         timeStart = clock();
61         auto pItem = c.find(target);
62         cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
63         if (pItem != c.end())
64             cout << "found, value=" << (*pItem).second << endl;
65         else
66             cout << "not found! " << endl;
67 
68         c.clear();
69     }
map

3.4无序容器

  严格意义上讲,无序容器也属于关联容器。

unordered_set,unordered_map,unordered_multiset,unordered_multimap

原文地址:https://www.cnblogs.com/flysong/p/8053845.html