五、2023.10.1.C++stl.5

文章目录

  • 65、请说说 STL 的基本组成部分?
  • 66、请说说 STL 中常见的容器,并介绍一下实现原理?
  • 67、请说说 STL 中常见的容器,并介绍一下实现原理?
  • 68、请你来介绍一下 STL 的空间配置器(allocator)?
  • 69、请你来介绍一下 STL 的空间配置器(allocator)?
  • 70、迭代器用过吗?什么时候会失效?
  • 71、说一下STL中迭代器的作用,有指针为何还要迭代器?
  • 72、说说 STL 迭代器是怎么删除元素的?
  • 73、说说 STL 中 resize 和 reserve 的区别?
  • 74、说说 STL 容器动态链接可能产生的问题?
  • 75、说说 map 和 unordered_map 的区别?底层实现?
  • 76、说说 vector 和 list 的区别,分别适用于什么场景?
  • 77、简述 vector 的实现原理?
  • 78、简述STL 中的 map 的实现原理?
  • 79、C++ 的 vector 和 list中,如果删除末尾的元素,其指针和迭代器如何变化?若删除的是中间的元素呢?
  • 80、 请你来说一下 map 和 set 有什么区别,分别又是怎么实现的?
  • 81、说说 push_back 和 emplace_back 的区别?
  • 82、STL 中 vector 与 list 具体是怎么实现的?常见操作的时间复杂度是多少?

65、请说说 STL 的基本组成部分?

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

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

66、请说说 STL 中常见的容器,并介绍一下实现原理?

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

  1. 顺序容器
    容器并非排序的,元素的插入位置同元素的值无关。包含vector、deque、list,具体实现原理如
    下:
    (1)vector 头文件
    动态数组。元素在内存连续存放。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能。
    (2)deque 头文件
    双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(仅次于vector)。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
    (3)list 头文件
    双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。

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

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

67、请说说 STL 中常见的容器,并介绍一下实现原理?

map、hashtable、deque、list实现机理分别为红黑树、函数映射、双向队列、双向链表,他们的特性分别如下:

  1. map实现原理
    map内部实现了一个红黑树(红黑树是非严格平衡的二叉搜索树,而AVL是严格平衡二叉搜索
    树),红黑树有自动排序的功能,因此map内部所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找、删除、添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉树(又名二叉查找树、二叉排序树)存储的,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值。使用中序历可将键值按照从小到大遍历出来。
  2. hashtable(也称散列表,直译作哈希表)实现原理
    hashtable采用了函数映射的思想记录的存储位置与记录的关键字关联起来,从而能够很快速地进
    行查找。这决定了哈希表特殊的数据结构,它同数组、链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找。
  3. deque实现原理
    deque内部实现的是一个双向队列。元素在内存连续存放。随机存取任何元素都在常数时间完成(仅次于vector)。所有适用于vector的操作都适用于deque。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
  4. list实现原理
    list内部实现的是一个双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。无成员函数,给定一个下标i,访问第i个元素的内容,只能从头部挨个遍历到第i个元素。

68、请你来介绍一下 STL 的空间配置器(allocator)?

一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系。
在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间)分配的工具,他与容器联系紧密,每一种容器的空间分配都是通过空间分配器alloctor实现的

  1. 两种C++类对象实例化方式的异同
    在c++中,创建类对象一般分为两种方式:一种是直接利用构造函数,直接构造类对象,如 Testtest();另一种是通过new来实例化一个类对象,如 Test *pTest = new Test;那么,这两种方式有
    什么异同点呢?
    我们知道,内存分配主要有三种方式:
    (1) 静态存储区分配:内存在程序编译的时候已经分配好,这块内存在程序的整个运行空间内都存在。如全局变量,静态变量等。
    (2) 栈空间分配:程序在运行期间,函数内的局部变量通过栈空间来分配存储(函数调用栈),当函数执行完毕返回时,相对应的栈空间被立即回收。主要是局部变量。
    (3)堆空间分配:程序在运行期间,通过在堆空间上为数据分配存储空间,通过malloc和new创建的对象都是从堆空间分配内存,这类空间需要程序员自己来管理,必须通过free()或者是delete()函数对堆空间进行释放,否则会造成内存溢出。
    那么,从内存空间分配的角度来对这两种方式的区别,就比较容易区分:
    (1)对于第一种方式来说,是直接通过调用Test类的构造函数来实例化Test类对象的,如果该实例化对象是一个局部变量,则其是在栈空间分配相应的存储空间。
    (2)对于第二种方式来说,就显得比较复杂。这里主要以new类对象来说明一下。new一个类对象,其实是执行了两步操作:首先,调用new在堆空间分配内存,然后调用类的构造函数构造对象的内容;同样,使用delete释放时,也是经历了两个步骤:首先调用类的析构函数释放类对象,然后调
    用delete释放堆空间。
  2. C++ STL空间配置器实现
    很容易想象,为了实现空间配置器,完全可以利用new和delete函数并对其进行封装实现STL的空间配置器,的确可以这样。但是,为了最大化提升效率,SGI STL版本并没有简单的这样做,而是采取了一定的措施,实现了更加高效复杂的空间分配策略。由于以上的构造都分为两部分,所以,在SGI STL中,将对象的构造切分开来,分成空间配置和对象构造两部分。
