一、vector
什么时候使用?
经常要进行随机访问,并且不需要经常对中间元素进行添加删除操作。
内存分配机制
连续存储空间,减少大小后,内存也不会释放。当内存空间Mem不够时,重新申请一块大小为Mem*2 的内存空间,再拷贝原始内容。
时间效率
插入和删除操作:除尾部元素外,需要移动内存,如果你得元素是结构或类,移动的同时还要进行构造和析构操作;O(N)
访问操作:O(1)
常用操作
- 初始化
vector<int> v1 = { 1,2,3,4,5 };
//列表初始化,注意使用的是花括号
vector<int> v2(5, -1);
//初始化为{-1,-1,-1,-1,-1},第一个参数是数目,第二个参数是要初始化的值
vector<string> v3(3, "hi");
vector<int> v4(10);
//默认初始化为10个0
vector<int> v5(4);
//默认初始化为4个空字符串 - 容器大小:
capacity查看当前保留的内存,使用swap来减少它使用的内存,如push_back 1000个元素,capacity返回值为16384,size为1000 - 访问
下标;vector.at();迭代器
v5.front();
//访问第一个元素
v5.back();
//访问最后一个元素
for (vector<string>::iterator iter = v1.begin(); iter != v1.end(); iter++)
{
cout << *iter << endl;
//下面两种方法都行
cout << (*iter).empty() << endl;
cout << iter->empty() << endl;
}
- 增删
v1.push_back();
//告诉编译器为新元素开辟空间、将新元素存入新空间里。
v1.pop_back();
//删除最后一个元素
v1.insert(v5.begin()+1,9);
//在第二个位置插入新元素
v1.erase(v5.begin() + 3);
//删除第四个元素
v1.insert(v5.begin() + 1, 7, 8);
//连续插入7个8
v1.clear();
//清除所有内容
二、set, multiset
底层实现
红黑树(平衡二叉树的一种)
容器特点
set容器内元素有序且唯一,插入时自动排序。
multiset允许重复元素
时间效率
访问:O(logN)
插入: O(logN)
删除:O(logN)
常用操作
-
初始化
set<int> s1{9,8,1,2,3,4,5,5,5,6,7,7 };
//自动排序,从小到大,剔除相同项 -
容器大小:
-
访问
find()
//O(logn) 找不到返回s1.end()
lower_bound()
//O(logn) 查找第一个不小于k的元素
upper_bound()
//O(logn) 查找第一个大于k的元素
equal_range()
//O(logn) 返回pair
迭代器(同vector)
for (set<T>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it;
}
- 增删
s1.erase(6);
s1.insert(9);
//有这个值了,do nothing
三、list
双向链表。
优缺点
优点是插入和删除元素都比较快捷,缺点是不能随机访问元素。
内存分配机制
元素存放在堆中,内存空间不连续。
时间效率
访问:O(N)
插入: O(1)
删除:O(1)
常用操作
- 初始化
list<int> l1{ 1,2,3,4,5,5,6,7,7};
- 容器大小
size(), clear(), empty()
- 访问
begin(), end()
不支持[ ]操作!
for (list<T>::iterator iter = v.begin(); it != v.end(); it++)
std::cout << *iter << std::endl;
- 增删
push_back(), pop_back()
//从末尾插入或删除元素
push_front(), pop_front()
insert()
// 插入和删除的复杂度的O(1)
erase()
// O(1) - 排序
值得注意的是,list容器不能调用algorithm下的sort函数进行排序,因为sort函数要求容器必须可以随机存储,而list做不到。所以,list自己做了一个自己用的排序函数:l1.sort();
四、map, multimap
底层实现
红黑树(平衡二叉树的一种)
容器特点
multimap允许重复元素, 没有[]运算符
时间效率
访问:O(logN)
插入: O(logN)
删除:O(logN)
常用操作
- 初始化
map<string, int> m1; //<>里的第一个参数表示key的类型,第二个参数表示value的类型
m1["Kobe"] = 100;
- 访问
find()
//O(logn) 找不到返回s1.end()
lower_bound()
//O(logn) 查找第一个不小于k的元素
upper_bound()
//O(logn) 查找第一个大于k的元素
equal_range()
//O(logn) 返回pair
迭代器
for (map<string, int>::iterator it = m1.begin(); it != m1.end(); it++) {
cout << it->first<<" "<<it->second << endl; //注意用法,不是用*it来访问了。first表示的是key,second存的是value
}
- 增删
m1.insert(pair<string, int>("Harris", 89));
m1.erase("Curry");
m1.clear();
//清空全部 - 判断元素是否存在
if (m1.count("Lee")) {
cout << "Lee is in m1!" << endl;
}
五、deque
双端队列。deque 是对vector 和list 优缺点的结合,它是处于两者之间的一种容器。
内存分配机制
是一种优化了的、对序列两端元素进行添加和删除操作的基本序列容器。它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小。它不需要重新分配空间,所以向末端增加元素比vector 更有效。
特点
优点:
随机访问方便;
可以在内部进行插入和删除操作;
可以在两端进行push和pop。
缺点:占用内存多。
时间效率
常用操作
-
初始化
deque data; -
访问
支持[ ]操作符和vector.at() -
增删
六、hash_map, hash_set, hash_multimap, and hash_multiset
底层实现
哈希表
时间效率
访问:O(1),最坏情况O(N)。
插入:O(1),最坏情况O(N)。
删除:O(1),最坏情况O(N)。
如果你采用合适的哈希函数,可能永远不会看到最坏情况。