(C++ 进阶)map & set

目录

一  关联式容器(KV模型)

二 键值对

三 树形结构的关联式容器

1  set

1.1 set的基本概念与注意事项

1.2  set的遍历

1.3 set 的查找与删除

2 multiset

3 map

3.1 概念

3.2 map的迭代器遍历方式

3.3 简化嵌套结构

3.4 统计水果出现次数

3.5 [ ]的重载使用

3.6 topK问题

4 multimap


一  关联式容器(KV模型)

用关联式容器 来存储数据,与序列式容器不同的是,其 里面存储的是 结构的键值对,在 数据检索时比序列式容器效率更高。

二 键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量 key value key 代表键值, value 表示与 key 对应的信息
SGI-STL中关于键值对的定义:
template 
struct pair
{
 typedef T1 first_type;
 typedef T2 second_type;
 T1 first;
 T2 second;
 
 pair()
 : first(T1()), 
   second(T2())
 {}
 
 pair(const T1& a, const T2& b)
 : first(a), 
   second(b)
 {}

};

三 树形结构的关联式容器

为了满足不同的使用场景, STL 总共实现了两种不同结构的管理式容器: 树型结构与哈希结构 树型结构的关联式 容器主要有四种: map、set、multimap、multiset 。这四种容器的共同点是:使用平衡搜索树 ( 即红黑树 ) 作为其底层结构,容器中的元素是一个有序的序列。

1  set

1.1 set的基本概念与注意事项

①  set 是按照一定次序存储元素的容器
②   set 中,元素的 value 也标识它 (value 就是 key ,类型为 T) ,并且每个 value 必须是唯一的。 set 中的元素不能在容器中修改( 元素总是 const) ,但是可以从容器中插入或删除它们。
③   在内部, set 中的元素总是按照其内部比较对象 ( 类型比较 ) 所指示的特定严格弱排序准则进行排序。
④  set 容器通过 key 访问单个元素的速度通常比 unordered_set 容器慢,但它们允许根据顺序对子集进行直接迭代。
  set 在底层是用二叉搜索树 ( 红黑树 ) 实现的。
注意:
①   map/multimap 不同, map/multimap 中存储的是真正的键值对 set中只放value,但在底层实际存放的是由构成的键值对。
  set 中插入元素时,只需要插入 value 即可,不需要构造键值对。
  set 中的元素不可以重复 ( 因此可以使用 set 进行去重 )
   使用 set 的迭代器遍历 set 中的元素,可以得到有序序列
⑤  set 中的元素默认按照小于来比较
  set 中查找某个元素,时间复杂度为:O(log2N)
  set 中的元素不允许修改,因为Value就是它的键,随意修改会破坏树的结构。
⑧  set 中的底层使用二叉搜索树 ( 红黑树 ) 来实现。

1.2  set的遍历

	set s;
	s.insert(10);
	s.insert(1);
	s.insert(99);
	s.insert(101);
	s.insert(50);
	s.insert(10);
	s.insert(6);
	s.insert(55);
	s.insert(10);

	//遍历方式一 迭代器
	//排序加去重
	set::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//降序
	set::reverse_iterator it1 = s.rbegin();
	while (it1 != s.rend())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
	//遍历方法二 范围for(基于迭代器)
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

1.3 set 的查找与删除

	//查找
	set sstr;
	sstr.insert("sort");
	sstr.insert("add");
	sstr.insert("sum");
	sstr.insert("adjust");
	sstr.insert("list");
	set::iterator iter = sstr.find("list");
	if (iter != sstr.end())
	{
		cout << "找到了" << *iter << endl;
	}
	else
	{
		cout << "没找到" << endl;
	}

	//因为set底层为搜索二叉树KEY模型,所以不支持随便更改数据的值,否则可能会破坏结构
	//删除
	auto pos = sstr.find("sort");
	sstr.erase(pos);
	sstr.erase("list");

2 multiset

 与set的区别是,multiset中的元素可以重复,set是中value是唯一的。

3 map

3.1 概念

①  map 是关联容器,它按照特定的次序 ( 按照 key 来比较 ) 存储由键值 key 和值 value 组合而成的元素。
②   map 中, 键值key通常用于排序和惟一地标识元素 而值 value 中存储与此键值 key 关联的内容。键值key和值 value 的类型可能不同,并且在 map 的内部, key value 通过成员类型 value_type 绑定在一起,为其取别名称为pair: typedef pair value_type;
③   在内部, map 中的元素总是按照键值 key 进行比较排序的。
④  map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行直接迭代( 即对 map 中的元素进行迭代时,可以得到一个有序的序列 )
⑤  map支持下标访问符,即在[]中放入key,就可以找到与key对应的value
⑥  map 通常被实现为二叉搜索树 ( 更准确的说:平衡二叉搜索树 ( 红黑树 ))

3.2 map的迭代器遍历方式