内存配置操作: 通过alloc::allocate()实现
内存释放操作: 通过alloc::deallocate()实现
对象构造操作: 通过::construct()实现
对象释放操作: 通过::destroy()实现

关于内存空间的配置与释放,SGI STL采用了两级配置器:一级配置器主要是考虑大块内存空间,利用malloc和free实现;二级配置器主要是考虑小块内存空间而设计的(为了最大化解决内存碎片问题,进而提升效率),采用链表free_list来维护内存池(memory pool),free_list通过union结构实现,空闲的内存块互相挂接在一块,内存块一旦被使用,则被从链表中剔除,易于维护。

69、请你来介绍一下 STL 的空间配置器(allocator)?

STL中常用的容器有vector、deque、list、map、set、multimap、multiset、unordered_map、
unordered_set等。容器底层实现方式及时间复杂度分别如下:

  1. vector
    采用一维数组实现,元素在内存连续存放,不同操作的时间复杂度为:
    插入: O(N)
    查看: O(1)
    删除: O(N)
  2. deque
    采用双向队列实现,元素在内存连续存放,不同操作的时间复杂度为:
    插入: O(N)
    查看: O(1)
    删除: O(N)
  3. list
    采用双向链表实现,元素存放在堆中,不同操作的时间复杂度为:
    插入: O(1)
    查看: O(N)
    删除: O(1)
  4. map、set、multimap、multiset
    上述四种容器采用红黑树实现,红黑树是平衡二叉树的一种。不同操作的时间复杂度近似为:
    插入: O(logN)
    查看: O(logN)
    删除: O(logN)
  5. unordered_map、unordered_set、unordered_multimap、 unordered_multiset
    上述四种容器采用哈希表实现,不同操作的时间复杂度为:
    插入: O(1),最坏情况O(N)
    查看: O(1),最坏情况O(N)
    删除: O(1),最坏情况O(N)
    注意:容器的时间复杂度取决于其底层实现方式。

70、迭代器用过吗?什么时候会失效?

用过,常用容器迭代器失效情形如下。

  1. 对于序列容器vector,deque来说,使用erase后,后边的每个元素的迭代器都会失效,后边每个元素都往前移动一位,erase返回下一个有效的迭代器
  2. 对于关联容器map,set来说,使用了erase后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素,不会影响下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可
  3. 对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的迭代器,因此上面两种方法都可以使用。

71、说一下STL中迭代器的作用,有指针为何还要迭代器?

  1. 迭代器的定义:提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++ 的指针也是一种迭代器。 但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符方法的类对象;
  2. 迭代器的作用
    (1)用于指向顺序容器和关联容器中的元素
    (2)通过迭代器可以读取它指向的元素
    (3)通过非const迭代器还可以修改其指向的元素
  3. 迭代器和指针的区别
    迭代器不是指针,是类模板,表现的像指针。他只是模拟了指针的一些功能,重载了指针的一些操作符,–>、++、–等。迭代器封装了指针,是一个”可遍历STL( Standard Template Library)容器内全部或部分元素”的对象,本质是封装了原生指针,是指针概念的一种提升,提供了比指针更高级的行为,相当于一种智能指针,他可以根据不同类型的数据结构来实现不同的++,–等操作。迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用取值后的值而不能直接输出其自身。
  4. 迭代器产生的原因
    Iterator类的访问方式就是把不同集合类的访问逻辑抽象出来,使得不用暴露集合内部的结构而达到循环遍历集合的效果。
    具体:
  5. 迭代器
    Iterator(迭代器)模式又称游标(Cursor)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。 或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。 由于Iterator模式的以上特性:与聚合对象耦合,在一定程度上限制了它的广泛运用,一般仅用于底层聚合支持类,如STL的list、vector、stack等容器类及ostream_iterator等扩展Iterator。
    例子:
