C++面经(4)(牛客)

1. 请说说STL的基本组成部分?
STL是标准模板库(Standard Template Library),简单来说就是一些常用数据结构和算法模板的集合。
广义上讲:STL分为三类:Algorithm(算法),Container(容器)和Iterator(迭代器),容器和算法通过迭代器可以进行无缝地连接。
详细的说:STL由6部分组成:容器(Container)、算法(Algorithm)、迭代器(Iterator)、仿函数(Function object)、适配器(Adaptor)、空间配制器(Allocator)。

  • 容器(Container):容器是一种数据结构,如list,vector和deque(双端队列)等,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器。
  • 算法(Algorithm):是用来操作容器中数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与它们操作的数据的结构和类型无关,因此它们可以用于从简单数组到高度复杂的容器的任何数据结构上。
  • 迭代器(Iterator):提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。除此之外,迭代器也可以是那些定义了operator*()(重载指针符号)以及其它类似于指针的操作的类对象。
  • 仿函数(Function):仿函数又称之为函数对象。本质就是类重载了一个operator(),创建一个行为类似函数的对象。
  • 适配器(Adaptor):简单的说就是一种接口类,专门用来修改现有类的接口,提供一种新的接口;调用现有的函数来实现所需要的功能。主要包括3种适配器Container Adaptor、Iterator Adaptor、Function Adaptor。
  • 空间配制器(Allocator):为STL提供空间配置的系统。其中主要工作包括两部分:对象的创建与销毁;内存的获取与释放。

2. 请说说STL种常见的容器?
容器可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构,都是模板类,分为顺序容器、关联式容器、容器适配器三种类型,三种类型容器特性分别如下:

  • 顺序容器
    容器并非排序的,元素的插入位置同元素的值无关。包含vector、deque、list等,具体实现如下:
    (1)vector 头文件 < vector >
    动态数组。元素在内存连续存放,随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能。
    (2)deque 头文件 < deque >
    双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(仅此于vector)【根据数据结构的学习,个人认为这里可以实现随机存取是因为双向队列底层也是数组】。在两端增删元素具有极佳的性能。
    (3)list 头文件 < list >
    双向链表。元素在内存不是连续存放,在任何位置增删元素都能在常数时间完成。不支持随机存取。

  • 关联式容器
    元素是排序的;插入任何元素,都按相应的排序规则来确定其位置;查找时具有非常好的性能;通常以平衡二叉树的方式实现。包含set、multiset、map、multimap等,具体实现如下:
    (1)set/multiset 头文件 < set >
    set即集合。set种不允许相同元素,multiset种允许存在相同元素。
    (2)map/multimap 头文件< map >
    map与set的不同在于map中存放的元素是键值对,一个名为first,另一个名为second,根据first值对元素从小到大排序,并可快速地根据first来检索元素。map同multimap的不同在于是否允许相同first值来检索元素,map不可以,multimap可以。

  • 容器适配器
    封装了一些基本的容器,使之具备了新的函数功能,比如把deque封装一下变为一个具有stack功能的数据结构。新得到的数据结构就叫适配器。包含stack、queue、priority_queue等,具体实现如下:
    (1)stack 头文件< stack >
    栈的删除、检索和修改的项只能是最后插入序列的项(栈顶)。后进先出。
    (2)queue 头文件< queue >
    队列的插入只能在尾部进行,删除、检索和修改只允许从头部进行。先进先出。
    (3)priority_queue 头文件< queue >
    优先级队列。内部维持某种有序,然后确保优先级最高的元素总是位于头部。最高优先级元素总是第一个出列。

  • 说说STL中map、hashtable、deque、list的实现原理
    map、hashtable、deque、list实现机理分别是红黑树、函数映射、双向队列、双向链表、它们的特性分别如下:

  • map实现原理
    map内部实现了一个红黑树(红黑树是非严格平衡的二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树有自动排序的功能,因此map内部所有元素都是有序的,红黑树的每一个结点都代表着map的一个元素。因此map进行的查找、删除、添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉树(二叉查找树、二叉排序树)存储的,特点就是左子树的所有节点的键值【不是键值对的键值】都小于根节点的键值,右子树所有节点的键值都大于根节点的键值。使用中序遍历可以将键值按照从小到大遍历出来。

  • hashtable(散列表、哈希表)实现原理
    hashtable采用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够快速地进行查找。这决定了哈希表特殊的数据结构,它同数组、链表以及二叉排序树等相比较有明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在记录的关键字进行比较来进行查找。

  • deque实现原理
    deque内部实现的是一个双向队列。元素在内存连续存放。随机存取任何元素都在常数时间完成。所有适合vector的操作都适用于deque。在两端增删元素具有极佳的性能。

  • list实现原理
    list内部实现的是一个双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。给定一个下标i,访问第i个元素的内容,只能从头部挨个遍历到第i个元素。

4. 说说vector和list的区别,分别适用于什么场景?
vector和list区别在于底层实现机理不同,因而特性和适用场景也有所不同。
vector:一维数组
特点:元素在内存连续存放,动态数组,在堆中分配内存,有保留内存,如果减少大小后内存也不会释放。

  • 优点:和数组一样开辟一段连续的空间,并且支持随机访问,所以它的查找效率高,时间复杂度为O(1)
  • 缺点:由于开辟一段连续的空间,所以插入删除会需要对数据进行移动,时间复杂度为O(n),另外当空间不足时需要扩容。

list:双向链表
特点:元素在堆中存放,每个元素都是存放在一块内存中,它的内存空间可以是不连续的,通过指针来进行数据访问。

  • 优点:底层实现是循环双链表,当对大量数据进行插入删除时,其时间复杂度为O(1)
  • 缺点:底层没有连续的空间,只能通过指针来进行访问,所以查找数据需要遍历O(n)

应用场景:
vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随机访问而不在乎插入删除的效率,使用vector。
list拥有一段不连续的内存空间,如果需要高效的插入和删除而不关心随机访问,应该使用list。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值