牛客网:C++面试宝典——基础知识(4)容器和算法

感觉牛客网的整理有丢丢凌乱

● 请你来说一下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主要由:以下几部分组成:
容器、迭代器、仿函数、算法、分配器、适配器

  1. 分配器给容器分配存储空间
  2. 算法通过迭代器获取容器中的内容
  3. 仿函数可以协助算法完成各种操作
  4. 适配器是用来修改其他组件接口的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: vectorv; v.resize(len);v的size变为len,如果原来v的size小于len,那么容器新增(len-size)个元素,元素的值为默认为0.当v.push_back(3);之后,则是3是放在了v的末尾,即下标为len,此时容器是size为len+1;

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<

牛客网:C++面试宝典——基础知识(4)容器和算法_第1张图片

你可能感兴趣的:(c++)