#include <vector>
#include <iostream>
using namespace std;
int main() {vector<int> v; //一个存放int元素的数组,一开始里面没有元素v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::const_iterator i; //常量迭代器for (i = v.begin(); i != v.end(); ++i) //v.begin()表示v第一个元素迭代器指针,++i指向下一个元素cout << *i << ","; //*i表示迭代器指向的元素cout << endl;vector<int>::reverse_iterator r; //反向迭代器for (r = v.rbegin(); r != v.rend(); r++)cout << *r << ",";cout << endl;vector<int>::iterator j; //非常量迭代器for (j = v.begin();j != v.end();j++)*j = 100;for (i = v.begin();i != v.end();i++)cout << *i << ",";return 0;
}
/* 运行结果:
1,2,3,4,
4,3,2,1,
100,100,100,100,
*/

72、说说 STL 迭代器是怎么删除元素的?

这是主要考察迭代器失效的问题。

  1. 对于序列容器vector,deque来说,使用erase后,后边的每个元素的迭代器都会失效,后边每个元素都往前移动一位,erase返回下一个有效的迭代器;
  2. 对于关联容器map,set来说,使用了erase后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素,不会影响下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可
  3. 对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的迭代器,因此上面两种方法都可以使用。
    在这里插入图片描述

73、说说 STL 中 resize 和 reserve 的区别?

  1. 首先必须弄清楚两个概念:
    (1)capacity:该值在容器初始化时赋值,指的是容器能够容纳的最大的元素的个数。还不能通过下标等访问,因为此时容器中还没有创建任何对象。
    (2)size:指的是此时容器中实际的元素个数。可以通过下标访问0-(size-1)范围内的对象。
  2. resize和reserve区别主要有以下几点:
    (1)resize既分配了空间,也创建了对象;reserve表示容器预留空间,但并不是真正的创建对象,需要通过insert()或push_back()等创建对象。
    (2)resize既修改capacity大小,也修改size大小;reserve只修改capacity大小,不修改size大小。
    (3)两者的形参个数不一样。 resize带两个参数,一个表示容器大小,一个表示初始值(默认为0);reserve只带一个参数,表示容器预留的大小。

问题延伸:
resize 和 reserve 既有差别,也有共同点。两个接口的共同点是它们都保证了vector的空间大小(capacity)最少达到它的参数所指定的大小。下面就他们的细节进行分析。
为实现resize的语义,resize接口做了两个保证:
(1)保证区间[0, new_size)范围内数据有效,如果下标index在此区间内,vector[indext]是合法的;
(2)保证区间[0, new_size)范围以外数据无效,如果下标index在区间外,vector[indext]是非法的。
而: reserve只是保证vector的空间大小(capacity)最少达到它的参数所指定的大小n。在区间[0, n)范围内,如果下标是index,vector[index]这种访问有可能是合法的,也有可能是非法的,视具体情况而定。

74、说说 STL 容器动态链接可能产生的问题?

  1. 可能产生的问题
    容器是一种动态分配内存空间的一个变量集合类型变量。在一般的程序函数里,局部容器,参数传递容器,参数传递容器的引用,参数传递容器指针都是可以正常运行的,而在动态链接库函数内部使用容器也是没有问题的,但是给动态库函数传递容器的对象本身,则会出现内存堆栈破坏的问题。
  2. 产生问题的原因
    容器和动态链接库相互支持不够好,动态链接库函数中使用容器时,参数中只能传递容器的引用,并且要保证容器的大小不能超出初始大小,否则导致容器自动重新分配,就会出现内存堆栈破坏问题。

75、说说 map 和 unordered_map 的区别?底层实现?

