C++语言导学(5): 容器¶
引言¶
如果一个类的主要目的是保存对象,那么通常称之为容器(container)。
这里主要简单概述一下这些标准库容器:
- vector: 有序序列
- list: 双向链表
- map: 关联字典
- unordered_map: 无序哈希
vector¶
一个vector就是一个给定类型元素的序列,元素在内存中是连续存储的。
对于vector最主要的操作是push_back()追加内容,但容量不足的时候它会自动扩充容量,它有一套自己的策略来扩充容器,效率很高。
vector足够灵活、高效,应该作为默认容器;尽量避免容器的拷贝复制,而是使用引用或指针来避免这种耗时操作。
但vector为了保证高效以应用到性能关键的程序中,不会进行下标越界检查,比如:
#include <iostream>
#include <vector>
using namespace std;
int main(){
try{
vector<int> vData;
//int i = vData[vData.size()];
int i = vData.at(vData.size()); // 推荐使用at()方法而不是下标访问
} catch(out_of_range& err){
cerr << "range error\n";
} catch(...){
cerr << "unknow exception\n";
}
return 0;
}
list¶
如果希望在一个序列中添加、删除元素而不需要移动其他元素,则选择list,它是双向链表。
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
void display(const list<int>& data){
for(auto &x:data)
cout << x << ",";
cout << "\n";
}
int main()
{
list<int> lData{10,2,3,5,8,1};
display(lData); // 10,2,3,5,8,1,
auto p = find(lData.begin(), lData.end(),3);
auto q = find(lData.begin(), lData.end(),8);
lData.insert(p,12); // 在迭代器p前面插入值
display(lData); // 10,2,12,3,5,8,1,
lData.erase(p); // 销毁元素
display(lData); // 10,2,12,5,8,1,
lData.erase(q); // p,q并没有因为前面insert操作而失效
display(lData); // 10,2,12,5,1,
return 0;
}
当数据量较小时,vector性能会优于list,除非有理由选择list,否则应该使用vector。
vector无论在遍历(find,count)性能还是排序和搜索(sort,equal_range)性能都优于list。
map¶
map又叫关联数组或字典,用平衡二叉树(红黑树)实现。
map<string, int> mData{{"David",123},{"Tom",123}};// David->123;Tom->123;
mData["Leslie"] = 578; // David->123;Leslie->578;Tom->123;
mData["Zhu"]; // David->123;Leslie->578;Tom->123;Zhu->0;
进行下标操作本质是进行一次搜索,如果没找到key就自动插入新元素,value是对应的默认值。
一般常用操作是find()和insert()。
unordered_map¶
标准库中哈希容器被叫做“无序”容器。
underorder_map的操作和map没太大区别,区别在于不是用一个有序函数进行比较操作,而是使用哈希函数。
比如:
#include <iostream>
#include <unordered_map>
using namespace std;
struct Record{
friend struct RHash;
string name;
int age;
Record(const string& s, const int& i): name(s), age(i){}
bool operator==(const Record& rhs) const {
return name == rhs.name && age == rhs.age;
}
};
struct RHash{
size_t operator()(const Record& r) const {
return hash<string>()(r.name)^hash<int>()(r.age);
}
};
void display(const unordered_map<Record,int,RHash>& data){
cout << "unordered map: ";
for(auto &x:data)
cout << "("<<x.first.name<<","<<x.first.age<<")" << "->" << x.second << ";";
cout << "\n";
}
int main()
{
unordered_map<Record,int,RHash> uData{{{"David",26},123}}; // 使用自定义哈希函数
display(uData); // (David,26)->123;
uData[Record("Tom",30)] = 456;
display(uData); // (Tom,30)->456;(David,26)->123;
uData[Record("Leslie",35)] = 578;
display(uData); // (Leslie,35)->578;(Tom,30)->456;(David,26)->123;
uData[Record("Zhu",40)];
display(uData); // (Zhu,40)->0;(Leslie,35)->578;(Tom,30)->456;(David,26)->123;
return 0;
}
- 微信搜索: 「 MinYiLife 」, 关注公众号!
- 本文链接: https://www.lesliezhu.com/blog/2022/10/26/cpp_5/
- 版权声明: 原创文章,如需转载请注明文章作者和出处。谢谢!