15程序员面试笔记之模板与泛型编程

参考资料:

[1]程序员面试笔记 第15章 模板与泛型编程

15.1模板

面试题1:模板全特化和偏特化的使用方式

(1)调用函数模板时,无需指定模板参数的类型。比如说:
(2)类模板在实例化时,必须指定模板参数类型。
(3)模板特化是说将模板参数指定为特定的类型。在原来没有特化的类模板基础上加的。
(4)函数模板只能进行全特化,不能进行偏特化。

面试题2:模板函数的重载问题

(1)只有模板参数的类型完全一致,该函数模板才会被调用,普通函数在类型不完全匹配时,会进行隐式类型转换。
(2)解决办法是将模板参数定义为不同类型,或者重载模板函数进行解决。

15.2顺序容器

(1)vector容器在堆空间建立一个1维数组,因为地址空间是连续的,支持快速随机访问。在vector尾部插入和删除元素最快,因为不需要移动任何元素。在头部插入和删除元素最慢,因为需要移动所有元素。
(2)string可以理解为char类型容器。
(3)list本质上是一个双向链表,支持任意位置的快速插入和删除。由于list物理空间不连续,不支持快速的随机访问,只能从链表的表头进行顺序遍历。
(4)deque容器的内部实现比较复杂,与vector类似,deque随机访问元素的效率很高,接近vector,deque的头部和尾部插入和删除速度特别快。
(5)vector和deque都涉及到动态申请空间的问题,vector在元素满的情况下,会申请一块更大的空间,将所有数据拷贝到新的空间中。
deque在首段数据空间和尾段数据空间满的情况下,会申请一块新的空间,附加到deque空间中,在首段数据空间和尾段数据空间为空的情况会把这段空间释放,从整个deque空间中移除。

面试题1:简述vector容器空间增长的原理

如果向一个已满的vector中插入元素,会重新分配一块新的内存空间,并将所有元素和新插入的元素拷贝到新的空间中。新空间的大小比原空间大若干个元素大小的空间,之后进行插入若干个元素而无需重新分配空间。

面试题2:简述vector容器中size和capacity函数的用法

size函数返回的是当前容器中的已经保存的元素的个数。
capacity函数返回的是当前容器最多能保存的元素的个数。

面试题3:手动调整vector容器空间的方式

reserve函数可以指定容器重新分配指定大小的空间。
shrink_to_fit函数可以进行回收尚未使用的空间
resize函数强制调整容器中已经保存的元素个数。超过resize指定大小的元素会被删除。

面试题4:简述deque容器的插入和删除原理

双端队列是一个双向开口的存储空间分段的数据结构,每段数据空间内部是连续的,每段数据空间之间不一定连续。
deque的空间是程序运行过程中在堆上进行动态分配的。
比如deque有4段数据空间。有一个中控器,中控器存储着一组指针,每个指针指向1段数据空间的起始位置,如果中控制的空间慢了,会申请一块更大的数据空间,然后把所有的指针拷贝到新的空间中。
deque在首段数据空间和尾段数据空间满的情况下,会申请一块新的空间,附加到deque空间中,原来的首段数据空间变为第二段数据空间,原来的尾段数据空间变为倒数第二段数据空间,在首段数据空间和尾段数据空间为空的情况会把这段空间释放,从整个deque空间中移除,原来的第二段和导数第二段数据空间变为首段数据空间和尾段数据空间。
首段数据空间和尾段数据空间分别有3个迭代器。
首段数据空间中first指针指向首段数据空间的起始位置,last指针指向首段数据空间的结束位置,cur指针指向首段数据空间第一个有效元素,由于在删除插入过程中,首段数据空间的前面若干个元素可能为空。
尾段数据空间中first指针指向尾段数据空间的起始位置,last指针指向尾段数据空间的结束位置,cur指针指向尾段数据空间的最后一个有效元素,由于在删除插入过程中,尾段数据空间后面几个元素可能为空。

15.3 容器适配器

面试题1:简述STL中容器适配器的概念

