欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

后台开发面试C++(STL)

程序员文章站 2022-06-13 12:29:58
...

目录

map和set有什么区别,分别又是怎么实现的

STL有什么基本组成

STL中map与multimap

vector和list的区别,应用,越详细越好

1)Vector

2)List

vector,list区别

请你来说一下STL中迭代器的作用,有指针为何还要迭代器

vector中size()和capacity()取值

Vector的reserve和resize详解


map和set有什么区别,分别又是怎么实现的

map和set都是C++的关联容器,其底层实现都是红黑树(RB-Tree)

map和set区别在于:

(1)map中的元素是key-value(关键字—值)对儿   set与之相对就是关键字的简单集合

(2)set的迭代器是const的,不允许修改元素的值;map允许修改value,但不允许修改key。

(3)map支持下标操作,set不支持下标操作。

STL有什么基本组成

后台开发面试C++(STL)
他们之间的关系:分配器给容器分配存储空间,算法通过迭代器获取容器中的内容,仿函数可以协助算法完成各种操作,配接器用来套接适配仿函数 

STL中map与multimap

  map Multimap
映射 Map映射, 所有元素都会根据元素的键值自动被排序。 多重映射。所有元素都会根据元素的键值自动被排序。
底层实现 红黑树 红黑树
适用场景 有序键值对不重复映射 有序键值对可重复映射

vector和list的区别,应用,越详细越好

1)Vector

连续存储的容器,动态数组,在堆上分配空间

底层实现:数组

两倍容量增长:

vector 增加(插入)新元素时,如果未超过当时的容量,则还有剩余空间,那么直接添加到最后(插入指定位置),然后调整迭代器。
如果没有剩余空间了,则会重新配置原有元素个数的两倍空间,然后将原空间元素通过复制的方式初始化新空间,再向新空间增加元素,最后析构并释放原空间,之前的迭代器会失效。
访问:O(1)

插入:在最后插入(空间够):很快

在最后插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝。
在中间插入(空间够)    :内存拷贝
在中间插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝。
删除:在最后删除:很快

在中间删除:内存拷贝
适用场景:经常随机访问,且不经常对非尾节点进行插入删除。

2)List

动态链表,在堆上分配空间,每插入一个元数都会分配空间,每删除一个元素都会释放空间。
底层:双向链表
访问:随机访问性能很差,只能快速访问头尾节点。
插入:很快,一般是常数开销
删除:很快,一般是常数开销
适用场景:经常插入删除大量数据

vector,list区别

1)vector底层实现是数组;list是双向链表。
2)vector支持随机访问,list不支持。
3)vector是顺序内存,list不是。
4)vector在中间节点进行插入删除会导致内存拷贝,list不会。
5)vector一次性分配好内存,不够时才进行2倍扩容;list每次插入新节点都会进行内存申请。
6)vector随机访问性能好,插入删除性能差;list随机访问性能差,插入删除性能好。

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


请你来说一下STL中迭代器的作用,有指针为何还要迭代器

迭代器不是指针,是类模板,表现的像指针。

本质是封装了原生指针,是指针概念的一种提升(lift),提供了比指针更高级的行为,相当于一种智能指针,他可以根据不同类型的数据结构来实现不同的++,--等操作。

迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身。


vector中size()和capacity()取值

vector v;此时没有初始化,所以size()和capacity()都是0;

cout<<v.size()<<endl<<v.capacity()<<endl;
v.push_back(1);
cout<<v.size()<<endl<<v.capacity()<<endl;//此时容器内有一个元素了,那么size()和capacity()都是1
v.push_back(1);
cout<<v.size()<<endl<<v.capacity()<<endl;//此时容器内能够提供的空间capacity()不够用了,需要申请内容,申请多少呢,申请后的大小应该是以前的2倍,那就应该是2了,此时有两个元素,size()为2,capacity()也是2
v.push_back(1);
cout<<v.size()<<endl<<v.capacity()<<endl;//此时容器能够提供的空间是2,又增加元素,不够,需要申请空间,申请后的空间为原来2倍,就是4了,那么size()为3,capacity()为4
v.push_back(1);
cout<<v.size()<<endl<<v.capacity()<<endl;//容器还能够提供一个空间,不需要申请新空间,size()为4,capacity()为4
v.push_back(1);
cout<<v.size()<<endl<<v.capacity()<<endl;//空间不够,需要申请,size()为5,capacity为8

Vector的reserve和resize详解

vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!
原因如下:
      reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。

      resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。

      两个函数的参数形式也有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小, 第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。下面是这两个函数使用例子:

例子1:
vector<int> myVec;
myVec.reserve( 100 );     // 新元素还没有构造, 
                                       // 此时不能用[]访问元素
for (int i = 0; i < 100; i++ )
{ 
     myVec.push_back( i ); //新元素这时才构造
}
myVec.resize( 102 );      // 用元素的默认构造函数构造了两个新的元素
myVec[100] = 1;           //直接操作新元素
myVec[101] = 2;  
例子2:
#include <vector>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    vector<int> vect;
    vect.push_back(1);
    vect.push_back(2);
    vect.push_back(3);
    vect.push_back(4);
    vect.reserve(100);
    cout<<vect.size()<<endl;  //size为4,但是capacity为100
    int i = 0;
    for (i = 0; i < 104; i++)
    {
        cout<<vect[i]<<endl;
    }
    return 0;
}