STL 容器
C++STL容器是C++的利器之一,在很多问题中使用非常方便。
顺序容器
vector向量容器
类模板实现,使用时需要实例化,底层数据结构:动态开辟的数组,每次以原来空间大小的2倍方式扩容。
接口名称 使用用法 功能描述 时间复杂度 push_back push_back(val) 末尾添加元素 0(1) insert insert(it,val) 迭代器位置添加元素 0(n) pop_back pop_back() 末尾删除元素 0(1) erase erase(it) 删除迭代器位置元素 0(n) operator [] vec[val] 下标访问元素 0(1) find find(val) 查找元素,返回迭代器 0(n) size size() 返回容器中元素个数 empty empty() 判断容器空 reserve reserve(val) 为数组预留空间,可以解决数组扩容效率低下问题 resize resize(num) 为数组扩容,不经开辟空间,而且填充元素 swap swap(vec1) 交换两个容器的内容
遍历容器
int main ( )
{
vector< int > vec;
for ( int i = 0 ; i < 10 ; ++ i)
{
vec. push_back ( rand ( ) % 100 ) ;
}
for ( int i = 0 ; i< vec. size ( ) ; ++ i)
{
cout << vec[ i] << " " ;
}
cout << endl;
vector< int > :: iterator it = vec. begin ( ) ;
for ( ; it != vec. end ( ) ; ++ it)
{
cout << * it << " " ;
}
cout << endl;
auto it1 = vec. begin ( ) ;
for ( ; it1 != vec. end ( ) ; ++ it1)
{
cout << * it1 << " " ;
}
cout << endl;
for ( int val : vec)
{
cout << val << " " ;
}
cout << endl;
return 0 ;
}
容器迭代器失效问题
使用迭代器连续删除和插入容器时,需要注意迭代器失效的问题。
int main ( )
{
vector< int > vec;
for ( int i = 0 ; i < 10 ; ++ i)
{
vec. push_back ( rand ( ) % 100 ) ;
}
auto it = vec. begin ( ) ;
for ( ; it != vec. end ( ) ; )
{
if ( * it % 2 == 0 )
{
it = vec. erase ( it) ;
}
else
{
++ it;
}
}
return 0 ;
}
deque双端队列容器
类模板实现的,使用时需要实例化,底层是动态开辟的二维数组,deque的底层二维数组大小的方式
#define MAX_SIZE 2
#define QUE_SZIE 4096 / sizeof(T)
由此可知,deque的二维的大小是固定大小开辟的,内存扩容时,扩容第一维的数组空间,每次按照2倍方式扩容,然后将内容调整后,使得上下预留空间。
函数接口 使用方法 功能描述 时间复杂度 push_back push_back(val) 从队列尾部插入元素 o(1) push_front push_front(val) 从队列首部添加元素 o(1) insert insert(it,val) 在迭代器的位置添加元素 o(n) pop_back pop_back() 从队列尾部删除元素 o(1) pop_front pop_front() 从队列头部删除元素 o(1) erase erase(it) 在迭代器的位置删除元素 o(n)
list双向循环链表
函数接口 使用方法 功能描述 时间复杂度 push_back push_back(val) 从队列尾部插入元素 o(1) push_front push_front(val) 从队列首部添加元素 o(1) insert insert(it,val) 在迭代器的位置添加元素 o(1) pop_back pop_back() 从队列尾部删除元素 o(1) pop_front pop_front() 从队列头部删除元素 o(1) erase erase(it) 在迭代器的位置删除元素 o(1)
list虽然删除插入本身是0(1),但是每次都需要从链表头开始遍历,时间复杂度是0(n)。
splice成员方式
因为链表的每个节点都是单独开辟内存的,因此链表的移动或者将两个链表之间移动数据的时候,直接将节点摘下来,然后链接到新的位置,效率比较高。
splice使用方式
int main ( )
{
list< int > lst1;
list< int > lst2;
for ( int i = 0 ; i < 10 ; ++ i)
{
lst1. push_back ( rand ( ) % 100 ) ;
}
for ( int i = 0 ; i < 10 ; ++ i)
{
lst2. push_back ( rand ( ) % 100 ) ;
}
for ( int val : lst1)
{
cout << val << " " ;
}
cout << endl;
for ( int val : lst2)
{
cout << val << " " ;
}
cout << endl;
lst1. splice ( lst1. end ( ) , lst1, lst1. begin ( ) ) ;
for ( int val : lst1)
{
cout << val << " " ;
}
cout << endl;
lst2. splice ( lst2. end ( ) , lst1, lst1. begin ( ) ) ;
for ( int val : lst2)
{
cout << val << " " ;
}
cout << endl;
lst2. splice ( lst2. end ( ) , lst1, lst1. begin ( ) , lst1. end ( ) ) ;
for ( int val : lst2)
{
cout << val << " " ;
}
cout << endl;
return 0 ;
}
由代码可以看出,splice函数也是使用迭代器进行的,第一个参数是调用splice函数的list的迭代器,然后第二个参数是移动的list,后面的参数是迭代器,可以移动一个元素,也可以移动多个连续的元素。
顺序容器之间的常见问题
vector和deque的区别
vector的内存是连续的,deque的内存是间隔连续的,每一个二维数组是连续的 vector的前插和中插的时间复杂度是0(n),后插的时间复杂度是0(1),deque的前插,后插是0(1),中插是0(n)。 因为vector的内存是连续的,因此vector插入效率比deque的插入效率高。
vector和list的区别
对于数组和链表的选择,特征比较明显,随机访问多的选择vector,增删多的选择list。
迭代器失效的问题
迭代器遍历容器时,是不允许连续删除或者插入元素的,因为每次插入或者删除一个元素后,迭代器就失效了,因此如果连续删除或者插入元素,就需要进行迭代器的的更新。
容器适配器
之所以叫容器适配器,是因为容器适配器没有自己的底层数据结构,底层使用是顺序容器。
stack栈
底层默认依赖deque实现的。 deque的二维内存是按照固定大小开辟的,相比vector初始内存使用率高 deque是分段开辟内存的,内存利用率高。
函数方法 使用方式 功能描述 push push(val) 入栈 pop pop() 出栈 empty empty() 判空 size size() 元素个数 top top() 获取栈顶元素
queue队列
底层默认duque实现的。 deque的二维内存是按照固定大小开辟的,相比vector初始内存使用率高 deque是分段开辟内存的,内存利用率高。 deque本身是双端队列,因此更适合queue队列
函数接口 使用方式 功能描述 push push(val) 入队列 front front() 查看队头元素 pop pop() 出队列 back back() 查看队尾元素 size size() 队列元素个数 empty empty() 判空
priority_queue优先级队列
底层使用的是vector,因为优先级队列底层是大根堆,因此需要使用vector的连续内存实现,需要按照下标计算孩子节点位置。
函数接口 使用方式 功能描述 push push(val) 入队列 pop pop() 出队列 top top() 队头元素 size size() 元素个数 empty empty() 判空
因此底层是默认大根堆,因此在可以解决top k 问题,也可以在定义时修改为小根堆。
template < class _Ty , class _Container = vector< _Ty> ,
class _Pr = less< typename _Container:: value_type> >
class priority_queue ;
priority_queue< int > que1;
priority_queue< int , vector< int > , greater< int >> que2;
less 和 greater都是类模板,实现的是operator()小括号运算符重载函数。
int main ( )
{
priority_queue< int , vector< int > , greater< int >> que;
priority_queue< int > que1;
for ( int i = 0 ; i < 10 ; ++ i)
{
que. push ( rand ( ) % 100 ) ;
que1. push ( rand ( ) % 100 ) ;
}
while ( ! que1. empty ( ) )
{
cout << que1. top ( ) << " " ;
que1. pop ( ) ;
}
cout << endl;
while ( ! que. empty ( ) )
{
cout << que. top ( ) << " " ;
que. pop ( ) ;
}
cout << endl;
}
关联容器
无序关联容器(C++11)
底层是链式哈希表,增删查接近O(1),效率非常高。
容器名称 容器说明 unordered_map 无序单重映射表 unordered_set 无序单重集合 unordered_multimap 无序多重映射表 unordered_multiset 无序多重集合
常用的是unrodered_map 和 unordered_set unordered_map常用于查重,unordered_set常用于去重。 unrodered_set常用函数:insert(val),find(val), 返回的都是迭代器,erase(val),erase(it)。 unrodered_map常用函数:insert({key,val}),find(key)返回迭代器,erase(key),erase(it),[]中括号运算符重载函数,map[key] = val:如果key不在插入key,如果key在修改val,并且返回key对应的val。
有序关联容器
底层是红黑树,增删查是O( log2(n) ),效率很高。
容器名称 容器说明 map 有序单重映射表 set 有序单重集合 multimap 有序多重映射表 multiset 有序多重集合
对于关联容器大家可以自行查找其他函数方法,这里不做多的解释 。
新手上路,如有错去,请指出!!!