C/C++面试知识点总结(二)

目录:

一、基础知识

    1.C/C++

    2.STL

    3.数据结构与算法

    4.计算机网络

    5.操作系统

    6.数据库

二、项目经历

    1.纯属个人YY








2.STL基础

(1).vector的实现原理

vector和数组类似,不同的是vector能动态增长,数组则是静态的,一旦初始化,大小就不能改变。相同之处在于,vector是线性的空间,其所有操作和数组一样。都能随机读写。

vector的动态增长的三步骤是,开辟新空间、移动数据、销毁旧空间。
需要注意的是,所谓的动态增长并不是在原空间之后分配接续的空间,而是另外配置大于原空间两倍的新空间(SGI版本是2倍,VS自带的那个版本是50%)。因此,对vector的任何操作,一旦引起空间重新分配,指向原vector的所有迭代器(类似使用野指针错误)就都失效了。

这里放个思考题,能不能在正常的for循环里面用erase删除元素,为什么。

(2).list的实现原理

list采用的是环状双向链表,这大概是链表中最高级的链表了,其添加、插入、删除操作的时间复杂度都是O(1)。

和vecotr不同的是,当删除某个节点的时候,只有指向那个节点的那个迭代器失效,其它迭代器可以正常使用,而vector因为担心添加删除后空间的大小问题导致程序出错,因而所有的迭代器都失效了。

(3).deque的实现原理

deque采用的是数据分段存储,即当其中一块缓冲区满了,不会像vector一样,进行开辟、移动、销毁三个步骤,而是直接开辟一块新的缓冲区进行存储,然后由一个指针数组来管理那些分块的缓冲区。由此达到vector的伪线性空间。

(4).stack的实现原理

stack是一种先进后出的数据结构,其底层采用deque实现,只是将deque的接口进行修改,因而在STL中stack被称作是容器适配器。

stack中不能有迭代器,要严格遵守先进后出的操作。

(5).queue的实现原理

和stack类似,它是一种先进先出的数据结构。

(6).priority_queue的实现原理

这是一个根据权值排序的优先队列,内部用的是max-heap,即大顶堆,取值的时候就是取根节点的值。

(7).set的实现原理

这是一个不允许键值重复的集合,因为set中的键就是值,值就是键,所以不允许像map一样插入一对键值。set的底层采用RB-Tree实现,也就是红黑树,一种比较平衡的二叉树(AVL树是高度平衡的二叉树)。RB-Tree向STL内部提供的两个插入接口为insert_unique()和insert_equal(),顾名思义,前者插入唯一的键值,后者可以重复,而set用的就是insert_unique()这个接口。

一个小的思考题,set中的find和STL的find哪个快,为什么?

(8).map的实现原理

map也是不允许键值重复的,和set不同的是,map的键值是分开的,不像set一样,相等的。其底层也是采用RB-Tree实现的,调用的也是insert_unique()这个接口。

(9).multiset和multimap的实现原理

multiset的原理和set差不多,只是调用的插入接口是insert_equal(),multimap同理。

(10).hash_XX的实现原理

底层都是采用hashtable实现,解决冲突的办法是采用开链(网上也有写叫做拉链),通俗的讲就是用vector维护一张一维的表格,然后每个格子都会指向一个链表,这个链表不是STL的list,而是hashtable自己维护的一个简单链表。
然后hash_XX就是封装了一下hashtable的接口,其用法和set、map等一模一样,只是底层从RB-Tree换成了hashtable。

(11).unordered_XX的实现原理

unordered_XX和hash_XX的实现原理一样,只是前者是C++11引入的标准库。现在一般推荐使用unordered_XX替换掉hash_XX。

(12).map和hash_map优缺点比较

直接从底层的实现比较即可。

红黑树实现的map占用内存较小,但是查找效率不高,O(logn)的查找效率。

hash表实现的map占用内存较大,但是查找效率高,往往可以逼近O(1)的惊人查找效率。

所以如何选择map和hash_map呢?这个就要看具体情况了。因为红黑树是一颗较为平衡的二叉树,所以查找的时间复杂度稳定在O(logN),而哈希表因为关键字冲突的情况,最坏的复杂度到达了O(N)(这种情况是非常小概率上的,这里只是夸张说明一下),为什么会到达O(N)?假设你N个元素都冲突,然后哈希表就退化成了单链表(用开链法的时候),此时查找的时间复杂度就是O(N)了。

经过测试,当数据较大,查找频繁的时候,使用hash_map的总体效率高于map。(这个就相当于数据量越大,查找越频繁,随机性就越大,冲突的概率就越小)

(13).STLfind的实现原理

这是一个泛型的查找函数,只需要提供两个迭代器和需要查找的值,然后内部进行循序查找,效率较低。这就是为什么set、map等的find比STL find快的原因,因为set、map等采用的是红黑树实现的,所以查找时间复杂度是O(logN)。

(14).STL sort的实现原理

sort接受两个RandomAccessIterators(随机存取迭代器),所以像list这种容器的迭代器是不能用sort来排序的,必须使用它自带的sort排序。而关联式容器,因为其是由红黑树实现的,本身就是排序的,所以也不能用sort排序。

当数据量大时采用快速排序,一旦分段后的数据量小于某个门槛,为了避免快排递归调用带来的过大负荷,就改用插入排序。如果递归层次过深还会改用堆排序。

说明一下,当数据量很小的时候,因为快速排序会递归的分割数据,造成额外的空间、时间浪费,性能上就比不上插入排序了。而如果数据量太大(特别是基本已序的),会造成快排递归深度过大,导致栈溢出,此时应该用堆排序。

猜你喜欢

转载自blog.csdn.net/qq_18297675/article/details/77117814