目录
1.STL标准模板库
2.容器
2.1 string容器
2.2 数组(vector array valarray)
2.3 链表(list forward_list)
2.4 双端队列deque
2.5 map
3.几种简单算法
3.1排序
3.1.1 从小到大
3.1.2 从大到小
3.1.3 随机排序
3.2 遍历(三种for循环)
3.2.1 常规for循环( 在复杂的逻辑中效率高)
3.2.2 foreach循环(简洁易用,不容易发生错误,适用于数组、集合遍历循环未知的情况下是不能进行增删操作的)
3.2.3 for_each循环
4.迭代器
5.适配器
6.分配器
7.仿函数
先上图,对上述六部分内容使用上注意点细节进行详解。
string在我们C语言当中,char *表示指向字符数组地址的指针。使用string类完全不用考虑内存分配和释放,也不用担心约界崩溃。使用注意以下几点:
可以查看以下源码:
pointer
_M_data() const
{ return _M_dataplus._M_p; }
既然是一个地址值,就一定是一个常量。所以在delete可以使得指针有所指。
我在实现此函数的时候是这样定义的char* Mystring::c_str(),如果不写引用,该函数将返回一个副本,期间不会涉及到对内容的修改,所以原指针不会同步状态给副本,会导致释放失败。
size | length | capacity | reserve(来自algorithm头文件) | |
概念 | 返回的字符串个数 | 返回字符串长度 | 系统为字符串分配所在空间大小(容器存储数据个数) | 重设分配空间大小 |
二者没有区别,可以看一下源码 length源码: size源码: |
分配空间原则(不同编译器可能不同,g++测试) 当数据<15,系统开辟内存空间大小为15 当内存不够的时候,会按照原来系统的大小整数陪递增 15--30--60--120..... 注意:Visual Studio和VC分配方式可能不同 |
reserve修改容量不能变小,只能变大。 比如原先容量15,reserve(16), 则容量变为30, reserve(1) 则容量仍为30 |
内存的分配原理跟string是一样的,是连续的空间,如果空间不够用,会申请一个更大的连续的空间,同时迭代器失效
vector | ||
头文件 | #include using namespace std; |
|
语法格式 | vector <>可以放基本数据类型、结构体、指针、对象 |
|
构造函数 | vector(); | 无参数的构造 |
vector(size_type _Count); | n个元素 | |
vector( size_type num, const TYPE &val ); | 用num个val来初始化容器 | |
vector( const vector &from ); | 拷贝构造 |
|
vector( input_iterator start, input_iterator end ); | 迭代器初始化 | |
定义vector的迭代器 | vector |
begin() 指向头 end() 指向尾元素的下一个元素 |
空间属性 |
empty() | 对象是否有元素 |
size() | 元素个数 | |
resize() | 重新设置元素个数 缩小时大小改变 容量不变, 放大时大小改变 容量改变 |
|
reserve() | 修改容量,不能变小只能变大。想修改多少就修改多少,不像是string变量必须按照整数倍来增加 | |
capacity() | 按照初始化空间大小的整数倍增加。(比如初始化空间大小为5,当空间占用满再插入新的数据,空间容量会加倍) | |
查寻 注:相对于list、map来讲查询速度快(因为可以通过下标访问) |
输出全部元素 |
循环(迭代器、下表运算)、for_each |
输出单个元素: |
at、[]下标运算、back(返回尾巴元素) 使用at的好处:检测下表是否越界,并做相应的处理 |
|
增加 注:由于是数组,尾添加效率非常高(不考虑重新增加空间) 中间添加的效率很低(因为插入该元素后,后边的元素都要以此重新排列) |
void push_back( const TYPE &val ); |
尾添加 |
iterator insert( iterator loc, const TYPE &val ); | 在指定迭代器的位置加入一个数据 | |
void insert( iterator loc, size_type num, const TYPE &val ); | 在某个迭代器后加入num个值为value的元素 | |
void insert( iterator loc, input_iterator start, input_iterator end ); | 在某个迭代器后加入另一个向量的中间一段 | |
删除 | void pop_back(); | 尾删除 |
iterator erase( iterator loc ); | 删除一个指定 | |
iterator erase( iterator start, iterator end ) | 删除一段指定 | |
void clear(); | 删除所有 | |
修改 | 利用输出的形式可以修改 | |
赋值函数(重新赋值,清除以前的) | ||
运算符重载 | v1 == v2 v1 != v2 v1 <= v2 v1 >= v2 v1 < v2 v1 > v2 |
所有相同位置的元素相等,比较的形式跟字符串一样 |
遍历(下面细说) | ||
排序 | ||
乱序 |
list是双向链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。
头文件 | #include using namespace std; |
|
语法格式 | list <>可以放基本数据类型、结构体、指针、对象 |
双向循环链表 |
构造函数 | list() | 无参数的构造 |
list( size_type _Count); | 多个元素,初始值为0 | |
list( size_type _Count, const Type& _Val); | 多个指定的值 | |
list( const _list& _Right); | 拷贝构造(用一个list初始化当前的list) |
|
list( InputIterator _First, InputIterator _Last ); | 用另一个对象中间的一段对该链表初始化 | |
定义vector的迭代器 | list |
begin() 指向头 end() 指向尾元素的下一个元素,不能进行加法运算,可以自加++ |
空间属性 |
empty() | 对象是否有元素 |
size() | 元素个数 | |
resize() | 重新设置元素个数 缩小时大小改变 容量不变, 放大时大小改变 容量改变 |
|
没有reserve(),因为是链表 | ||
没有capacity(),因为是链表 | ||
查寻 注:相对于数组来讲查询速度慢(因为需要遍历查询) |
输出全部元素 |
循环(迭代器、下表运算)、for_each |
输出单个元素: |
1.[]下标运算、2.back(返回尾巴元素) 3.front()(返回第一个元素) |
|
增加 注:插入删除速度快,只需要修改前一个节点和后一个节点指向 |
void push_front(const TYPE &val ) | 头添加 |
void push_back( const TYPE &val ); |
尾添加 | |
iterator insert( iterator loc, const TYPE &val ); | 在指定迭代器的位置加入一个数据 | |
void insert( iterator loc, size_type num, const TYPE &val ); | 在某个迭代器后加入num个值为value的元素 | |
void insert( iterator loc, input_iterator start, input_iterator end ); | 在某个迭代器后加入另一个向量的中间一段 | |
删除 | void pop_front() | 头删除 |
void pop_back(); | 尾删除 | |
iterator erase( iterator loc ); | 删除一个指定 | |
iterator erase( iterator start, iterator end ) | 删除一段指定 | |
void clear(); | 删除所有 | |
void remove( const TYPE &val ); | 删除所有跟参数相同的元素。如果是结构体需要重载== | |
void unique(void) | 删除list中重复的元素 | |
修改 | 利用迭代器修改 | |
赋值函数assign | ||
赋值=修改 | ||
运算符重载 | v1 == v2 v1 != v2 v1 <= v2 v1 >= v2 v1 < v2 v1 > v2 |
所有相同位置的元素相等,比较的形式跟字符串一样 |
void swap( list &from ); | 交换两个list的内容 | |
void reverse(); | reverse() 把list的元素翻转 | |
void sort(); | 默认从小到大排序,如果容器本身自带排序,那么使用的时候就可以不用选择排序算法 | |
void merge( list &lst ); | 合并两个list。 特点: 1.自动排序 2.重载小于号 3.两个链表必须有序(如果链表元素是升序的,就要用<号,return true,反之) |
|
void splice( iterator pos, list &lst ); void splice( iterator pos, list &lst, iterator del ); void splice( iterator pos, list &lst, iterator start, iterator end ); |
拼接 |
forward_list是一个单向链表,只支持单向顺序访问,在链表的任何位置进行插入/删除操作都非常快(为了提高效率没有添加size函数)
一般通常使用中,对效率没有非常细微要求都可以。
,注意以下两点:
deque属于段连续空间,
deque | vector | list | |
空间结构 | 段连续空间 | 连续空间 | 不连续空间 |
功能比较 | 1.随机位置插入/删除效率不高(数据量512) 2.支持随机访问[比vector慢,因为要做堆跳转(迭代器结构复杂,会降低访问效率) 3.支持头添加,支持尾添加 |
1.随机位置插入/删除效率低 2.随机访问效率高(下标运算) 3.不支持头添加,支持尾添加 |
1.随机位置插入/删除效率高 2.不支持随机访问 支持头添3.加,支持尾添加 |
使用选择 | 随机访问+头添加,就选deque,支持随机访问,即支持[]以及at(),但是性能没有vector好,可以在内部进行插入和删除操作,但性能不及list | 随机访问操作频率高,就选vector | 插入删除频率高,头尾添加,就选list |
行为对比 | 没有capacity和reserve | 有capacity和reserve | 没有capacity和reserve |
map属于一种关联容器,它保存的是一个键值,通过键值来排序,通过键值来查找访问。Map使用的是平衡二叉树结构
头文件 | #include | |
语法格式 | map <>可以放基本数据类型、结构体、指针、对象 |
键值对,有序,平衡二叉树 |
构造函数 | map() | 无参数的构造 |
map(const _map& _Right); | 一个参数 | |
map(InputIterator _First, InputIterator _Last); | 另一个对象的一段 | |
定义map的迭代器 | map |
begin() 指向头 end() 指向尾元素的下一个元素,不能进行加法运算,可以自加++ first指向键值 second指向实值 |
空间属性 |
empty() | 对象是否有元素 |
size() | 元素个数 | |
resize() | 重新设置元素个数 缩小时大小改变 容量不变, 放大时大小改变 容量改变 |
|
count(const Key& _Key) | 得到某一个元素数量,或者说判断一个键值是否存在 | |
没有capacity(),reserve(),因为是链表 | ||
查寻 注:相对于数组来讲查询速度慢(因为需要遍历查询) |
输出全部元素 |
for(ite; ite != mp.end(); ite++) { cout< } |
输出单个元素: |
cout< |
|
iterator find( const Key& _Key); | 有就返回所在节点迭代器,没找到则无法输出,崩溃 | |
增加 注:插入效率低于链表,因为涉及到排序 |
pair |
pair<键,值>,键值不能重复,实值可以重复。输出first和second |
insert( iterator pos, const TYPE &val ); |
迭代器可以++,但是不可以+4 | |
void insert( iterator loc, input_iterator start, input_iterator end ); | 在某个迭代器后加入另一个向量的中间一段 | |
删除 | iterator erase( iterator _Where); | 迭代器指定的删除 |
iterator erase(iterator _First,iterator _Last); | 迭代器指定的段删除 | |
size_type erase( const key_type& _Key); | 根据键值删除 | |
void clear(); | 删除所有 | |
void remove( const TYPE &val ); | 删除所有跟参数相同的元素。如果是结构体需要重载== | |
void unique(void) | 删除list中重复的元素 | |
修改(键值不能改,实值可以改) | 利用迭代器修改 | |
赋值函数assign | ||
赋值=修改 | ||
交换 | swap() | |
lower_bound(key) | 返回参数key位置,该位置的键值不小于key : key<=pos | |
upper_bound(key) | 返回位置,该位置的键值>key : key < pos | |
equal_range(key) | 返回这个区间 | |
无序容器(散列表) | unorder_map\unorder_multimap\unorder_set\unorder_multiset | |
hash_map | 哈希表 头文件 |
包含头文件#include
template
void sort(RandomAccessIterator _First, RandomAccessIterator _Last );
示例:
void fun(int c)
{
cout<< c <vec(5);
vec.at(0) = 5;
vec.at(1) = 1;
vec.at(2) = 2;
vec.at(3) = 7;
vec.at(4) = 4;
sort(vec.begin(), vec.end()); //从小到大
for_each(vec.begin(), vec.end(), fun);
}
template
void sort( RandomAccessIterator _First, RandomAccessIterator _Last, BinaryPredicate _Comp);
其中参数三 greater<>() 可以指定从大到小
示例:
void fun(int c)
{
cout << c <vec(5);
vec.at(0) = 5;
vec.at(1) = 1;
vec.at(2) = 2;
vec.at(3) = 7;
vec.at(4) = 4;
sort(vec.begin(), vec.end(), greater()); //从大到小
for_each(vec.begin(), vec.end(), fun);
}
void random_shuffle(RandomAccessIterator _First, RandomAccessIterator _Last );
示例:
void vector_random_shuffle()
{
vectorvec(5);
vec.at(0) = 5;
vec.at(1) = 1;
vec.at(2) = 2;
vec.at(3) = 7;
vec.at(4) = 4;
sort(vec.begin(), vec.end()); //从小到大
for_each(vec.begin(), vec.end(), fun);
srand(time(0));
random_shuffle(vec.begin(), vec.end()); //利用随机数发生器,涉及到srand-随机种子
for_each(vec.begin(), vec.end(), fun);
}
void look_vector_output_all()
{
vectorvec(5,10);
vec.at(4) = 15;
vector::iterator ite = vec.begin();
vector::iterator ite1 = vec.end();
for(ite; ite != vec.end(); ite++)
{
cout<< *ite<
void look_vector_output_all()
{
vectorvec(5,10);
vec.at(4) = 15;
vector::iterator ite = vec.begin();
vector::iterator ite1 = vec.end();
for(auto vec_temp : vec)
{
cout<
迭代器相当于char *,使用迭代器更重要的一点原因是与算法相结合,并且适用于所有容器
常规用法 :
注意:end()是末尾元的指向的下一个元素(NULL)
迭代器失效:
原因:迭代器在创建完毕对象后指向对象首地址,当对象发生改变后,一定是重新申请空间。但此时迭代器指向没有发生改变,会导致迭代器失效。 因此如果对象发生了内存变化,一定要重新调用一遍迭代器。
容器类型 | 行为 |
迭代器是否失效 |
以string为例 | str.append():数据追加到原字符串尾部,当初始化空间不够的时候,会重新开辟新的空间将所有数据搬运到新空间 | 失效 |
str.insert():数据插入到原字符串指定位置,当初始化空间不够的时候,会重新开辟新的空间将所有数据搬运到新空间 | 失效 | |
str.erase(): 删除数据,但是初始地址不会改变 | 不失效 | |
str.assign():重新赋值,初始地址不会改变 | 不失效 | |
如果是数组,string等由空间容量的容器,当空间容量满的时候系统会重新分配空间,此时迭代器会失效。 如果是链表、Map,不存在空间容量之说,迭代器不会失效 |
后续更新