面试宝典:容器和算法

1、说一下map和set有什么区别,分别是怎么实现的:
map和set都是c++的关联容器,底层实现都是红黑树;
区别在于:map中的元素是(关键字–值)对,关键词起到索引的作用,值表示与索引相关联的数据;set是关键字的简单集合,set中每个元素只包含一个关键字;
set的迭代器是const的,map允许修改value不允许修改key,因为map和set是根据关键字排序保证其有序性;
map支持下标操作,set不支持,当map使用下标执行查找时若不存在相应key,则插入一个具有该key和mapped_type类型默认值的元素到map中;

2、介绍STL中的allocaotr:
和vector一样allocator是一个模板类型,它将内存配置(new运算)和内存释放(delete运算)两个阶段操作区分开;
为了提升内存管理效率,减少申请小内存造成的碎片问题,采用两级配置器,当分配的空间大小超过128B时,会使用第一级空间配置器;当分配空间大小小于128B时,将使用第二级空间配置器,第一级空间配置器直接使用malloc,realloc,free函数进行内存空间的分配和释放,而第二级空间配置器采用内存池技术,通过空闲链表管理内存。

3、说一说STL迭代器删除元素:
对于序列容器vector、deque来说,使用erase(itertor)后,后面的每个元素的迭代器都会失效,但是后面的每个元素都会往前移动一个位置,但是erase会返回下一个有效的迭代器;
对于关联容器map set来说,使用了erase(itertor)后,当前元素的迭代器失效,删除当前元素的,不会影响到下一个元素的迭代器;
对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的itraator。

4、STL中MAP数据存放形式:
红黑树,底层结构是哈希表。

5、STL有什么基本组成:
容器、迭代器、仿函数、算法、分配器、配接器
分配器给容器分配存储空间,算法通过迭代器获取容器内容,仿函数可以协助算法完成各种操作,配接器用来套接适配仿函数。

6、STL中的map与unordered_map:
map映射,map所有元素都是pair,同时拥有key和value,pair的第一元素被视为key,第二元素被视为value,所有元素都会根据元素的key自动被排序,不允许key重复,底层用红黑树实现;
multimap多重映射,和map的区别是允许键值重复,底层用红黑树实现,其他同map。

7、vector和list的区别,应用:
vector是一个连续存储的容器,动态数组,在堆上分配空间;
底层实现是数组,vector增加新元素时,如果未超过当时的容量,直接添加到最后,然后调整迭代器,若没有剩余空间,则会重新配置原有元素个数的两倍空间,然后将原空间元素复制初始化新空间,再向新空间增加元素,最后析构并释放原空间,之前的迭代器会失效;性能方面:访问O(1),插入(最后插入空间够很快,不够申请内存释放原空间,以及对之前数据进行拷贝;中间插入内存够 内存拷贝;不够多一个内存申请和释放)删除(最后删除很快,中间删除 内存拷贝)适用于随机访问,且不经常对非尾节点进行插入删除;
list:动态链表,在堆上分配空间,每插入一个元素都会分配空间,每删除一个元素都会释放空间;底层是双向链表,随机访问性能很差只能快速访问头尾节点,插入和删除很快,使用也经常插入删除大量数据的场景;
区别:vector底层实现是数组,list是双向链表;
vector支持随机访问,list不支持;
vector是顺序内存,list不是;
vector在中间节点插入删除会导致内存拷贝,list不会;
vector一次性分配好内存,不够时进行二倍扩容,list每次插入新节点都会进行内存申请;
vector随机访问性能良好,插入删除性能差;list插入删除性能好,随机访问性能差。

8、说一下为什么STL中迭代器的作用,有指针为何还要迭代器:
迭代器用于提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象内部表示;运用迭代器是我们可以在不知道内部表示的情况下,按照一定顺序访问聚合对象中的各个元素;
迭代器不是指针,是类模板,表现得像指针,只是通过重载了一些操作符–,++等模拟了指针的一些功能;迭代器封装了指针,是一个可遍历STL容器内全部或部分元素的对象,本质是封装了原生指针,相当于一种智能指针,可以根据不同类型的数据结构来实现不同的++,–等操作,迭代器返回的是对象的引用;
iterator类访问方式就是把不同集合类的访问逻辑抽象出来,使得不用暴露集合内部结构而达到循环遍历集合的效果。

9、说一说epoll原理:
首先创建一个epoll对象,然后使用epoll_ctl对这个对象进行操作把需要监控的描述添加进去,这些描述将会以epoll_event结构体的形式组成一颗红黑树,接着阻塞在epoll_wait,进入大循环,当某个fd上有事件发生时,内核将会把其对应的结构体放入到一个链表中,返回有事件发生的链表;

10、n个整数的无序数组,找到每个元素后面比他大的第一个数,要求时间复杂度为O(n):
vector < int> find(vector< int> num) {
if (num.size() == 0)
return num;
vector< int> arr(num.size());
int i = 0;
stack< int> s;
while (i < num.size()) {
if (s.empty() || num[s.top()] >= num[i])
s.push(i++);
else{
arr[s.top()] = num[i];
s.pop();
}
}
while (!s.empty()) {
arr[s.top()] = INT_MAX;
s.pop();
}
for (int j = 0; j < arr.size(); j++) {
cout << arr[j] << " ";
}
return arr;
}

11、回答一下STL里resize和reserve的区别:
resize:改变当前容器内含有元素的数量,例如:vector< int> v;v.resize(len);v的size变为len,那么容器新增(len-size)个元素,元素的值默认为0,当v.push_back(3)之后,3放在了容器末尾,下标为len,此时容器是size为len+1;
reserve():改变容器的最大容量,他不会生成元素,只是改变这个容器允许放入多少对象,如果reserve(len)的值大于当前的容器容量,那么会重新分配一块能存len个对象的空间,然后把之前的对象复制进去,销毁之前的内存;

12、set和map是怎么实现的:
集合,所有的元素都会根据元素值自动被排序,且不允许重复,底层用红黑树实现,set所开放的各种操作接口,rb-tree也都提供了,所以几乎所有的set操作行为,都只是转调rb-tree的操作行为,适用于有序不重复集合;
map映射,map映射的所有元素都是pair,同时拥有value和key,pair的第一元素被视为key第二元素被视为value,所有元素都会根据元素的减值自动被排序,不允许键值重复,底层是红黑树,适用于有序键值对不重复映射。

你可能感兴趣的:(面试,面试)