感觉牛客网的整理有丢丢凌乱
● 请你来说一下map和set有什么区别,分别又是怎么实现的?
map和set都是C++的关联容器,其底层实现都是红黑树(RB-Tree)。
map和set区别在于:
(1)map中的元素是key-value(关键字—值)对:关键字起到索引的作用,值则表示与索引相关联的数据;Set与之相对就是关键字的简单集合,set中每个元素只包含一个关键字。
(2)set的迭代器是const的,不允许修改元素的值;map允许修改value,但不允许修改key。其原因是因为map和set是根据关键字排序来保证其有序性的,如果允许修改key的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平衡,如此一来,严重破坏了map和set的结构,导致iterator失效,不知道应该指向改变前的位置,还是指向改变后的位置。所以STL中将set的迭代器设置成const,不允许修改迭代器的值;而map的迭代器则不允许修改key值,允许修改value值。
(3)map支持下标操作,set不支持下标操作。map可以用key做下标,map的下标运算符[ ]将关键码作为下标去执行查找
(4)set适用:有序无重复的集合,map适用:有序键值对不重复的映射
● 请你来介绍一下STL的allocator
参考
我不知道的东西太多了,,,
new将内存分配和对象构造组合在了一起,
delete将对象析构和内存释放组合在了一起.
标准库中allocator的类,允许我们将分配和初始化分离。使用allocator通常会提供更好的性能和更灵活的内存管理能力。
STL allocator将两个阶段操作区分开来:内存配置有allocate()负责,内存释放由deallocate()负责;
对象构造由construct()负责,对象析构由destroy()负责。
● 请你来说一说STL迭代器删除元素
参考1 参考2
1.对于序列容器vector,deque来说,删除当前的iterator会使后面所有元素的iterator都失效。这是因为vector,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。不过erase方法可以返回下一个有效的iterator。
2.对于关联容器map set来说,使用了erase(iterator)后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素的,不会影响到下一个元素的迭代器,只要在erase时,递增当前的iterator即可。
3.对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种正确的方法都可以使用。
list是由双向链表实现的,因此内存空间是不连续的。
● 请你说一说STL中MAP数据存放形式
参考
map: map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树存储的,使用中序遍历可将键值按照从小到大遍历出来。
unordered_map: unordered_map内部实现了一个哈希表,因此其查找速度非常的快(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此,其元素的排列顺序是无序的。
● 请你讲讲STL有什么基本组成
STL主要由:以下几部分组成:
容器、迭代器、仿函数、算法、分配器、适配器
● 请你说说STL中map与unordered_map
● 请你说一说vector和list的区别,应用,越详细越好
参考
区别 | vector | list |
底层结构 | 动态顺序表——数组,在内存中是一段连续的空间。 | 双向链表,在内存中不是一段连续的空间 |
随机访问 | vector支持随机访问,可以利用下标精准定位到一个元素上,访问某个元素的时间复杂度是O(1)。 | list不支持随机访问,时间复杂度是O(N)。 |
插入 | vector一次性分配好内存,不够时才进行2倍扩容 考虑插入的位置和是否扩容 在新增数据的时候,就要分配一块更大的内存,vector是以2倍的方式扩容的,将原来的数据复制过来,释放之前的内存,在插入新增的元素; |
list每次插入新节点都会进行内存申请。 不需要搬移元素,只需要改变插入或删除位置的前后两个节点的指向即可,时间复杂度为O(1)。 |
删除 | 考虑删除的位置——内存拷贝 | 不需要搬移元素,只需要改变插入或删除位置的前后两个节点的指向即可,时间复杂度为O(1)。 |
● 请你来说一下STL中迭代器的作用,有指针为何还要迭代器
1、迭代器
Iterator(迭代器)用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。
2、迭代器和指针的区别
迭代器不是指针,是类模板,表现的像指针。他只是模拟了指针的一些功能,通过重载了指针的一些操作符,->、*、++、--等。
迭代器封装了指针,是一个可遍历STL( Standard Template Library)容器内全部或部分元素”的对象
迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身。
● 请你说一说epoll原理
Linux完全的知识盲区,,,
参考
1. epoll_create:建立一个epoll对象(在epoll文件系统中给这个句柄分配资源);
2. 调用epoll_ctl:可以向epoll句柄添加或者删除要监听的文件句柄
3.epoll_wait:等待事件发生了
● n个整数的无序数组,找到每个元素后面比它大的第一个数,要求时间复杂度为O(N)
参考 需要借用一个栈stack
vector func(vector num){
if(num.size()==0) return num;
vector res(num.size());
stack s;
int i=0;
while(i
● 请你回答一下STL里resize和reserve的区别
参考
resize():改变当前容器内含有元素的数量
eg: vector
reserve():改变当前容器的最大容量,它不会生成元素,只是确定这个容器允许放入多少对象如果reserve(len)的值大于当前的capacity(),那么会重新分配一块能存len个对象的空间,然后把之前v.size()个对象通过copy construtor复制过来,销毁之前的内存;
#include
#include
using namespace std;
int main() {
vector a;
a.reserve(100);
a.resize(50);
cout<