C++面试总结(四)标准库

1.什么是标准库(STL)?

C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。

2.C++ 标准模板库的核心三个组件组成?

3.string

C++ 从 C 继承的字符串概念仍然是以 '\0' 为结束符的 char 数组。C++ 标准库中的 string class 可以将 string 作为一个型别,可以实现复制、赋值和比较,不必担心内存大小及占用内存实际长度等具体问题。

STL 中只有一个字符串类,即 basic_string。类 basic_string 实现管理以 \0 结尾的字符数组,字符类型由模板参数决定。要使用 string 类,必须包含头文件 <string>。在 STL 库中,basic_string 有两个预定义类型:包含 char 的 string 类型和包含 wchar 的 wstring 类型。

(1)string 类提供的各种操作函数大致分为八类:构造器和析构器、大小和容量、元素存取、字 符串比较、字符串修改、字符串接合、I/O 操作以及搜索和查找。

                                                                              string 类的所有成员函数

函数名称 功能
构造函数 产生或复制字符串
析构函数 销毁字符串
=,assign 赋以新值
Swap 交换两个字符串的内容
+ =,append( ),push_back() 添加字符
insert () 插入字符
erase() 删除字符
clear () 移除全部字符
resize () 改变字符数量
replace() 替换字符
+ 串联字符串
==,! =,<,<=,>,>=,compare() 比较字符串内容
size(),length() 返回字符数量
max_size () 返回字符的最大可能个数
empty () 判断字符串是否为空
capacity () 返回重新分配之前的字符容量
reserve() 保留内存以存储一定数量的字符
[],at() 存取单一字符
>>,getline() 从 stream 中读取某值
<< 将值写入 stream
copy() 将内容复制为一个 C - string
c_str() 将内容以 C - string 形式返回
data() 将内容以字符数组形式返回
substr() 返回子字符串
find() 搜寻某子字符串或字符
begin( ),end() 提供正向迭代器支持
rbegin(),rend() 提供逆向迭代器支持
get_allocator() 返回配置器

(2) string构造函数和析构函数详解

//构造函数
string strs //生成空字符串
string s(str) //生成字符串str的复制品
string s(str, stridx) //将字符串str中始于stridx的部分作为构造函数的初值
string s(str, strbegin, strlen) //将字符串str中始于strbegin、长度为strlen的部分作为字符串初值
string s(cstr) //以C_string类型cstr作为字符串s的初值
string s(cstr,char_len)    //以C_string类型cstr的前char_len个字符串作为字符串s的初值
strings(num, c) //生成一个字符串,包含num个c字符
strings(strs, beg, end)    //以区间[beg, end]内的字符作为字符串s的初值
//析构函数
~string() //销毁所有内存,释放内存
//注意,不能使用字符或者整数去初始化字符串。
std::string s('x');    //错误
std::string s("x");    //正确
std::string s(1, 'x');    //正确

(3)C++获取字符串长度详解

String 类型对象包括三种求解字符串长度的函数:size() 和 length()、 maxsize() 和 capacity():

  • size() 和 length():这两个函数会返回 string 类型对象中的字符个数,且它们的执行效果相同。
  • max_size():max_size() 函数返回 string 类型对象最多包含的字符数。一旦程序使用长度超过 max_size() 的 string 操作,编译器会拋出 length_error 异常。
  • capacity():该函数返回在重新分配内存之前,string 类型对象所能包含的最大字符数。

string 类型对象还包括一个 reserve() 函数。调用该函数可以为 string 类型对象重新分配内存。重新分配的大小由其参数决定。reserve() 的默认参数为 0。

(4)string获取字符串元素:[]和at()

字符串中元素的访问是允许的,一般可使用两种方法访问字符串中的单一字符:下标操作符[] 和 成员函数at()。两者均返回指定的下标位置的字符。第 1 个字符索引(下标)为 0,最后的字符索引为 length()-1。

需要注意的是,这两种访问方法是有区别的:

  • 下标操作符 [] 在使用时不检查索引的有效性,如果下标超出字符的长度范围,会示导致未定义行为。对于常量字符串,使用下标操作符时,字符串的最后字符(即 '\0')是有效的。对应 string 类型对象(常量型)最后一个字符的下标是有效的,调用返回字符 '\0'。
  • 函数 at() 在使用时会检查下标是否有效。如果给定的下标超出字符的长度范围,系统会抛出 out_of_range 异常。

(5)C++ string字符串比较方法详解

Basic_string 类模板既提供了  >、<、==、>=、<=、!= 等比较运算符,还提供了 compare() 函数,其中 compare() 函数支持多参数处理,支持用索引值和长度定位子串进行比较。该函数返回一个整数来表示比较结果。如果相比较的两个子串相同,compare() 函数返回 0,否则返回非零值。

4.容器

  容器是用来管理某一类对象的集合,包括序列式容器和关联式容器。