map和unordered_map的区别在于他们的实现基理不同。

  1. map实现机理
    map内部实现了一个红黑树(红黑树是非严格平衡的二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树有自动排序的功能,因此map内部所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找、删除、添加等一系列的操作都相当于是对红黑树进行的操作,map中的元素是按照二叉树(又名二叉查找树、二叉排序树)存储的,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值。使用中序遍历可将键值按照从小到大遍历出来。
  2. unordered_map实现机理
    unordered_map内部实现了一个哈希表(也叫散列表),通过把关键码值映射到Hash表中一个位置来访问记录,查找时间复杂度可达O(1),其中在海量数据处理中有着广泛应用。因此,元素的排列顺序是无序的。

76、说说 vector 和 list 的区别,分别适用于什么场景?

vector和list区别在于底层实现机理不同,因而特性和适用场景也有所不同。

  1. vector:一维数组
    特点:元素在内存连续存放,动态数组,在堆中分配内存,元素连续存放,有保留内存,如果减少大小
    后内存也不会释放。
    优点:和数组类似开辟一段连续的空间,并且支持随机访问,所以它的查找效率高其时间复杂度O(1)。
    缺点:由于开辟一段连续的空间,所以插入删除会需要对数据进行移动比较麻烦,时间复杂度O(n),另外当空间不足时还需要进行扩容。

  2. list:双向链表
    特点:元素在堆中存放,每个元素都是存放在一块内存中,它的内存空间可以是不连续的,通过指针来
    进行数据的访问。
    优点:底层实现是循环双链表,当对大量数据进行插入删除时,其时间复杂度O(1)。
    缺点:底层没有连续的空间,只能通过指针来访问,所以查找数据需要遍历其时间复杂度O(n),没
    有提供[]操作符的重载

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

77、简述 vector 的实现原理?

vector底层实现原理为一维数组(元素在空间连续存放)。

  1. 新增元素
    Vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素。插入新的数据分在最后插入push_back和通过迭代器在任何位置插入,这里说一下通过迭代器插入,通过迭代器与第一个元素的距离知道要插入的位置,即int index=iter-begin()。这个元素后面的所有元素都向后移动一个位置,在空出来的位置上存入新增的元素。

78、简述STL 中的 map 的实现原理?

map是关联式容器,它们的底层容器都是红黑树。map 的所有元素都是 pair,同时拥有实值(value)和键值(key)。pair 的第一元素被视为键值,第二元素被视为实值。所有元素都会根据元素的键值自动被排序。不允许键值重复。
map的特性如下
(1)map以RBTree作为底层容器;
(2)所有元素都是键+值存在;
(3)不允许键重复;
(4)所有元素是通过键进行自动排序的;
(5)map的键是不能修改的,但是其键对应的值是可以修改的。

79、C++ 的 vector 和 list中,如果删除末尾的元素,其指针和迭代器如何变化?若删除的是中间的元素呢?

  1. 迭代器和指针之间的区别
    **迭代器不是指针,是类模板,表现的像指针。他只是模拟了指针的一些功能,重载了指针的一些操作符,–>、++、–等。迭代器封装了指针,是一个”可遍历STL( Standard Template Library)容器内全部或部分元素”的对象,本质是封装了原生指针,是指针概念的一种提升,提供了比指针更高级的行为,相当于一种智能指针,他可以根据不同类型的数据结构来实现不同的++,–等操作。**迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用取值后的值而不能直接输出其自身。
  2. vector和list特性
    vector特性 动态数组。元素在内存连续存放。随机存取任何元素都在常数时间完成。在尾端增删元素具有较大的性能(大部分情况下是常数时间)。list特性双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。
  3. vector增删元素
    对于vector而言,删除某个元素以后,该元素后边的每个元素的迭代器都会失效,后边每个元素都往前移动一位,erase返回下一个有效的迭代器。
  4. list增删元素
    对于list而言,删除某个元素,只有“指向被删除元素”的那个迭代器失效,其它迭代器不受任何影响。

80、 请你来说一下 map 和 set 有什么区别,分别又是怎么实现的?

  1. set是一种关联式容器,其特性如下:
    (1)set以RBTree作为底层容器
    (2)所得元素的只有key没有value,value就是key
    (3)不允许出现键值重复
    (4)所有的元素都会被自动排序
    (5)不能通过迭代器来改变set的值,因为set的值就是键,set的迭代器是const的
  2. map和set一样是关联式容器,其特性如下:
    (1)map以RBTree作为底层容器
    (2)所有元素都是键+值存在
    (3)不允许键重复
    (4)所有元素是通过键进行自动排序的
    (5)map的键是不能修改的,但是其键对应的值是可以修改的
    综上所述,map和set底层实现都是红黑树;map和set的区别在于map的值不作为键,键和值是分
    开的。

81、说说 push_back 和 emplace_back 的区别?

如果要将一个临时变量push到容器的末尾,push_back()需要先构造临时对象,再将这个对象拷贝到容
器的末尾,而emplace_back()则直接在容器的末尾构造对象,这样就省去了拷贝的过程。

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
class A {
public:A(int i){str = to_string(i);cout << "构造函数" << endl;
}~A(){}A(const A& other): str(other.str){cout << "拷贝构造" << endl;}
public:
string str;
};
int main() {
vector<A> vec;
vec.reserve(10);for(int i=0;i<10;i++){vec.push_back(A(i)); //调用了10次构造函数和10次拷贝构造函数,
// vec.emplace_back(i); //调用了10次构造函数一次拷贝构造函数都没有调用过return 0;
}

82、STL 中 vector 与 list 具体是怎么实现的?常见操作的时间复杂度是多少?

  1. vector 一维数组(元素在内存连续存放)
    是动态数组,在堆中分配内存,元素连续存放,有保留内存,如果减少大小后,内存也不会释放;如果新增大小当前大小时才会重新分配内存。
    扩容方式:
    a. 倍放开辟三倍的内存
    b. 旧的数据开辟到新的内存
    c. 释放旧的内存
    d. 指向新内存
  2. list 双向链表(元素存放在堆中)
    元素存放在堆中,每个元素都是放在一块内存中,它的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点,使得它的随机存取变得非常没有效率,因此它没有提供[ ]操作符的重载。但是由于链表的特点,它可以很有效的支持任意地方的删除和插入操作。
    特点:
    a. 随机访问不方便
    b. 删除插入操作方便
  3. 常见时间复杂度
    (1)vector插入、查找、删除时间复杂度分别为:O(n)、O(1)、O(n);
    (2)list插入、查找、删除时间复杂度分别为:O(1)、O(n)、O(1)。

国庆快乐!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/146460.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式并行训练(DP、DDP、DeepSpeed)

[pytorch distributed] 01 nn.DataParallel 数据并行初步 数据并行 vs. 模型并行 数据并行&#xff1a;模型拷贝&#xff08;per device&#xff09;&#xff0c;数据 split/chunk&#xff08;对batch切分&#xff09; 每个device上都拷贝一份完整模型&#xff0c;每个device分…

密码技术 (5) - 数字签名

一. 前言 前面在介绍消息认证码时&#xff0c;我们知道消息认证码虽然可以确认消息的完整性&#xff0c;但是无法防止否认问题。而数字签名可以解决否认的问题&#xff0c;接下来介绍数字签名的原理。 二. 数字签名的原理 数字签名和公钥密码一样&#xff0c;也有公钥和私钥&am…

字符串函数(一)

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;进阶C语言 字符串函数&#xff08;一&#xff09; 0.前言1.求字符串长度的函数1.1 strlen&#xff08;字符串长度&#xff09; 2.长度不受限制的字符串函数2.1 strcpy&#xff08;字符串拷贝&#xff0…

直播协议 python 常见直播协议

1. 推流、直播 和 点播分别是什么意思&#xff1f; 推流 主播将本地视频源和音频源推送到云服务器&#xff0c;也被称为“RTMP发布”。 直播 即直接观看主播实时推送过来的音视频数据。 点播 视频源已经事先存储于云服务器之上的音视频文件&#xff0c;观众随时可以观看。 目…

怒刷LeetCode的第22天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;回溯算法 方法二&#xff1a;基于位运算的回溯 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;动态规划 方法二&#xff1a;分治法 方法三&#xff1a;前缀和数组 第三题 题目来源 题目内容…

Acwing 842. 排列数字

Acwing 842. 排列数字 知识点题目描述思路讲解代码展示 知识点 DFS 题目描述 思路讲解 DFS重点是&#xff1a;顺序&#xff01;&#xff08;暴力的手法&#xff09;&#xff08;递归&#xff09; 用 path 数组保存排列&#xff0c;当排列的长度为 n 时&#xff0c;是一种方…

【Leetcode】 17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits "23" 输出&…

Java笔记五(数组)

目录 数组 数组声明创建 数组初始化的三种初始化类型&#xff1a; 静态初始化 动态初始化 数组的默认初始化 数组的四个基本特点 数组边界 数组的使用 示例一&#xff1a;计算所有的元素和以及查找最大元素 示例二&#xff1a;For-Each循环 示例三&#xff1a;数组作…

Ubuntu 安装 Docker 的详细步骤

文章目录 简介1.更新2.安装必要的软件包2.1 基于阿里源 3.验证 Docker 安装是否成功4.安装后的一些常规设置及常用的命令4.1 启动 Docker4.2 Docker 在系统启动时自动运行4.3 运行一个 Hello World 镜像4.4 查看docker运行状态 欢迎来到这篇关于在 Ubuntu 上安装 Docker 的教程…

鞋类 整鞋试验方法 剥离强度

声明 本文是学习GB-T 3903.3-2011 鞋类 整鞋试验方法 剥离强度. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 GB/T 3903 的本部分规定了整鞋鞋底与鞋帮或外底与外中底之间剥离强度的试验方法。 本部分适用于采用模压、硫化、注塑、灌注、胶…

【c++随笔07】常量、变量、static

【c随笔07】常量、变量、static 1、常量、变量1.1、声明变量1.2、使用常量 2、static介绍2.1、static 局部变量2.2、static 全局变量2.3、C static静态成员变量2.4、C static静态成员函数详解 原创地址&#xff0c;https://zhengjunxue.blog.csdn.net/article/details/13167770…

【数据结构】——顺序表详解

大家好&#xff01;当我们学习了动态内存管理后&#xff0c;就可以写一个管理数据的顺序表了&#xff01;&#xff01;&#xff01; 顺序表的理解&#xff1a; 线性表是最基本、最简单、也是最常用的一种数据结构。线性表&#xff08;linear list&#xff09;是数据结构的一种…

02-Zookeeper实战

上一篇&#xff1a;01-Zookeeper特性与节点数据类型详解 1. zookeeper安装 Step1&#xff1a; 配置JAVA环境&#xff0c;检验环境&#xff1a; java -versionStep2: 下载解压 zookeeper wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.8/apache-zookeepe…

响应式设计的实现方式

一. 什么是响应式 响应式网站设计是一种网络页面设计布局。页面的设计与开发应当根据用户行为以及设备环境&#xff08;系统平台&#xff0c;屏幕尺寸&#xff0c;屏幕定向等&#xff09;进行相应的响应和调整。 响应式网站常见特点&#xff1a; 1. 同时适配PC平板手机。 2…

Win10自带输入法怎么删除-Win10卸载微软输入法的方法

Win10自带输入法怎么删除&#xff1f;Win10系统自带输入法就是微软输入法&#xff0c;这个输入法满足了很多用户的输入需求。但是&#xff0c;有些用户想要使用其它的输入法&#xff0c;这时候就想删除掉微软输入法。下面小编给大家介绍最简单方便的卸载方法吧。 Win10卸载微软…

Hive【Hive(三)查询语句】

前言 今天是中秋节&#xff0c;早上七点就醒了&#xff0c;干啥呢&#xff0c;大一开学后空教室紧缺&#xff0c;还不趁着假期来学校等啥呢。顺便偷偷许个愿吧&#xff0c;希望在明年的这个时候&#xff0c;秋招不知道赶不赶得上&#xff0c;我希望拿几个国奖&#xff0c;蓝桥杯…

淘宝天猫复制商品链接粘贴到草柴查优惠券iPhone苹果手机粘贴弹窗怎么关闭?

经常在淘宝、天猫、京东网购&#xff0c;挑选商品后复制链接&#xff0c;到草柴APP查询要购买商品的优惠券和返利&#xff0c;iPhone苹果手机每次粘贴复制的商品链接都弹窗提示特别烦人。接下来分享如何关闭草柴APP复制粘贴提醒的弹窗&#xff1b; 如何永久关闭iPhone苹果手机复…

去雨去雪去雾算法之本地与服务器的TensorBoard使用教程

在进行去雨去雾去雪算法实验时&#xff0c;需要注意几个参数设置&#xff0c;num_workers只能设置为0&#xff0c;否则会报各种稀奇古怪的错误。 本地使用TensorBoard 此外&#xff0c;发现生成的文件是events.out.tfevents格式的&#xff0c;查询了一番得知该文件是通过Tens…

28294-2012 钢渣复合料 课堂随笔

声明 本文是学习GB-T 28294-2012 钢渣复合料. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了混凝土用钢渣复合料的术语和定义、原材料组成及要求、强度等级、技术要求、试验方 法、检验规则、包装、标识、运输与贮存。 本标准…

解决内网拉取企微会话存档代理问题的一种办法

问题&#xff1a;客户的服务都是内网的&#xff0c;不能直接访问外网&#xff1b;访问外网的话需要走kong网关才能出去。 会话存档官网说可以使用socket5、http方式拉取会话存档&#xff1b;我这边尝试了直接使用kong网关的ip和端口配置进去&#xff0c;是访问不了的 我后面就…