• 开始跟着《STL源码剖析》的作者侯捷真人视频,学习STL,了解STL背后的真实故事!
  • 视频链接:侯捷STL
  • 还有很大其他视频需要的留言

第一节:STL版本和重要资源

  • STL和标准库的区别

第二节:STL六大部件

  • 迭代器将容器和算法结合起来
  • 分配器实现,适配器用的地方很多

  • 实例:

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

第三节:容器之分类和各种测试(一)

分类结构

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

测试Array

  • 指针void* a -> *(long*)a;
  • array<long, size> c使用初始化大小,#include<array>
  • c.data()返回这个数组的初始地址,和数组的地址对比
  • qsort应用:qsort(c.data,size,size(long),comparelongs)
  • bsearch()应用,查找前必须排好序了:bsearch(&target,(c.data()),size,size(long),comparelongs)
  • qsort,bsearch包含头文件#include<cstdlib>,C本身库函数
#include <array>
#include <iostream>
#include <ctime>
#include <cstdlib> //qsort, bsearch, NULL namespace jj01
{
void test_array()
{
cout << "\ntest_array().......... \n"; array<long,ASIZE> c; clock_t timeStart = clock();
for(long i=0; i< ASIZE; ++i) {
c[i] = rand();
}
cout << "milli-seconds : " << (clock()-timeStart) << endl; //
cout << "array.size()= " << c.size() << endl;
cout << "array.front()= " << c.front() << endl;
cout << "array.back()= " << c.back() << endl;
cout << "array.data()= " << c.data() << endl; long target = get_a_target_long(); timeStart = clock();
::qsort(c.data(), ASIZE, sizeof(long), compareLongs);
long* pItem = (long*)::bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
cout << "qsort()+bsearch(), milli-seconds : " << (clock()-timeStart) << endl; //
if (pItem != NULL)
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
}
}

第四节:容器之分类和各种测试(二)

测试Vector

  • 主要通过程序细节说明
  • namespace命名空间的说明
  • vector的增长速度是2倍增长,当capacity不够时,容量增长为前面的2倍。是在另外的2倍空间!
  • try...catch...捕获函数,字符串最大占一个指针大小,空间不够的时候抛出,abort()退出
  • ::find()模板函数,加冒号表明是全局函数,当没有冒号时,编译器在当前没有找到,也会到全局去找。
  • 用两种查找算法比较,find()用时更少。
#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort() //qsort, bsearch, NULL
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
#include <algorithm> //sort()
namespace jj02
{
void test_vector(long& value)
{
cout << "\ntest_vector().......... \n"; vector<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
//曾經最高 i=58389486 then std::bad_alloc
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "vector.max_size()= " << c.max_size() << endl; //1073747823
cout << "vector.size()= " << c.size() << endl;
cout << "vector.front()= " << c.front() << endl;
cout << "vector.back()= " << c.back() << endl;
cout << "vector.data()= " << c.data() << endl;
cout << "vector.capacity()= " << c.capacity() << endl << endl; string target = get_a_target_string();
{
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl; if (pItem != c.end())
cout << "found, " << *pItem << endl << endl;
else
cout << "not found! " << endl << endl;
} {
timeStart = clock();
sort(c.begin(), c.end());
cout << "sort(), milli-seconds : " << (clock()-timeStart) << endl; timeStart = clock();
string* pItem = (string*)::bsearch(&target, (c.data()),
c.size(), sizeof(string), compareStrings);
cout << "bsearch(), milli-seconds : " << (clock()-timeStart) << endl; if (pItem != NULL)
cout << "found, " << *pItem << endl << endl;
else
cout << "not found! " << endl << endl;
} c.clear();
test_moveable(vector<MyString>(),vector<MyStrNoMove>(), value);
}
}

第五节:容器之分类和各种测试(三)

测试List,双向链表

  • list.max_size()按理list是动态申请空间的,为什么最大的size呢?
  • list双向链表实现
  • 有趣的c.sort(),这里注意在STL标准库全局有一个sort函数,但这里调用的是list容器自身内部的sort函数。注意在STL容器中有些自身有sort函数,此时用自身的排序算法更快。
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <algorithm> //find()
#include <iostream>
#include <ctime>
namespace jj03
{
void test_list(long& value)
{
cout << "\ntest_list().......... \n"; list<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "list.size()= " << c.size() << endl;
cout << "list.max_size()= " << c.max_size() << endl; //357913941
cout << "list.front()= " << c.front() << endl;
cout << "list.back()= " << c.back() << endl; string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl; if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl; timeStart = clock();
c.sort();
cout << "c.sort(), milli-seconds : " << (clock()-timeStart) << endl; c.clear();
test_moveable(list<MyString>(),list<MyStrNoMove>(), value);
}
}