STL 中已经提供的容器主要如下:

  • vector <T>:一种向量。
  • list <T>:一个双向链表容器,完成了标准 C++ 数据结构中链表的所有功能。
  • queue <T>:一种队列容器,完成了标准 C++ 数据结构中队列的所有功能。
  • stack <T>:一种栈容器,完成了标准 C++ 数据结构中栈的所有功能。
  • deque <T>:双端队列容器,完成了标准 C++ 数据结构中栈的所有功能。
  • priority_queue <T>:一种按值排序的队列容器。
  • set <T>:一种集合容器。
  • multiset <T>:一种允许出现重复元素的集合容器。
  • map <key, val>:一种关联数组容器。
  • multimap <key, val>:一种允许出现重复 key 值的关联数组容器。

    序列式容器:vector,list,deque,queue,stack,priority_queue
    关联式容器:map,set

5.序列式容器的种类?

序列容器以线性序列的方式存储元素。它没有对元素进行排序,元素的顺序和存储它们的顺序相同。以下有5种标准的序列容器,每种容器都具有不同的特性:

  • array<T,N>(数组容器)是一个长度固定的序列,有 N 个 T 类型的对象,不能增加或删除元素
  • vector<T>(向量容器)是一个长度可变的序列,用来存放 T 类型的对象。必要时,可以自动增加容量,但只能在序列的末尾高效地增加或删除元素。
  • deque<T>(双向队列容器)是一个长度可变的、可以自动增长的序列,在序列的两端都不能高效地增加或删除元素
  • list<T>(链表容器)是一个长度可变的、由 T 类型对象组成的序列,它以双向链表的形式组织元素,在这个序列的任何地方都可以高效地增加或删除元素。访问容器中任意元素的速度要比前三种容器慢,这是因为 list<T> 必须从第一个元素或最后一个元素开始访问,需要沿着链表移动,直到到达想要的元素。
  • forward list<T>(正向链表容器)是一个长度可变的、由 T 类型对象组成的序列,它以单链表的形式组织元素,是一类比链表容器快、更节省内存的容器,但是它内部的元素只能从第一个元素开始访问
表 1 array、vector 和 deque 容器的函数成员
函数成员 array<T,N> vector<T> deque<T>
begin() - 返回幵始迭代器
end() - 返回结束迭代器
rbegin() - 返回反向'开始迭代器
rend() - 返回反向结束迭代器
cbegin() - 返M const开始迭代器
cend() - 返回const结束迭代器
crbegin() - 返回const反向开始迭代器
crend() - 返回const反向结束迭代器
assign() - 用新元素替换原有内容 -
operator=() - 复制同类型容器的元素,或者用初始化列表替换 现有内容
size() - 返回实际元素个数
max_size() - 返回元素个数的设大值
capacity() - 返回当前容量 - -
empty() - 返回true,如果容器中没有元素的话
resize() - 改变实际元素的个数 -
shrink _to_fit() - 将内存减少到等于当前元素实际所使用的大小 -
front() - 返回第一个元素的引用
back() - 返回铖后一个元素的引用
operator[]() - 使用索弓丨访问元素
at() - 使用经过边界检査的索引访问元素
push_back() - 在序列的尾部添加一个元素 -
insert() - 在指定的位置插入一个或多个元素 -
emplace() - 在指定的位置直接生成一个元素 -
emplace_back() - 在序列尾部生成一个元素 -
pop_back() - 移出序列尾部的元素 -
erase() - 移出一个元素或一段元素 -
clear() - 移出所苻的元素,容器大小变为 0 -
swap() - 交换两个容器的所有元素
data() - 返回包含元素的内部数组的指针 -
表 2 list 和 forward_list 的函数成员
函数成员 list<T> forward list<T>
begin() - 返回开始迭代器
end() - 返回结束迭代器
rbegin() - 返回反向开始迭代器 -
rend() - 返回反向结束迭代器 -
cbegin() - 返回 const 开始结束迭代器
before_begin() - 返回一个指向第一个元素前一个位置的迭代器 -
cbefore_begin() - 返回一个指向第一个元素前一个位置的const迭代器 -
cend() - 返回 const 结束迭代器
crbegin() - 返回 const 反向开始迭代器 -
crend() - 返回 const 反向结束迭代器 -
assign() - 用新元素替换原有内容
operator=() - 复制同类型容器的元素,或者用初始化列表替换现有内容
size() - 返回实际元素个数 -
max_size() - 返回元素个数的最大值
resize() - 改变实际元素的个数
empty() - 返回 true,如果容器中没有元素的话
from() - 返回第一个元素的引用
back() - 返回最后一个元素的引用 -
push_back() - 在序列的潘部添加一个元素 -
push_front() - 在序列的起始位置添加一个元素
emplace() - 在指矩位置直接生成一个元素 -
emplace_after() - 在指定位置的后面直接生成一个元素 -
emplace_back() - 在序列尾部生成一个元素 -
cmplacc_front() - 在序列的起始位生成一个元索
insert() - 在指定的位置插入一个或多个元素 -
insert_after() - 在指定位置的后面插入一个或多个元素 -
pop_back() - 移除序列尾部的元素 -
pop_front() - 移除序列头部的元素
reverse()-反向元素的顺序
erase() - 移除指定位置的一个元素或一段元素 -
erase_after() - 移除指定位 1;后面的一个元素或一段元素 -
remove() - 移除所苻和参数匹配的元素
remove_if() - 移除满足一元函数条件的所有元素
unique() - 移除所有连续重复的元素
clear() - 移除所有的元素,容器大小变为 0
swap() - 交换两个容器的所有元素
sort() - 对元素进行排序
merge() - 合并两个有序容器
splice() - 移动指定位置前面的所有元素到另一个同类型的 list 中 -
splice_after() - 移动指定位置后面的所有元素到另一个同类型的 list 中 -

