12 容器

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都支持

相关推荐
此生只爱蛋7 分钟前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
blammmp14 分钟前
Java:数据结构-枚举
java·开发语言·数据结构
何曾参静谧27 分钟前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
暗黑起源喵32 分钟前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong37 分钟前
Java反射
java·开发语言·反射
Troc_wangpeng38 分钟前
R language 关于二维平面直角坐标系的制作
开发语言·机器学习
努力的家伙是不讨厌的40 分钟前
解析json导出csv或者直接入库
开发语言·python·json
Envyᥫᩣ1 小时前
C#语言:从入门到精通
开发语言·c#
童先生1 小时前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu1 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法