前言
STL(Standard Template Library)标准模板库
STL大致分为六大模块:容器(container),算法(algorithm),迭代器(iterator),仿函数(functor),配接器(adapter),配置器(allocator)
一、容器
container
C++ STL顺序容器详解(一)
你必须要知道所有容器都具有的一个基本特性:
它保存元素采用的是“值”(value)语义,也就是说,容器里存储的是元素的拷贝、副本,而不是引用。
容器操作元素的很大一块成本就是值的拷贝。所以,如果元素比较大,或者非常多,那么操作时的拷贝开销就会很高,性能也就不会太好。
- 尽量为元素实现转移构造和转移赋值函数,在加入容器的时候使用std::move()来“转移”,减少元素复制的成本:
Point p; // 一个拷贝成本很高的对象
v.push_back(p); // 存储对象,拷贝构造,成本很高
v.push_back(std::move(p)); // 定义转移构造后就可以转移存储,降低成本
// 直接使用C++11为容器新增加的emplace操作函数,它可以“就地”构造元素,免去了构造后再拷贝、转移的成本
v.emplace_back(...); // 直接在容器里构造元素,不需要拷贝或者转移
- 容器中存放指针,则必须要自己手动管理元素的生命周期
如果真的有这种需求,可以考虑使用智能指针unique_ptr/shared_ptr,让它们帮你自动管理元素。
1.1 顺序容器
1.1.1 std::vector
初始化
方法一
vector<int> vi;
方法二
vector<int> vi(10,10);//size 10,each value 10
方法三
vector<int> vi(arr,arr+10);//begin,end
插入
方法一 push_back、emplace_back、emplace
vector<T> a;
T val;
a.push_back( val);//在末尾插入一个元素
方法二 insert
v2.insert(v2.begin()+4, L"3"); //在指定位置,例如在第五个元素前插入一个元素
v2.insert(v2.end(), L"3"); //在末尾插入一个元素
v2.insert(v2.begin(), L"3"); //在开头插入一个元素
查找
方法一 迭代器
#include <algorithm>
...
vector<int> vec;
...
vector<int>::iterator it = find(vec.begin(), vec.end(), value);
if (it != vec.end()){
//找到了
}
方法二 数组查找
std::vector <T> a;
for (size_t i = 0; i < a.size(); i++)
{
if(value == a[i];{
//找到了
}
}
遍历
方法一 迭代器
std::vector <T> a;
std::vector <T>::iterator iVector = a.begin();
while(iVector != a.end())
{
std::cout<<" dump "<< (*iVector)<<std::endl;
++iVector;
}
方法二 数组
std::vector <T> v1;
for (size_t i = 0; i < v1.size(); i++)
{
T tempNum = v1[i];
}
删除
删除最后一个元素
v1.pop_back(); //删除最后一个元素
删除开头的元素
v1.erase(v2.begin()); //删除开头的元素
删除[begin,end]区间的元素
v1.erase(v1.begin(),v1.end);
或者删除范围内的
v1.erase(v1.begin(),v1.begin() + n);
删除全部元素
方法一
v1.clear()
方法二
std::vector<T>::iterator iVector = v1.begin();
while(iVector != v1.end())
{
delete (*iVector)->p;
iVector = v1.erase(iVector);
}
方法三
while(pVector->size() != 0)
{
//pop_back方法无返回值
pVector->pop_back();
//删除操作避免大量移动的方法,如果元素有申请堆栈的内存,不可用此方法
}
push_back 与 emplace_back区别
push_back拷贝数据结构,所以有两次构造调用
emplace_back直接调用构造函数,只有1次构造调用
emplace_back, emplace_font与emplace区别
emplace_back:尾插
emplace_font:头插
emplace:容器指定位置之前插入一个新的元素
1.2 线性容器
1.1.3 std::list
初始化
list<int> li(10);
list<int> li2(10);
list<int> li3(10,1);//size 10,each value 1
int arr2[10] = {};
list<int> li4(arr2,arr2+10);//begin,end
1.3 关联容器
关联容器底层数据结构:unordered_map/set基于hash表,不保证插入顺序;map/set基于红黑树,根据键自动排序
1.3.1 std::map
插入
方法一 数组
//map[key] = value
map<int,string> mis;
mis[0] = "first";
mis[1] = "second";
mis[2] = "third";
方法二 pair
//make_pair
map<int,string> mis2(mis.begin(),mis.end());
mis.insert(pair<int, string>(3, "fourth"));
方法三 make_pair
mapStudent.insert(make_pair(1, "student_one"));
方法四 value_type
//value_type
mis.insert(map<int, string>::value_type(3, "fourth"));
for (auto& pair : mis){
cout << pair.first << ":" << pair.second.c_str() << endl;
}
查找
方法一
std::map<T,V> m1;
T key;
...
if(m1.find(key) != m1.end){
//找到了
}
删除
删除所有
方法一
cmap.erase(cmap.begin(), cmap.end());
方法二
cmap.clear()
删除范围
例如删除map前5个
auto first = map_data.begin();
map_data.erase(first, std::next(first, 5));
排序删除
/* Online C++ Compiler and Editor */
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
std::map<std::string,int> map_data;
map_data["1"] = 1;
map_data["2"] = 1;
map_data["3"] = 1;
map_data["4"] = 1;
map_data["5"] = 1;
map_data["6"] = 1;
map_data["7"] = 1;
map_data["8"] = 1;
map_data["9"] = 1;
map_data["10"] = 1;
for(auto item:map_data){
printf("map_data[%s]=%d\n", item.first.c_str(), item.second);
}
std::vector<std::pair<std::string, ConnectCacheInfo>> vec(map_data.begin(),
map_data.end());
sort(vec.begin(),
vec.end(),
[=] (std::pair<std::string, int> p1, std::pair<std::string, int> p2)
{
return atoi(p1.first) > atoi(atoi(p2.first);
}
);
map_data.clear();
for (int i = 0; i < vec.size(); ++i) {
map_data.emplace(vec[i]);
}
if (map_data.size() > 10) {
auto first = map_data.begin();
map_data.erase(first, std::next(first, 5));
}
for(auto item:map_data){
printf("map_data[%s]=%d\n", item.first.c_str(), item.second);
}
return 0;
}
1.3.2 std::unordered_map
无序的map
不排序的unordered_map怎么做到快速查找?靠的就是unordered_map的第三个模板参数,把哈希算法传递进去。储存数据的时候会顺便算一遍 Key 的哈希值并保存起来,需要查找的时候就用哈希值来找。
默认情况下,unordered_map已经预先设定好使用std::hash作为第三个模板参数。如果不想使用std::hash,而是想用自己的,那就
std::unordered_map<int, std::string, MyHash> test_map;
其中MyHash是自己实现的Hash算法类。
1.3.3 std::multimap
多重映射是允许一个键对应多个附加数据的映射。
1.3.4 std::set
1.3.5 std::multiset
多重集合是允许有重复元素的集合
二、算法
algorithm
算法库
C++STL库之algorithm库
三、迭代器
iterator
cpp 迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型
四、仿函数
functor
仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。
五、适配器
adapter
是把一个事物,改造一下接口等等。使得其看起来像一个新的事物。适配器其实是一种应用在STL的设计模式。
六、配置器
allocator
默默完成内存配置与释放,对象构造和析构的工作。