6.常见的容器适配器? 

容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。
这里有 3 种容器适配器:

  1. stack<T>:是一个封装了 deque<T> 容器的适配器类模板,默认实现的是一个后入先出(Last-In-First-Out,LIFO)的压入栈。stack<T> 模板定义在头文件 stack 中。
  2. queue<T>:是一个封装了 deque<T> 容器的适配器类模板,默认实现的是一个先入先出(First-In-First-Out,LIFO)的队列。可以为它指定一个符合确定条件的基础容器。queue<T> 模板定义在头文件 queue 中。
  3. priority_queue<T>:是一个封装了 vector<T> 容器的适配器类模板,默认实现的是一个会对元素排序,从而保证最大元素总在队列最前面的队列。priority_queue<T> 模板定义在头文件 queue 中。

7.stack堆栈操作

stack<T>容器适配器中的数据是以 LIFO 的方式组织的,和其他序列容器相比,stack 是一类存储机制简单、所提供操作较少的容器。下面是 stack 容器可以提供的一套完整操作:

top():返回一个栈顶元素的引用,类型为 T&。如果栈为空,返回值未定义。

push(const T& obj):可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。

push(T&& obj):以移动对象的方式将对象压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。

pop():弹出栈顶元素。

size():返回栈中元素的个数。

empty():在栈中没有元素的情况下返回 true。

emplace():用传入的参数调用构造函数,在栈顶生成对象。

swap(stack<T> & other_stack):将当前栈中的元素和参数中的元素交换。参数所包含元素的类型必须和当前栈的相同。对于 stack 对象有一个特例化的全局函数 swap() 可以使用。

8. queue(STL queue)用法

只能访问 queue<T> 容器适配器的第一个和最后一个元素。只能在容器的末尾添加新元素,只能从头部移除元素。

queue操作:

queue 和 stack 有一些成员函数相似,但在一些情况下,工作方式有些不同:

(1)front():返回 queue 中第一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。

(2)back():返回 queue 中最后一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。

(3)push(const T& obj):在 queue 的尾部添加一个元素的副本。这是通过调用底层容器的成员函数 push_back() 来完成的。

(4)push(T&& obj):以移动的方式在 queue 的尾部添加元素。这是通过调用底层容器的具有右值引用参数的成员函数 push_back() 来完成的。

(5)pop():删除 queue 中的第一个元素。

(6)size():返回 queue 中元素的个数。

(7)empty():如果 queue 中没有元素的话,返回 true。

(8)emplace():用传给 emplace() 的参数调用 T 的构造函数,在 queue 的尾部生成对象。

(9)swap(queue<T> &other_q):将当前 queue 中的元素和参数 queue 中的元素交换。它们需要包含相同类型的元素。也可以调用全局函数模板 swap() 来完成同样的操作。

9.C++序列容器存储智能指针 

通常用容器保存指针比保存对象更好,而且大多数时候,保存智能指针比原生指针好。下面是一些原因:

在容器中保存指针需要复制指针而不是它所指向的对象。复制指针通常比复制对象快。

(1)在容器中保存指针可以得到多态性。存放元素基类指针的容器也可以保存其派生类型的指针。当要处理有共同基类的任意对象序列时,这种功能是非常有用的。应用这一特性的一个常见示例是展示一个含有直线、曲线和几何形状的对象序列。

(2)对指针容器的内容进行排序的速度要比对对象排序快;因为只需要移动指针,不需要移动对象。

(3)保存智能指针要比保存原生指针安全,因为在对象不再被引用时,自由存储区的对象会被自动删除。这样就不会产生内存泄漏。不指向任何对象的指针默认为 nullptr。

10.各容器的实现原理

vector 拥有一段连续的内存空间

list 就是数据结构中的双向链表

deque 的动态数组首尾都开放

set 有序的容器,红黑树的平衡二叉检索树的数据结构

multiset 红黑树实现的,set插入的元素不能相同,但是multiset可以相同。

map  键不能重复,红黑树实现的,

mtltimap 红黑树实现的,允许键有重复
 

这一章感觉做成了字典,不应该这样的!所以不再添加内容!这部分主要是各个容器的操作函数和算法函数较多,感觉用的时候查一查。提供学习的地址:http://c.biancheng.net/stl/algorithms/ 

猜你喜欢

转载自blog.csdn.net/qq_36086861/article/details/84866053