C++ set、map

发布于:2024-04-25 ⋅ 阅读:(92) ⋅ 点赞:(0)

关联式容器

C++STL包含了序列式容器和关联式容器:

  1. 序列式容器:vector/list/deque
  2. 关联式容器:set/map等

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

键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。
比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应
该单词,在词典中就可以找到与其对应的中文含义。
SGI-STL中关于键值对的定义:

template <class T1, class T2>
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。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。unordered系列均为哈希结构。

set

set的介绍

  1. set是按照一定次序存储元素的容器。
  2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
  5. set在底层是用二叉搜索树(红黑树)实现的。

set的使用

#include <iostream>
#include <set>
using namespace std;

int main()
{
	//插入元素(去重且排序)
	set<int> s; // 默认是升序
	// set<int, greater<int>> s; // 这样是降序
	s.insert(4);
	s.insert(4);
	s.insert(1);
	s.insert(3);
	s.insert(6);
	s.insert(6);

	// 迭代器遍历
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		*it++;
	}
	cout << endl;

	// 范围for遍历
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	// 删除3 (存在)
	s.erase(3);
	// 删除4
	set<int>::iterator pos = s.find(4);
	if (pos != s.end())
	{
		s.erase(pos);
	}
	// s.erase(100); // 删除不存在的值没有影响
	// s.erase(s.end()); 会崩掉
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//容器中值为4的元素个数
	cout << s.count(6) << endl; // 1

	//容器大小
	cout << s.size() << endl; // 4

	//清空容器
	s.clear();

	//容器判空
	cout << s.empty() << endl; // 1
	return 0;
}

multiset

multiset容器与set容器的底层实现一样,都是平衡搜索树(红黑树);
multiset容器和set容器的唯一区别就是multiset容器当中存储的元素是可以重复的。

#include <iostream>
#include <set>
using namespace std;

int main()
{
	// 查找在不在
	// 插入元素(重复且排序)
	multiset<int> ms;
	ms.insert(1);
	ms.insert(2);
	ms.insert(3);
	ms.insert(3);
	ms.insert(2);
	ms.insert(3);
	for (auto e : ms)
	{
		cout << e << " ";
	}
	cout << endl; //1 2 2 3 3 3 4
	return 0;
}

multiset

  • find():返回第一个中序的第一个val
  • count():返回值为val的元素个数

set

  • find():返回值为val的元素的迭代器l
  • count():值为val的元素存在则返回1,不存在则返回0

map

map的介绍

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

map的使用

#include <iostream>
#include <map>

using namespace std;

int main()
{
	map<string, string> m;

	// 构造匿名对象插入
	m.insert(pair<string, string>("left", "左边"));
	m.insert(pair<string, string>("right", "右边"));
	m.insert(pair<const char*, const char*>("up", "上边"));

	// 调用make_pair函数模板插入
	// 我们只需向make_pair函数传入key和value,
	// 该函数模板会根据传入参数类型进行自动隐式推导,
	// 最终构造并返回一个对应的pair对象。
	m.insert(make_pair("down", "下边")); // 推荐这个最优(能省即省,能少敲就少敲,qwq)

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

	// 范围for遍历
	for (auto e : m)
	{
		cout << "<" << e.first << "," << e.second << ">";
		cout << endl;
	}
	cout << endl;

	// pair里的 key有const,而value没有const
	for (auto& e : m)
	{
		e.first += '1'; // 不可修改
		e.second += '1'; // 可修改 

		cout << "<" << e.first << "," << e.second << ">";
		cout << endl;
	}
	cout << endl;


	return 0;
}

make_pair函数模板:

template <class T1, class T2>
pair<T1, T2> make_pair(T1 x, T2 y)
{
	return (pair<T1, T2>(x, y));
}

insert的返回值

insert函数的返回值也是一个pair对象,该pair对象中第一个成员的类型是map的迭代器类型,第二个成员的类型的一个bool类型,具体含义如下:

  1. 若待插入元素的键值key在map当中不存在,则insert函数插入成功,并返回插入后元素的迭代器和true。
  2. 若待插入元素的键值key在map当中已经存在,则insert函数插入失败,并返回map当中键值为key的元素的迭代器和false。

map的[ ]

mapped_type& operator[] (const key_type& k);

[ ]运算符重载实现的逻辑实际上就是以下三个步骤:

  • 调用insert函数插入键值对。
  • 拿出从insert函数获取到的迭代器。
  • 返回该迭代器位置元素的值value。
mapped_type& operator[] (const key_type& k)
{
	//1、调用insert函数插入键值对
	pair<iterator, bool> ret = insert(make_pair(k, mapped_type()));
	//2、拿出从insert函数获取到的迭代器
	iterator it = ret.first;
	//3、返回该迭代器位置元素的值value
	return it->second;
}
  • 如果k不在map中,则先插入键值对<k, v()>,然后返回该键值对中v对象的引用。
  • 如果k已经在map中,则返回键值为k的元素对应的v对象的引用。
#include <iostream>
#include <map>

using namespace std;

int main()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;

	for (auto& str : arr)
	{
		//auto ret = countMap.find(str);
		//if (ret == countMap.end())
		//{
		//	// 么有表示第一次出现,插入
		//	countMap.insert(make_pair(str, 1));
		//}
		//else
		//{
		//	// 次数++
		//	ret->second++;
		//}
		countMap[str]++; // 6 3 2
	}


	for (auto& str : arr)
	{
		countMap[str]++; // 12 6 4
	}

	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	
	return 0;
}

multimap

multimap容器与map容器的底层实现一样,也都是平衡搜索树(红黑树);
multimap容器和map容器的区别与multiset容器和set容器的区别一样,multimap容器当中存储的元素是可以重复的。

#include <iostream>
#include <string>
#include <map>
using namespace std;

int main()
{
	multimap<string, string> mm;
	//插入元素(重复且排序)
	mm.insert(make_pair("left", "左边"));
	mm.insert(make_pair("left", "左边"));
	mm.insert(make_pair("right", "右边"));
	mm.insert(make_pair("up", "上边"));
	mm.insert(make_pair("left", "左边"));
	mm.insert(make_pair("right", "右边"));
	mm.insert(make_pair("up", "上边"));

	for (auto e : mm)
	{
		cout << "<" << e.first << "," << e.second << ">";
		cout << endl;
	}
	cout << endl; 

	return 0;
}

multimap

  • find():返回底层搜索树中序的第一个键值为key的元素的迭代器
  • count():返回键值为key的元素个数

map

  • find():返回值为key的元素的迭代器
  • count():键值为key的元素存在则返回1,不存在则返回0

网站公告

今日签到

点亮在社区的每一天
去签到