1.C++标准库和STL
C++标准库以header files形式呈现:
- C++标准库的header files不带后缀名(.h),例如#include <vector>
- 新式C header files 不带后缀名.h,例如#include<cstdio>
- 旧式C header files (带有后缀名.h)仍然可用,例如#include <stdio.h>
- 新式headers内的组件封装于namespace “std”。 using namespace std;或者以 using std::cout;的形式
- 旧式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的行为也是一种容器。这就是一种配接器。除此之外,还有迭代器配接器和仿函数配接器。
STL 六大组件的交互关系
Container
通过Allocator
取得数据储存空间Algorithm
通过Iterator
存取Container
内容Functor
可以协助Algorithm
完成不同的策略变化Adapter
可以修饰或套接Functor
、Iterator
。
#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 }
静态整数成员变量
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 }
重载自增、自减、操作符
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 }
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 }
仿函数,函数对象
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 }
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 }
注: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 为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
- 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 }
::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
- 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 }
测试结果
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
- 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 }
测试结果
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
- 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 }
- 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 }
测试结果
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
- 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 }
- 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 }
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 }
- 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 }
3.4无序容器
严格意义上讲,无序容器也属于关联容器。
unordered_set,unordered_map,unordered_multiset,unordered_multimap