1、容器的基本要求
a、并非所有的数据都可以放进容器当中。各种容器模板对所存数据类型都有一个基本要求——可复制构造。将数据放进容器的过程就是通过数据的复制构造函数在容器内创建数据的一个副本的过程。
b、容器中必须有若干与所存数据类型有关的嵌套定义类型。
C::value_type 容器所存数据类型
C::reference 容器数据的引用类型
C::const_reference 容器数据的只读引用类型
C::size_type 容器容量类型,通常是一个无符号整数类型
c、除嵌套类型定义外,容器还必须拥有默认构造函数以及复制构造函数。
d、容器还须提供一系列与迭代器有关的嵌套定义类型以及成员函数。

e、其它:
新增四个成员函数cbegin()、cend()、crbegin()、crend()分别明确返回对应的只读迭代器。
容器必须有成员函数size()、max_size()、empty(),分别返回当前容器内元素个数、最大可容元素数以及容器是否为空。
容器必须有一个成员函数swap(C &a)用于与另一同类容器互换内容。
两个同类容器之间可以比较是否相等。
还有其它附加要求。
 
2、序列型容器
2.1、vector
vector是一个边长数组容器类模板。数据在vector中连续存储。谓词vector会预先申请一段内存空间以保存数据。随着数据不断增加,当预留的内存空间不够用时,vector会再申请一段更大的空间并将现有数据搬到新空间中后再继续接受新数据。由于数据在内存空间内连续存放,所以vector可提供快速随机访问。
所以,vector适用于数据增删不频繁但需要高效随机存取的场合,而不适用于需要频繁在序列中增删数据的场合。
如果数据可以预估,可以先调用reserve()函数申请足够空间,这样可以避免无谓的数据迁移。
 
void main()
{
int array[] = { , , , , };
std::vector<int> v; v.reserve();
v.assign(array, array + ); typedef std::vector<int>::iterator iterator;
iterator p = v.begin();
iterator q = v.end() - ; v.erase(p + , p + ); v.insert(v.end(), array, array + ); getchar();
}
由于erase以及insert操作,原本的p和q指针已经不指向原本预期的位置了。
vector除了要求所存数据类型是可复制构造的,还要求是可赋值的。
了解容器,就要了解支撑这个容器的底层的数据结构,才能以最高效的方式使用这个容器。
2.2、双向链表
2.3、双端序列
 
3、容器转换器
容器转换器是某种模板,这种模板利用某种容器而构建成某种数据结构。
容器转换器,是利用容器实现特定数据结构的模板。标准中定义三种容器转换器模板:stack、queue、priority_queue。
stack与queue的模板有两个参数,前一参数定义stack及queue要保存的数据类型,后一参数则定义所用容器类型。
std::stack<int, std::vector<int>> vector_stack;    //用vector实现stack
std::stack<int> deque_stack; //用deque实现stack
std::queue<char, std::list<char>> queue; //用list实现queue
std::queue<char> deque_queue; //用deque实现queue
以priority_queue为例:
#include <iostream>
#include <queue>
#include <vector> struct my_pair
{
int first;
int second;
}; struct comp_my_pair//这是一个函数对象
{
bool operator()(my_pair const &left,
my_pair const &right)
{
return left.first == right.first ?
left.second > right.second :
left.first > right.first;
}
}; void main()
{
my_pair array[] = {{, }, {, }, {, }, {, }, {, }};
using std::priority_queue;
using std::vector; priority_queue<my_pair, vector<my_pair>, comp_my_pair> pq(array, array + );
while(!pq.empty())
{
std::cout << pq.top().first << ", " << pq.top().second << std::endl;
pq.pop();
} return;
}
4、关联型容器
关联型容器的特征就是以“值”寻“址”,即容器可以快速找出某个给定值在容器中的位置,或者查无此值返回。
关联型容器包括集合set、多值集合multiset、映射map以及多值映射multimap。四种容器都是以红黑树保存数据。所以这些容器的优势就等同于红黑树的优势。
a、要了解什么是红黑树,参考:https://blog.csdn.net/cout_sev/article/details/24628903
b、要知道什么是“多值”。
 
关联型容器都会支持一个函数型对象,用来比较插入的数据大小。
 
插入:执行插入操作时,如果你心中有一个map的底层数据结构模型,那么你就可以知道你每一步插入的时间复杂度是多少。并使用“智能插入”来实现高效插入。
举例:
typedef std::set<int> int_set;
typedef void func_type(int*, int*); float measure(func_type func, int *start, int *end)
{
//int start_clock = clock();
func(start, end);
//int end_clock = clock();
return ;
//return float(end_clock - start_clock) / CLOCKS_PER_SEC;
} void test_plain_insert(int *start, int *end)
{
int_set s;
s.insert(start, end);
for(int_set::iterator it = s.begin(); it != s.end(); it++)
{
printf("%d ", *it);
}
printf("\n");
} void test_smart_insert(int *start, int *end)
{
int_set s;
int_set::iterator prev = s.begin();
for(; start != end; ++start)
{
prev = s.insert(prev, *start);
for(int_set::iterator it = s.begin(); it != s.end(); it++)
{
printf("prev:%d ;", *prev);
printf("%d ", *it);
}
printf("\n"); } printf("\n");
} void main()
{ const int num = ;
const int half = num / ; int array1[num];
int array2[num];
for(int i = ; i < num; ++i)
{
array1[i] = i;
array2[i] = (i & ) ? (i - num) : (num - i);
} measure(test_plain_insert, array2, array2 + num -);
measure(test_smart_insert, array2, array2 + num -);
//measure(test_plain_insert, array1, array1 + num -1);
//measure(test_smart_insert, array1, array1 + num -1);
return;
}