//map的基本使用
void map_test(void)
{
	map m;
	//调用pair的构造函数,构造一个匿名对象插入
	m.insert(pair(1, 8.9));
	m.insert(pair(5, 45.4));
	m.insert(pair(7, 9.0));
	m.insert(pair(2, 8.9));
	m.insert(pair(3, 7.8));
	m.insert(pair(7, 6.9));//插入不成功,键值相同
	//调用函数模板构造对象。
	//好处:不需要去声明pair的参数,让函数自己推演,用起来方便
	m.insert(make_pair(7, 6.9));

	//迭代器遍历
	map::iterator it = m.begin();
	while (it != m.end())
	{
		//cout << (*it).first << ":" << (*it).second << "  ";
		cout << it->first << ":" << it->second << "  ";
		it++;
	}
	cout << endl;
}

3.3 简化嵌套结构

//简化嵌套结构
void map_test1(void)
{
	typedef std::map DICT;
	typedef std::pair DICT_KV;
	typedef std::map::iterator DICT_IT;

	//std::map dic;
	DICT dic;

	//dic.insert(std::pair("insert", "插入"));
	//dic.insert(std::pair("sort", "排序"));
	//dic.insert(std::pair("find", "查找"));
	dic.insert(DICT_KV("insert", "插入"));
	dic.insert(DICT_KV("sort", "排序"));
	dic.insert(DICT_KV("find", "查找"));
	dic.insert(DICT_KV("left", "左边"));

	DICT_IT dit = dic.begin();
	while (dit != dic.end())
	{
		//key值不可修改,但是value可以修改
		dit->second.insert(0, "{");
		dit->second += "}";

		cout << dit->first << "--" << dit->second << endl;
		dit++;
	}

	auto ret = dic.find("left");
	if(ret != dic.end())
	{
		//可读性优化
		string& str = ret->second;
		str.insert(str.size() - 1, "、剩余");
	}

	cout << endl;
	dit = dic.begin();
	while (dit != dic.end())
	{
		cout << dit->first << "--" << dit->second << endl;
		dit++;
	}

}

3.4 统计水果出现次数

//统计水果出现次数
void map_test2(void)
{
	思路一
	//string arr[] = { "苹果","苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "香蕉", "苹果", "苹果" };
	//std::map countMap;
	//for (const auto& str : arr)
	//{
	//	std::map::iterator it = countMap.find(str);
	//	//找到了就不是第一次出现,数量加加
	//	if (it != countMap.end())
	//	{
	//		it->second++;
	//	}
	//	//没找到,第一次出现,插入
	//	else
	//	{
	//		countMap.insert(make_pair(str,1));
	//	}
	//}
	//for (const auto& e : countMap)
	//{
	//	cout << e.first << "--" << e.second << endl;
	//}

	思路二
	//string arr[] = { "苹果","苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
	//std::map countMap;
	//for (const auto& str : arr)
	//{
	//	auto ret = countMap.insert(make_pair(str, 1));
	//	if(ret.second==false)
	//	{
	//		ret.first->second++;
	//	}
	//}
	//for (const auto& e : countMap)
	//{
	//	cout << e.first << "--" << e.second << endl;
	//}
	
	//思路三
	string arr[] = { "苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
	map countMap;
	for (const auto& str : arr)
	{
			countMap[str]++;
	}
	for (const auto& e : countMap)
	{
		cout << e.first << "--" << e.second << endl;
	}
}

3.5 [ ]的重载使用

//[key],key为结点键值,[key]会返回结点的value的引用
void map_test3(void)
{
	map sortmap;
	sortmap.insert(make_pair("left", "左边"));
	cout << sortmap["left"] << endl;

	//插入right,value为右边。
	sortmap["right"] = "右边";
	//插入sort,value为缺省值
	sortmap["sort"];
	sortmap["insert"] = "插入";

	sortmap["left"] += "、剩余";
	cout << sortmap["left"] << endl;

}

3.6 topK问题

//TOPK问题
struct MapItCompare
{
	bool operator()(map::iterator x, map::iterator y)
	{
		return x->second > y->second;
	}
};
void map_test4(void)
{
	string arr[] = { "苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
	map countMap;
	for (const auto& str : arr)
	{
		countMap[str]++;
	}
	//for (const auto& e : countMap)
	//{
	//	cout << e.first << "--" << e.second << endl;
	//}

	//排序一
	vector::iterator> v1;
	map::iterator countMapIt = countMap.begin();
	while (countMapIt != countMap.end())
	{
		v1.push_back(countMapIt);
		countMapIt++;
	}
	sort(v1.begin(),v1.end(),MapItCompare());

	//排序二
	//map> sortMap;//降序
	map sortMap;//升序
	for (auto e : countMap)
	{
		sortMap.insert(make_pair(e.second, e.first));
	}
	for (auto e : sortMap)
	{
		cout << e.second << "--" << e.first << endl;
	}
}

4 multimap

multimap和map的区别:①map中的key是唯一的,而multimap中key是可以重复的。
                                          ②multimap中没有重载operator[]操作,因为键值可以重复

你可能感兴趣的:(C/C++学习笔记,c++,数据结构)