测试forward-list,单向链表

  • forward-list单向链表,C++11出现的
  • push_front在链表头插入,不提供在尾部插入,效率低些。
  • front取链表头的元素,不提供back()操作取链表尾的元素。
  • c.sort()用它自身的排序算法
#include <forward_list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
namespace jj04
{
void test_forward_list(long& value)
{
cout << "\ntest_forward_list().......... \n"; forward_list<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_front(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "forward_list.max_size()= " << c.max_size() << endl; //536870911
cout << "forward_list.front()= " << c.front() << endl; string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl; if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl; timeStart = clock();
c.sort();
cout << "c.sort(), milli-seconds : " << (clock()-timeStart) << endl; c.clear();
}
}

测试slist

  • Gnu C之前的单链表,forward-list是C++11才出现的
  • #include<ext\slist>头文件
#include <ext\slist>
//注意, 上一行並沒有引發警告訊息如 #include <ext\hash_set> 所引發者:
//...\4.9.2\include\c++\backward\backward_warning.h
//[Warning] ... #include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
namespace jj10
{
void test_slist(long& value)
{
cout << "\ntest_slist().......... \n"; __gnu_cxx::slist<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_front(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
}
}

测试deque

  • 双向开口,是分段连续,感觉是连续的,其实不是。
  • 内存上两边都可以扩充
  • 每次512扩充,两边扩充申请buffer,buffer由指针指向
  • max_size由限制,使用全局的sort排序

#include <deque>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
namespace jj05
{
void test_deque(long& value)
{
cout << "\ntest_deque().......... \n"; deque<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "deque.size()= " << c.size() << endl;
cout << "deque.front()= " << c.front() << endl;
cout << "deque.back()= " << c.back() << endl;
cout << "deque.max_size()= " << c.max_size() << endl; //1073741821 string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl; if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl; timeStart = clock();
sort(c.begin(), c.end());
cout << "sort(), milli-seconds : " << (clock()-timeStart) << endl; c.clear();
test_moveable(deque<MyString>(),deque<MyStrNoMove>(), value);
}
}

测试stack

