forward_list
std::forward_list是C++11中引入的单向链表或叫正向链表。foeward_list具有插入、删除速度快、消耗内存空间少的特点,但只能向前遍历。与其他序列容器(vector deque等)相比,forward_list允许在序列的任何一处位置以O1的方式插入或删除元素。forward_list可以看作是对C语言风格的单链表的封装,仅提供有限的接口,和C中它的实现相比,基本不会有任何开销,当不需要双向迭代的时候,与std::list相比,该容器具有更高的空间利用率。缺点:不能O1的随机访问任意成员,要On 存储连接信息需要消耗内存,forward_list出于效率考虑,有意不提供size()成员函数,获取forward_list所包含的成员个数需要用std::distance(list.begin(),list.end())
#include<iostream>
#include<forward_list>
using namespace std;
int main()
{
forward_list<int> list = { 1,2,3,4 ,6,4,4, 99,777 };
cout << "size :" << std::distance(list.begin(), list.end());//长度
for (auto it = list.begin(); it != list.end(); it++)
cout << " " << *it;
cout << endl;
list.insert_after(list.before_begin(), 88);//头部插入一个数 还有emplace_after
list.insert_after(list.before_begin(), { 1,2,5,5,2,8 });//头部插入多个
list.push_front(10);//头部插入一个元素
list.erase_after(list.begin());//删除第2个 (下一个)
list.erase_after(find(list.begin(),list.end(),99),list.end());//把99后面所有元素删除
list.remove(3);//删除所有为3的元素
list.sort();//排序
list.unique();//去重
std::array
array是一个固定大小的顺序容器,不能动态改变大小,array内的元素在内存中以严格的线性顺序存储
与普通数组声明存储空间大小[]方式是一样有效的,只是加入了一些成员函数好全局函数get()/operator(==,!=,>,<) 以便当做标准容器使用
std::array除了 传统数组支持随机访问、效率高、存储大小固定等特点外,还支持迭代器访问、获取容量、获得原始指针等高级功能
零大小的array是有效的,在零长array上调用front ,back(),data()是未定义的
#include<iostream>
#include<array>
using namespace std;
int main()
{
array<int, 10>arr = { 1,2,3,4,5,6,7,8,9,10 };
arr[2] = 44;//访问
arr.size();
for (auto it = arr.begin(); it != arr.end(); it++)
{
cout << *it << endl;
}
cout << *arr.begin() << endl;//迭代器
cout << arr.front() << endl;
cout << arr.back() << endl;//最后一个元素的值
std::get<2>(arr);//访问
//还支持 == 来比较两个array
const char* t = "aaa";
memcpy(arr.data(), t, arr.size());//data()可以返回原始指针
}
cbegin、cend
返回一个const迭代器(const_iterator)不能用于修改元素
vector<int>arr = {1,2,3,4,5};
for(auto it = arr.cbegin();it!=arr.cend();++it){
cout<<' '<<*it;
*it= 1;//error
}
swap
swap操作交换两个相同类型容器的内容。调用swap之后,两个容器中的元素将会交换。C++11标准中提供了非成员版本的swap操作,此操作对array容器 会交换元素的值,对其他容器,则只交换容器内部结构,并不进行元素值拷贝操作,所以造这种情况下是非常迅速的。元素不会被移动的事实意味着,指向容器的迭代器、引用和指针在swap操作后都不会失效。他们任然指向swap操作之前所指向的那些元素,但是,在swap之后,这些元素已经属于不同的容器了。与其他容器不同,swap两个array会真正交换他们的元素。一次,交换两个array所需的时间与array中元素的数目成正比,对于array,在swap操作之后,指针,引用,迭代器所绑定的元素保持不变,但元素值已经与另一个array中应元素进行了交换
新标准库中,容器既提供成员函数版本的swap,也提供非成员函数版本的sao,而早起标椎库版本只提供成员函数版本的swap,非成员函数版本的swap在泛型编程中是非常重要的,统一使用非成员版本的swap是一个好习惯
提高容器插入效率:emplace/emplace_back
vector的push_back,insert,map的insert,set的insert,这些插入操作会涉及两次构造,首先是对象的初始化构造,接着在插入的时候会复制1次,会触发拷贝构造,但是很多时候并不用两次
C++11标准的emplace只需要构造一次,vector有两个函数可以使用:
emplace 、emplace_back。emplace类似insert,emplace_back类似push_back
在开发过程中,使用emplace可以达到效果,就应该尽量使用emplace
vector
emplace<->push_back
emplace_back<->insert
set
emplace<->insert
map
emplace<->insert
shrink_to_fit
capacity:现在目前容器最多容纳个数,size当前个数
请求容器降低其容量与size匹配,从曾经最大的容量减少到他现在需要的容量,这样减少容量的方法常常称为“收缩到合适”(shrink_to_fit)
它并不保证一定会释放掉多余的内存,看编译器脸色,只是提出个请求,如果请求被接纳,那么内存被释放,如果不接纳,就不释放。这个请求不具有约束力,容器可以自由的去执行其他的优化方案
vector<int>v;
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
cout<<"size:"<<v.size()<<endl;
cout<<"capacity"<<v.capacity()<<endl;
v.clear();//清空内容,没释放内存
v.shrik_to_fit();
vector<int>(iv).swap(iv);
真正把容器从最大容量减少到需要的容量,表达式vector<int>(iv)建立一个临时vector,拷贝构造函数负责把iv拷贝到临时vector,vector的拷贝构造函数只分配拷贝的元素需要的内存,所以这个临时的vector没有多余容量,临时vector和iv交换数据,iv只有临时变量的修整过的容量,而这个临时变量则持有了曾经在iv中没用到的过剩容量,临时vector被销毁,因此释放了以前iv使用的内存 收缩到合适
vector<int>().swap(iv);
将容量清零
unordered_map
C++11中有新出的4个关联式容器:
unordered_map,unordered_set,unordered_multimap,unordered_multiset
与map、set、multimap。multiset功能类似 前者红黑树 后者hash表
unordered_map<string, int>stu_map;
stu_map.insert(make_pair("tom", 25));
stu_map.insert(make_pair("lily", 26));
stu_map.insert(make_pair("jack", 20));
stu_map["garrett"] = 40;
for (auto it = stu_map.begin(); it != stu_map.end(); it++)
{
cout << it->first.c_str() << ' ' << it->second << endl;
}
unordered_map自定义数据
unordered_map必须自定义operator== 和hash_key仿函数。
struct person
{
string name;
int age;
person(string n, int a) :name(n), age(a) {}
bool operator==(const person& p)const
{
return name == p.name && age == p.age;
}
};
struct hash_key { //仿函数
size_t operator()(const person& p)const {
size_t hash = 0;
size_t seed = 13;
for (int i = 0; i < p.name.size(); i++) {
hash = hash * seed + p.name[i];
}
hash = hash * seed + p.age;
return hash;
}
};
int main()
{
unordered_map<person, int,hash_key>m;
person p1("tom", 10);
person p2("ll", 20);
person p3("ww", 30);
m.insert(make_pair(p1, 82));
m.insert(make_pair(p2, 99));
m.insert(make_pair(p3, 100));
for (auto it = m.begin(); it != m.end(); it++) {
cout << it->first.name << ' ' << it->first.age << " " << it->second<<endl;
}
rehash
rehash就是重新hash,在unordered_map里有一个函数,完成rehash的操作
void rehash(size_type n);(哈希表重建)
参数 n 是为了重新设置hash表中的buckets,就是哈希桶的数量,调用这个函数的时候,hash表中的桶数量就会设置成n或者大于n
哈希函数计算出来的值就是在桶中的位置多个key计算出来的是一样的话就用链表来解决哈希冲突
这种情况下就会强制进行rehash操作,位置就可能发生变化,如果n小于当前桶数量,那么不会做任何事情
装载因子超过某个值 也就是当前桶的数量超过max数量 也会rehash
可以通过bucket_count()成员函数来获取桶的数量
load_factor()成员函数获取装载因子