容器用来管理某类对象。为了应付程序中的不同需求,STL 准备了两类共七种基本容器类型:
序列式容器(Sequence
containers),此为可序群集,其中每个元素均有固定位置—取决于插入时机和地点,和元素值无关。如果你以追加方式对一个群集插入六个元素,它们的排列次序将和插入次序一致。STL提供了三个序列式容器:向量(vector)、双端队列(deque)、列表(list),此外你也可以把
string 和 array 当做一种序列式容器。 关联式容器(Associative
containers),此为已序群集,元素位置取决于特定的排序准则以及元素值,和插入次序无关。如果你将六个元素置入这样的群集中,它们的位置取决于元素值,和插入次序无关。STL提供了四个关联式容器:集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)。
优点:支持随机访问,即 [] 操作和 .at(),所以查询效率高。
缺点:当向其头部或中部插入或删除元素时,为了保持原本的相对次序,插入或删除点之后的所有元素都必须移动,所以插入的效率比较低。
适用场景:适用于对象简单,变化较小,并且频繁随机访问的场景。
//定义一个vector 插入6个元素,然后打印所有元素
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
vector<int> vecTemp;
for (int i = 0; i<6; i++)
vecTemp.push_back(i);
for (int i = 0; i<vecTemp.size(); i++)
cout << vecTemp[i] <<" "; // 输出:0 1 2 3 4 5
return 0;
}
2.deque:
优点:支持随机访问,即 [] 操作和 .at(),所以查询效率高;可在双端进行 pop,push。
缺点:不适合中间插入删除操作;占用内存多。
适用场景:适用于既要频繁随机存取,又要关心两端数据的插入与删除的场景。
//声明一个浮点类型的deque,并在容器尾部插入6个元素,最后打印所有元素。
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
deque<float> dequeTemp;
for (int i = 0; i<6; i++)
dequeTemp.push_back(i);
for (int i = 0; i<dequeTemp.size(); i++)
cout << dequeTemp[i] << " "; // 输出:0 1 2 3 4 5
return 0;
}
3.list
优点:内存不连续,动态操作,可在任意位置插入或删除且效率高。
缺点:不支持随机访问。
适用场景:适用于经常进行插入和删除操作并且不经常随机访问的场景。
//产生一个空list,将a至z的所有字符插入其中,循环每次打印移除集合的第一个元素,从而打印出所有元素
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
list<char> listTemp;
for (char c = 'a'; c <= 'z'; ++c)
listTemp.push_back(c);
while (!listTemp.empty())
{
cout <<listTemp.front() << " ";
listTemp.pop_front();
}
return 0;
}
成员函数empty()的返回值告诉我们容器中是否还有元素,只要这个函数返回
false,循环就继续进行。循环之内,成员函数front()会返回第一个元素,pop_front()函数会删除第一个元素。
4.set
优点:使用平衡二叉树实现,便于元素查找,且保持了元素的唯一性,以及能自动排序。
缺点:每次插入值的时候,都需要调整红黑树,效率有一定影响。
适用场景:适用于经常查找一个元素是否在某群集中且需要排序的场景。
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
set<int> setTemp;
setTemp.insert(3);
setTemp.insert(1);
setTemp.insert(2);
setTemp.insert(1);
set<int>::iterator it;
for (it = setTemp.begin(); it != setTemp.end(); it++)
{
cout << *it << " ";
}
return 0;
}
//输出结果:1 2 3。一共插入了 4 个数,但是集合中只有 3 个数并且是有序的,可见之前说过的 set 集合的两个特点,有序和不重复。
//当 set 集合中的元素为结构体时,该结构体必须实现运算符 ‘<’ 的重载:
#include
#include
#include
using namespace std;
struct People
{
string name;
int age;
bool operator <(const People p) const
{
return age < p.age;
}
};
int main(int argc, char* argv[])
{
set<People> setTemp;
setTemp.insert({
"张三",14});
setTemp.insert({
"李四", 16 });
setTemp.insert({
"隔壁老王", 10 });
set<People>::iterator it;
for (it = setTemp.begin(); it != setTemp.end(); it++)
{
printf("姓名:%s 年龄:%d\n", (*it).name.c_str(), (*it).age);
}
return 0;
}
/*
输出结果
姓名:王二麻子 年龄:10
姓名:张三 年龄:14
姓名:李四 年龄:16
*/
5.map
优点:使用平衡二叉树实现,便于元素查找,且能把一个值映射成另一个值,可以创建字典。
缺点:每次插入值的时候,都需要调整红黑树,效率有一定影响。
适用场景:适用于需要存储一个数据字典,并要求方便地根据key找value的场景。
#include "stdafx.h"
#include
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
map<int, string> mapTemp;
mapTemp.insert({
5,"张三" });
mapTemp.insert({
3, "李四"});
mapTemp.insert({
4, "隔壁老王" });
map<int, string>::iterator it;
for (it = mapTemp.begin(); it != mapTemp.end(); it++)
{
printf("学号:%d 姓名:%s\n", (*it).first, (*it).second.c_str());
}
return 0;
}
/*
输出结果:
学号:3 姓名:李四
学号:4 姓名:隔壁老王
学号:5 姓名:张三
*/