!!!难点:优先队列
(1)栈的特征是先进后出,后进先出。栈适配器支持从栈顶插入删除和访问栈顶的元素。容器vector、list,deque都满足栈操作的条件,因此都能作为栈适配器的底层容器,STL默认使用deque作为栈适配器的底层容器。
(2)队列的特征是先进先出,后进后出。因此队列适配器应该支持从队头删除元素,队尾插入元素以及访问队头队尾元素的操作。vector在删除首元素时需要移动所有元素,因此不能作为队列适配器的底层容器,应该选用list或者deque,STL默认使用deque作为队列适配器的底层容器。
(3)优先队列适配器和队列适配器一样,一端插入元素,一端删除元素。但是优先队列适配器在元素中加入权重的概念。插入元素时根据元素的权重进行插入到指定的位置,删除元素时删除权重最高的元素。
优先队列需要随机访问元素,所以list不能作为底层容器,deque也不太适合,STL默认使用vector作为优先队列的底层容器。(背后的机理先不看。)

面试题2:自定义优先队列的元素权重

!!!难点:函数对象的概念:21天学习C++P321 实现operator()的类的对象
优先队列自定义权重比较算法通过函数对象实现。
自己写程序了。

15.4 关联容器

(1)关联容器中的元素的键必须是可比较的,如果键是基本类型,那么可以直接使用,如果键是自定义类型,那么需要自己定义带有比较谓词(实现operator()的类)才能作为关联容器的类型参数。
用于标准模板库算法的函数对象可以分为1元函数和二元函数。实现operator()的类的对象。参考21天C++ P321
(2)可以用下标操作符访问map中的元素。map的下标是键,也可以通过下标运算符给map中添加元素。
(3)set中的每个元素只包含一个键。
(4)multiset、multimap与set、map的区别在于允许重复的键。


15程序员面试笔记之模板与泛型编程_第1张图片
QQ图片20180626113121.jpg

15程序员面试笔记之模板与泛型编程_第2张图片
QQ图片20180626113143.jpg
面试题1:迭代器失效的问题

(1)vector的删除操作都会导致迭代器失效。因为如果删除vector中的元素,其他元素都会移动。
(2)list操作不会导致迭代器失效。
(3)deque的删除操作都会导致迭代器失效。
(4)set和map的删除操作不会导致迭代器失效,删除操作只会导致被删除元素的迭代器失效。
(5)erase函数在删除元素后会返回被删除元素的后继元素的迭代器。

15.4 智能指针

智能指针和常规指针:
程序员必须手动释放自己申请的动态内存,否则会造成内存泄漏。为了解决令人头疼的内存泄漏问题,STL引入智能指针。
智能指针通过重载->和*操作符使得智能指针和常规指针的操作相同,通过析构函数释放指针指向的内存空间,这样就无需进行手动释放。
unique_ptr:独享指针,唯一拥有所指对象的所有权,不支持拷贝和赋值操作。
shared_ptr:共享指针,多个指针可以指向同一个对象,有统计指向同一个对象的智能指针的个数。
weak_ptr:弱指针,可以与shared_ptr指向同一个对象,但是不改变计数值。
auto_ptr:已被抛弃。

面试题1:简述环状引用问题及其解决方案

对象a调用析构函数的前提是指向a的智能指针的计数(!!!)为0,才能结束a的数据成员。
对象b调用析构函数的前提是指向b的智能指针的计数(!!!)为0,才能结束b的数据成员。
两个进行相互缠绕。

面试题2:unique_ptr优于auto_ptr的原因

(1)unique_ptr不支持赋值操作
auto_ptr支持赋值操作,但是这里的赋值是将指针指向对象的所有权转移到另一个auto_ptr指针,原指针失去对原对象的所有权之后变为一个空指针。如果后序使用这个空指针会引发问题。
(2)auto_ptr不能作为容器元素。容器的对象需要支持拷贝构造函数。拷贝构造函数的参数是为const类型,不能改变,而auto_ptr在赋值之后肯定会修改参数的值,需要将参数中的指针置空,避免两个auto_ptr指向同一个对象,而unique_ptr解决了这个问题。
比如vector > vs;//允许
(3)auto_ptr不适用于动态数组,释放动态数组需要用delete[]进行释放数组中所有元素的空间,而auto_ptr释放对象时默认使用delete,只会释放动态数组首元素的空间,造成内存泄漏。而unique_ptr在释放对象时,会正确使用delete[]释放整个动态数组中所有元素的空间。

你可能感兴趣的:(15程序员面试笔记之模板与泛型编程)