正常的插入insert(i, j)底层执行的是insert(end, v),而我们看这里的逻辑,end始终指向的是8;
而如果使用insert(prev, v),那么prev始终指向的是刚刚插入的位置;
就是二者的迭代器指向不同,导致了效率的差异。
所以,想用好stl库,一定要对其底层数据结构有深入了解。
 
 

《深入实践C++模板编程》之六——标准库中的容器的更多相关文章

  1. STL标准库中的容器

    容器:顾名思义,我的理解就是把同一种数据类型括起来,作为一捆.如vector<int> ,vector就是个容器,里面全是一个个的int型数据. 容器包括三大块: 顺序型容器: (1)ve ...

  2. STL笔记(6)标准库:标准库中的排序算法

    STL笔记(6)标准库:标准库中的排序算法 标准库:标准库中的排序算法The Standard Librarian: Sorting in the Standard Library Matthew A ...

  3. 用CAS操作实现Go标准库中的Once

    Go标准库中提供了Sync.Once来实现"只执行一次"的功能.学习了一下源代码,里面用的是经典的双重检查的模式: // Once is an object that will p ...

  4. 彻底弄清c标准库中string.h里的常用函数用法

    在我们平常写的c/c++程序,一些算法题中,我们常常会用到c标准库中string.h文件中的函数,这些函数主要用于处理内存,字符串相关操作,是很有用的工具函数.而且有些时候,在笔试或面试中也会出现让你 ...

  5. 通过atomic_flag简单自旋锁实现简单说明标准库中锁使用的memory_order

    在使用标准库中的加锁机制时,例如我们使用std::mutex,写了如下的代码(下面的代码使用condition_variable可能更合适) std::mutex g_mtx; int g_resNu ...

  6. Python 标准库中的装饰器

    题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...

  7. (转)python标准库中socket模块详解

    python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...

  8. c/c++标准库中的文件操作总结

    1 stdio.h是c标准库中的标准输入输出库 2 在c++中调用的方法 直接调用即可,但是最好在函数名前面加上::,以示区分类的内部函数和c标准库函数. 3 c标准输入输出库的使用 3.1 核心结构 ...

  9. C标准库中atoi的一种可能的实现

    为避免与标准库中的atoi产生歧义, 我将自己编写的函数命名为strToInt, 以下是示例代码 #include <stdio.h> int strToInt(const char *s ...

随机推荐

  1. Spring Boot ERROR StatusLogger No Log4j 2 configuration file found

    1. 问题描述 项目之前的 log4j2 配置没问题,把 pom 文件中的 spring-boot-starter-web 依赖删除后,然后启动项目就报错找不到 log4j2.yml 文件. 之前引用 ...

  2. css 能改变input type radio和checkbox 圆圈或方框的大小

    把input隐藏,外面套label,再里面加个span,样式写在span上,让label覆盖在span上面,js去改active的class <label for="remember& ...

  3. 查找与排序算法(Searching adn Sorting)

    1,查找算法 常用的查找算法包括顺序查找,二分查找和哈希查找. 1.1 顺序查找(Sequential search) 顺序查找: 依次遍历列表中每一个元素,查看是否为目标元素.python实现代码如 ...

  4. Android 美团Robust热更新 使用入门

    Android热更新方案Robust 相信很多人都认识了解过 热修复.热更新.热补丁(对于这个技术也没有特别标准的一种叫法,下面我统一叫热更新),之后的一年里,各种热更新方案如雨后春笋般出现,比较耳熟 ...

  5. 基于Python使用scrapy-redis框架实现分布式爬虫

    1.首先介绍一下:scrapy-redis框架 scrapy-redis:一个三方的基于redis的分布式爬虫框架,配合scrapy使用,让爬虫具有了分布式爬取的功能.github地址: https: ...

  6. RedHat Enterprise7 修改为CentOS的yum源

    报错 解决 1.将自带的yum卸载掉 2.下载centos的yum并安装 wget http://mirrors.163.com/centos/7/os/x86_64/Packages/yum-met ...

  7. Ubuntu16.04格式化U盘

    root@ubuntu:~# fdisk -l root@ubuntu:~# fdisk /dev/sdb 格式化U盘: root@ubuntu:~# fdisk -l sudo mkfs.ntfs ...

  8. 关于XMind软件文件格式的一些思考

    1,安装XMind软件,看见可以导入Markdown文件 2,因此新建了测试.md文件,代码格式为左图,显示效果为右图. 3,导入到XMind中显示为下图 4,也就是XMind中子标题对应着Markd ...

  9. Swift3.0项目学习: 创建撰写按钮

    import UIKit class PSMainViewController: UITabBarController { override func viewDidLoad() { super.vi ...

  10. 小程序接入云通信IM

    小程序接入云通信IM--插件 小程序微信后台搜索AI情报官组件即可获得小程序云通信IM的即时通信能力