12 容器
- 1、线性容器(基本容器)
-
- [1.1 向量 vector](#1.1 向量 vector)
- [1.2 双端队列 deque](#1.2 双端队列 deque)
- [1.3 列表 list](#1.3 列表 list)
- [2、 适配器容器](#2、 适配器容器)
-
- [2.1 栈](#2.1 栈)
- [2.2 队列](#2.2 队列)
- [2.3 优先队列](#2.3 优先队列)
- 3、关联容器
-
- [3.1 映射 map](#3.1 映射 map)
- [3.2 多重映射 multimap](#3.2 多重映射 multimap)
- [3.3 集合 set](#3.3 集合 set)
- [3.4 多重集合](#3.4 多重集合)
- 4、无序容器
1、线性容器(基本容器)
1.1 向量 vector
-
成员函数
-
初始化
- 向量中的元素被存储在一段连续的内存空间中
- 向量维护的内存空间会随着新元素的增加而自动增长。
- 如果内存空间无法满足新元素的增加,向量会开辟新的足够的连续的内存空间 ,并把原内存空间的数据复制到新的内存空间,释放原内存空间。
- 向量的增加会伴随着内存空间的分配和释放,元素复制和销毁等额外开销。
- 如果能够在创建向量时,合理预分配一些空间将很大程度上缓解这些额外开销。
-
迭代器的使用
c++
class HumanVector{
public:
HumanVector(const char * name = " ",int age=0) :m_name(name),m_age(age){
//cout << "缺省构造了:" << m_name << "(" << ")" <<m_age<< endl;
}
HumanVector(const HumanVector & that) :m_name(that.m_name),m_age(that.m_age){
//cout << "用" << that.m_age << "(" << &that << ")" << "克隆了:" << m_name << "(" << this << ")" << endl;
}
~HumanVector(){
//cout << "析构了:" << m_name << "(" << this << ")"<<endl;
}
bool operator==(const HumanVector & that){
return m_age == that.m_age && m_name == that.m_name;
}
bool operator<(const HumanVector & that){
return m_age < that.m_age;
}
private:
string m_name;
int m_age;
friend ostream& operator<<(ostream& os, const HumanVector& that);
};
ostream& operator<<(ostream& os, const HumanVector& that){
os << that.m_name << ":" << that.m_age;
return os;
}
#include<algorithm>
int main(){
vector<HumanVector> vs{ HumanVector("1", 10), HumanVector("2", 20), HumanVector("3", 30), HumanVector("4", 40) };
vs.push_back(HumanVector("51", 25));
vs.push_back(HumanVector("6", 31));
PrintHumanVector("打印:", vs);
typedef vector<HumanVector>::iterator IT;
IT insert = vs.end();
vs.insert(insert, HumanVector("11", 34));// 增操作:insert
PrintHumanVector("新增之后的数据:",vs);
IT edit = vs.begin();
*edit = HumanVector("1", 40); // 改操作
PrintHumanVector("修改之后的数据:", vs);
IT fit = find(vs.begin(), vs.end(), HumanVector("8", 23));// 查操作 :find 需要引入algorithm头文件
if (fit != vs.end()){
vs.erase(fit);//找到了就删除 删操作:erase
}
PrintHumanVector("删除后的数据", vs);
sort(vs.begin(), vs.end()); // 排序操作 : sort,需要引入algorithm头文件
PrintHumanVector("比较后的数据", vs);
}
1.2 双端队列 deque
- 双端队列和向量的差别
- 和向量差别就是首尾两端同样都是开放的,因此他同时提供了首尾两端增删元素的接口
- 没有提供设置/获取容量的函数,设置和获取容器大小的函数存在。
- 成员函数
c++
int main(){
deque<HumanVector> vs{ HumanVector("1", 10), HumanVector("2", 20), HumanVector("3", 30), HumanVector("4", 40) };
vs.push_back(HumanVector("51", 25));
vs.push_back(HumanVector("6", 31));
vs.push_back(HumanVector("7", 45));
vs.push_back(HumanVector("8", 23));
vs.push_back(HumanVector("9", 67));
vs.push_back(HumanVector("10", 9));
PrintHumanVector("打印:", vs);
vs.pop_front();
vs.pop_back();
PrintHumanVector("删除头尾节点后:", vs);
vs.insert((++vs.begin()), HumanVector("11", 34));// 增操作:insert
PrintHumanVector("新增之后的数据:", vs);
typedef deque<HumanVector>::iterator IT;
IT edit = vs.begin();
*edit = HumanVector("1", 40); // 改操作
PrintHumanVector("修改之后的数据:", vs);
IT fit = find(vs.begin(), vs.end(), HumanVector("8", 23));// 查操作 :find 需要引入algorithm头文件
if (fit != vs.end()){
vs.erase(fit);//找到了就删除 删操作:erase
}
PrintHumanVector("删除后的数据", vs);
sort(vs.begin(), vs.end()); // 排序操作 : sort,需要引入algorithm头文件
PrintHumanVector("比较后的数据", vs);
return 0;
}
1.3 列表 list
- 成员函数
2、 适配器容器
2.1 栈
- 定义形式
- stack<元素类型,底层容器类型> 堆栈对象
- 底层容器
- deque(默认) / vector / list / 自己实现的容器
- 成员函数
push ->push_back
pop ->pop_back
top -> back
size -> size
empty -> empty
c++
int main(){
stack <int, deque<int> > s;
s.push(1); s.push(2); s.push(3); s.push(4); s.push(5);
while (!s.empty()){
cout << s.top() << endl;// 返回栈顶元素,但不出栈
s.pop();// 出栈
}
return 0;
}
2.2 队列
- 定义形式
- queue<元素类型,底层容器类型> 队列对象
- 底层容器
deque(默认) / list,不能使用vector - 成员函数
push -> push_back
pop -> pop_front
back - > back
front -> front
size -> size
empty -> empty
c++
int main(){
queue<int, deque<int>> s;
s.push(1); s.push(2); s.push(3); s.push(4); s.push(5);
while (!s.empty()){
cout << s.front() << endl;// 返回队列元素,但不出队列
s.pop();// 出队列
}
return 0;
}
2.3 优先队列
- 定义形式
priority_queue<元素类型,底层容器类型> 优先队列对象 - 底层容器
deque / vector(默认),不能使用list (因其不支持随机迭代) - 注意事项
优者先出,默认以大者为优(默认内部使用<运算符进行比较) - 可以通过比较器定制比较规则
并不是出队列时挑 ,而是进队列时就保证有序。 - 成员函数
push -> push_back
pop -> pop_back
top -> back
size -> size
empty -> empty
c++
int main(){
priority_queue<int, deque<int>> pq;// 比较器不给的话,内部是使用<实现的比较
pq.push(5);pq.push(1);pq.push(7);pq.push(4);pq.push(9);
while (!pq.empty()){
cout << pq.top() << endl;// 返回队列元素,但不出队列
pq.pop();// 出队列
}
return 0;
}
3、关联容器
3.1 映射 map
平衡有序二叉树(红黑树),检索信息效率极高,但是修改的效率极低,适用于结构相对稳定,但是需要频繁的检索信息
- 映射容器的每个节点保存的为pair对象(键/值 对)
- pair类模板
c++
template<typename FIRST, typename SECOND>
class pair {
pair(FIRST f, SECOND s):first(f),second(s) {}
FIRST first; // 保存 键
SECOND seond; // 保存 值
}
- 基本使用
c++
class Candidata{
public :
Candidata(const char * name = " ") :m_name(name), m_vote(0){}
string getName(){
return m_name;
}
int getVote(){
return m_vote;
}
void setVote(){
++m_vote;
}
private:
string m_name;
int m_vote;
friend ostream & operator<<(ostream& os, const Candidata & that);
};
ostream & operator<<(ostream& os, const Candidata & that){
os << that.m_name << " : " << that.m_vote << ' ';
return os;
}
void PrintMap(map<char, Candidata>& m){
typedef map<char, Candidata>::iterator IT;
for (IT it = m.begin(); it != m.end(); it++){
cout << it->first << " " << it->second << endl;
}
}
int main(){
// 几种向map中添加节点的方式
map<char, Candidata>m{ { 'A', Candidata("张飞") } };
m.insert(pair<char, Candidata>('B', Candidata("赵云")));
m.insert(make_pair('C', Candidata("关羽")));
m.insert({ { 'D', Candidata("马超") }, { 'E', Candidata("马超") } });
m['F'] = Candidata("黄忠");
for (int i = 0; i < 10; i++){
PrintMap(m);
char a;
cin >> a;
/*try{
m.at(a).setVote();
}
catch (out_of_range &e){
cout << "废票" << endl;
}*/
/*typedef map<char, Candidata>::iterator IT;
IT it = m.find(a);
if (it != m.end()){
it->second.setVote();
}
else{
cout << "废票" << endl;
}*/
}
PrintMap(m);
return 0;
}
3.2 多重映射 multimap
- 允许键重复的映射,表示一对多的逻辑关系,不支持下标运算符。
定义形式: multimap<键类型,值类型> 映射对象;
c++
void PrintMultimap(multimap<string,int>&m){
for (multimap<string, int>::const_iterator it = m.begin(); it != m.end(); it++){
cout << (*it).first << (*it).second << endl;
}
}
int main(){
multimap<string, int>m{ {"张飞",90 } };
m.insert(pair<string, int>("赵云",80));
m.insert(make_pair("关羽",88));
m.insert({ { "马超",77 }, {"马超",79 },{"关羽",90} },{"张飞",60 });
PrintMultimap(m);
return 0;
}
3.3 集合 set
- 没有值只有键的映射
- 与向量等基本容器相比最大优势就是排重。
- 定义形式:set<T> 集合对象;
c++
void PrintSet(set<int>&m){
for (set<int>::const_iterator it = m.begin(); it != m.end(); it++){
cout << *it << endl;
}
}
int main(){
set<int>s{1,2,3,4};
s.insert(5);
s.insert({6,7,8,4});
cout << "集合中节点的个数" << s.size() << endl;
PrintSet(s);
return 0;
}
3.4 多重集合
- 键S可以重复的集合。
- 定义形式:multiset <T> 多重集合对象
c++
void PrintMultiset(multiset<int>&m){
for (multiset<int>::const_iterator it = m.begin(); it != m.end(); it++){
cout << *it << endl;
}
}
int main(){
multiset<int>s{ 1, 2, 3, 4 };
s.insert(5);
s.insert({ 9, 8, 7, 4 });
cout << "集合中节点的个数" << s.size() << endl;
PrintMultiset(s);
return 0;
}
4、无序容器
无序映射:哈希散列表
哈希算法------》哈希散列表-------》无序映射
数学算法 数据结构 容器
- 哈希算法
- 定义:哈希算法是用给定范围的基本类型的数据项也包括string,生成整数值的过程,哈希算法产生的值叫做哈希值或者哈希码,理想情况下,每个对象产生的哈希值是唯一的,但实际是可能产生重复的。重复的哈希值称为哈希碰撞。(概率极低)
- 哈希函数模板
c++
template<typename Key> class hash{
...
size_t operator()(Key k){}
...
};
- unordered_map
- 定义形式
unordered_map<键的类型,值的类型[,哈希器类型][,判等器类型]> 对象; - 底层实现
c++
template <typename K, typename V, typeame H = hash<Key>, ... >
class unordered_map{
...
};
案例:
c++
void PrintUnordered_map(unordered_map<string,int>&m){
for (unordered_map<string,int>::const_iterator it = m.begin(); it != m.end(); it++){
cout << (*it).first << (*it).second << endl;
}
}
int main(){
unordered_map<string, int, hash<string>>um{ { "张飞", 22 } };
// 构造函数中 (1)定义pair对象("张飞",22)
// (2)定义hash<string>类对象,利用这个对象("张飞")-->触发小括号操作符函数,获取hash值
// (3)将哈希值进行处理(例如:对10取余)
// (4) 将哈希值和pair对象保存到哈希散列表相应的支脉
um.insert(pair<string, int>("赵云", 32));
um.insert(make_pair("关羽", 34));
um["马超"] = 48;
PrintUnordered_map(um);
return 0;
}
// map 支持的操作,unordered_map都支持