C++面试题目汇总 容器和算法
容器和算法
map
和set
有什么区别,分别又是怎么实现的?
-
map
和set
都是STL
中的关联容器,其底层实现都是红黑树(RB-Tree
)。由于map
和set
所开放的各种操作接口,RB-tree
也都提供了,所以几乎所有的map
和set
的操作行为,都只是转调RB-tree
的操作行为。 -
map
和set
区别在于:map
中的元素是key-value(关键字—值)对
:关键字起到索引的作用,值则表示与索引相关联的数据;set
只是关键字的简单集合,它的每个元素只包含一个关键字。set
的迭代器是const
的,不允许修改元素的值;而map
虽然不允许修改关键字(Key)
,但是允许修改value
。
其原因是map
和set
都是根据关键字排序来保证其有序性的,如果允许修改key
的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平衡,如此一来,严重破坏了map
和set
的结构,导致iterator
失效。所以STL
中将set
的迭代器设置成const
,不允许修改迭代器的值;而map
的迭代器则不允许修改key
值,允许修改value
值。map
支持下标操作,set
不支持下标操作。
map
可以用key
做下标,map
的下标运算符[ ]
将关键码作为下标去执行查找,如果关键码不存在,则插入一个具有该关键码和mapped_type
类型默认值的元素至map
中,因此下标运算符[ ]
在map应用中需要慎用,const_map
不能用,只希望确定某一个关键值是否存在而不希望插入元素时也不应该使用,mapped_type
类型没有默认值也不应该使用。如果find
能解决需要,尽可能用find
。
请你来介绍一下STL
的allocator
STL
的分配器用于封装STL
容器在内存管理上的底层细节。- 在
C++
中,其内存配置和释放包括两个关键之:new
和delete
:new
运算分两个阶段:1) 调用::operator new
配置内存;2) 调用对象构造函数初始化对象delete
运算分两个阶段:1) 调用对象析构函数;2) 调用::operator delete
释放内存
- 在
STL allocator
将以上阶段分作四个函数分别负责:allocate函数
负责分配内存空间,deallocate函数
负责内存释放,construct
负责对象构造,destroy
负责对象析构. - 为了提升内存管理效率, 减少申请小内存造成的内存碎片化问题,
SGI STL
采用两级分配至, 当分配空间的大小超过128B
的时候,会使用第一级空间配置器, 当分配空间大小小于128B
时,采用第二级空间配置器.- 一级空间配置器直接使用
malloc
,realloc
,free
函数进行内存空间分配和释放. - 二级空间配置器使用内存池技术管理内存, 使用
16
个链表维护8-128byte
的16级别的小内存块.
- 一级空间配置器直接使用
- 参考: C++ STL 的内存优化
STL
迭代器删除元素
- 这个主要考察的是迭代器失效的问题。
- 对于序列容器
vector
,deque
来说,使用erase(itertor)
后,后边的每个元素的迭代器都会失效,但是后边每个元素都会往前移动一个位置,但是erase
会返回下一个有效的迭代器 - 对于关联容器map set来说,使用了erase(iterator)后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素的,不会影响到下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可。
- 对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种正确的方法都可以使用。
- 对于序列容器
STL
中MAP
数据存放形式
- 红黑树。
unordered map
底层结构是哈希表
STL
有什么基本组成
STL
主要由六大部分组成:容器
,迭代器
,仿函数
,算法
,适配器
,配置器
- 他们之间的关系:
- 配置器为容器提供空间, 它是对空间动态分配,管理和释放的实现
- 迭代器实现了容器和算法的衔接, 算法通过迭代器获取容器中的内容
- 仿函数可以协助算法完成各种操作,适配器用来套接适配仿函数
STL
中map
, unordered_map
, multimap
map
,unordermap
以及mul