  • 栈,数据结构上和deque差不多
  • 两段插入插入删除受限的容器
  • 也有人叫做容器的适配器adapter
  • 没有提供容器的迭代器iterator,否则对迭代器的操作会破坏堆栈的结构
  • 也没有提供find,sort的功能;但是有时候让你实现堆栈的排序操作

#include <stack>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
namespace jj17
{
void test_stack(long& value)
{
cout << "\ntest_stack().......... \n"; stack<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
c.pop();
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl; {
stack<string, list<string>> c; //以 list 為底層
for(long i=0; i< 10; ++i) {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
c.pop();
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
} {
stack<string, vector<string>> c; //以 vector 為底層
for(long i=0; i< 10; ++i) {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
c.pop();
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
} {
stack<string, set<string>> c; //以 set 為底層
/*!
for(long i=0; i< 10; ++i) {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
c.pop();
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl; //[Error] 'class std::set<std::basic_string<char> >' has no member named 'push_back'
//[Error] 'class std::set<std::basic_string<char> >' has no member named 'back'
//[Error] 'class std::set<std::basic_string<char> >' has no member named 'pop_back'
*/
} //!stack<string, map(string>> c5; ////以 map 為底層, [Error] template argument 2 is invalid
//!stack<string>::iterator ite1; //[Error] 'iterator' is not a member of 'std::stack<std::basic_string<char> >' }
}

测试queue

  • 堆,数据结构上有deque衍生出来的
  • 没有提供容器的迭代器iterator,否则对迭代器的操作会破坏堆栈的结构

#include <queue>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
namespace jj18
{
void test_queue(long& value)
{
cout << "\ntest_queue().......... \n"; queue<string> c;
char buf[10]; clock_t timeStart = clock();
for(long i=0; i< value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
catch(exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock()-timeStart) << endl;
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
c.pop();
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl; {
queue<string, list<string>> c; //以 list 為底層
for(long i=0; i< 10; ++i) {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
c.pop();
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
} {
queue<string, vector<string>> c; //以 vector 為底層
for(long i=0; i< 10; ++i) {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
//!c.pop(); //[Error] 'class std::vector<std::basic_string<char> >' has no member named 'pop_front'
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
} {
queue<string, set<string>> c; //以 set 為底層
/*!
for(long i=0; i< 10; ++i) {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
c.pop();
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
//[Error] 'class std::set<std::basic_string<char> >' has no member named 'push_back'
//[Error] 'class std::set<std::basic_string<char> >' has no member named 'front'
//[Error] 'class std::set<std::basic_string<char> >' has no member named 'pop_front'
*/
} //! queue<string, map<string>> c5; //以 map 為底層, [Error] template argument 2 is invalid
//! queue<string>::iterator ite1; //[Error] 'iterator' is not a member of 'std::queue<std::basic_string<char> >'
}
}

侯捷STL学习(一)--顺序容器测试的更多相关文章

  1. 侯捷STL学习(二)--序列容器测试

    第六节:容器之分类和各种测试(四) stack不提供iterator操作,破坏了容器的独特性,先进先出. 使用容器multiset(允许元素重复) 内部是红黑树,insert操作就保证了排好了序. 标 ...

  2. 侯捷STL学习(十)--容器hashtable探索(unordered set/map)

    layout: post title: 侯捷STL学习(十) date: 2017-07-23 tag: 侯捷STL --- 第二十三节 容器hashtable探索 hashtable冲突(碰撞)处理 ...

  3. 侯捷STL学习(九)--关联式容器(Rb_tree,set,map)

    layout: post title: 侯捷STL学习(九) date: 2017-07-21 tag: 侯捷STL --- 第十九节 容器rb_tree Red-Black tree是自平衡二叉搜索 ...

  4. 侯捷STL学习(12)--STL相关内容hash+tuple

    layout: post title: 侯捷STL学习(12) date: 2017-08-01 tag: 侯捷STL --- 第四讲 STL相关的内容 Hash Function 将hash函数封装 ...

  5. 侯捷STL学习(11)--算仿+仿函数+适配器

    layout: post title: 侯捷STL学习(十一) date: 2017-07-24 tag: 侯捷STL --- 第三讲 标准库内核分析-算法 标准库算法形式 iterator分类 不同 ...

  6. 侯捷STL学习(八)-- 深度探索deque

    layout: post title: 侯捷STL学习(八) date: 2017-07-19 tag: 侯捷STL --- 第十八节 深度探索deque上 duque内存结构 分段连续,用户看起来是 ...

  7. 侯捷STL学习(七)--深度探索vector&&array

    layout: post title: 侯捷STL学习(七) date: 2017-06-13 tag: 侯捷STL --- 第十六节 深度探索vector vector源码剖析 vector内存2倍 ...

  8. 侯捷STL学习(一)

    开始跟着<STL源码剖析>的作者侯捷真人视频,学习STL,了解STL背后的真实故事! 视频链接:侯捷STL 还有很大其他视频需要的留言 第一节:STL版本和重要资源 STL和标准库的区别 ...

  9. 侯捷STL学习(二)

    第六节:容器之分类和各种测试(四) stack不提供iterator操作,破坏了容器的独特性,先进先出. 使用容器multiset(允许元素重复) 内部是红黑树,insert操作就保证了排好了序. 标 ...

随机推荐

  1. 【bzoj5085】最大(二分+乱搞)

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5085 这道题我们可以先二分答案,然后转化为判定是否有四角权值>=mid的矩形. ...

  2. EntityFramework 学习 一 Colored Entity in Entity Framework 5.0

    You can change the color of an entity in the designer so that it would be easy to see related groups ...

  3. js正则表达式验证(化繁为简)

    以前用js写正则表达式验证,每一个文本框后面都要添加一个onblur函数,验证的信息少,也没体会到有多繁琐,这次项目中的页面比较多,页面中的信息也比较多,如果每个文本框都加一个验证函数的话,js验证代 ...

  4. DataX-ElasticSearch(写)

    DataX写入ElasticSearch 1 快速介绍 数据导入elasticsearch的插件 2 实现原理 使用elasticsearch的rest api接口, 批量把从reader读入的数据写 ...

  5. JavaWeb -- 文件上传下载示例

    1. 上传简单示例 Jsp <%@ page language="java" import="java.util.*" pageEncoding=&quo ...

  6. OpenStack企业私有云新需求(1):Nova 虚机支持 GPU

    作者:Sammy Liu 刘世民 本系列会介绍OpenStack 企业私有云的几个需求: GPU 支持 自动扩展(Auto-scaling)支持 混合云(Hybrid cloud)支持 物理机(Bar ...

  7. Nginx虚拟主机配置模板

    /////////////////////////////写在前头//////////////////////////////////////////Nginx 服务器中文文档:http://www. ...

  8. css3+jquery+js做的翻翻乐小游戏

    主要是为了练习一下css3的3D翻转功能,就做了这么个小游戏,做的比较粗糙,但是效果看的见. 主要用到的css3代码如下: html结构: <div class="container& ...

  9. hdu3605最大流

    题意:给n个人m个星球,每个人适不适合去某个星球,每个星球的最大容量,看能不能满足所有人能去一个星球 题解:可以看出如果直接建边,边的个数是1e5左右的,这样时间肯定会爆掉,那么我们考虑用二进制状态压 ...

  10. PCA算法详解——本质上就是投影后使得数据尽可能分散(方差最大),PCA可以被定义为数据在低维线性空间上的正交投影,这个线性空间被称为主⼦空间(principal subspace),使得投影数据的⽅差被最⼤化(Hotelling, 1933),即最大方差理论。

    PCA PCA(Principal Component Analysis,主成分分析)是一种常用的数据分析方法.PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量 ...