C++---map和set的使用

Posted Moua

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++---map和set的使用相关的知识,希望对你有一定的参考价值。

目录

一、基础知识

1、序列式容器和关联式容器

2、键值对

3、键值对的使用

二、map和set的介绍和使用

1、set的介绍

2、set的使用

3、map的介绍

4、map的使用

三、multiset和multimap的介绍和使用

1、multiset介绍

2、multiset的使用

3、multimap介绍


一、基础知识

1、序列式容器和关联式容器

  • 序列式容器:底层是线性数据结构,且存储的是元素本身,称为序列式容器。例如:vector string list deque等。
  • 关联式容器:底层数据结构存储的是<key,value>的键值对,在数据检索时比序列是容器效率更高。

2、键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。

键值对的定义:

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)

        {}

};

3、键值对的使用

1)访问键值对中的元素

pair(K,V)  val;

//访问类型为K的元素

val.first

//访问类型为V的元素

val.second

2)构造一个键值对

make_pair(Key,Value)

二、map和set的介绍和使用

1、set的介绍

set基本介绍

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

注意

  • 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
  • set中插入元素时,只需要插入value即可,不需要构造键值对。
  • set中的元素不可以重复(向set中插入一个元素时,如果该元素已经在set中,则不进行任何操作,因此可以使用set进行去重)。
  • 使用set的迭代器遍历set中的元素,可以得到有序序列(二叉搜索树,左子树比根节点小右子树比根节点大,按照中序遍历就可以得到有序序列)。
  • 默认情况下set中的元素按照小于进行比较的。
  • set中查找某个元素的时间复杂度为:log(n) (平衡二叉搜索树,查找的时间复杂度为树的高度次)
  • set中的元素值是const的,不能进行修改。

2、set的使用

1)set的模板参数列表

  • T存储的元素类型,底层实际存储的是<value,value>的键值对。
  • Compare是比较方式,默认是小于。
  • Alloc是set中元素空间的管理方式,即空间配置器。

2)构造函数和析构函数

函数原型:

空构造:explicit set (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

迭代器区间构造:set (InputIterator first, InputIterator last, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

拷贝构造:set (const set& x);

使用举例:

void print(set<int>::iterator begin,set<int>::iterator end)
{
	while (begin != end)
	{
		std::cout << *begin << " ";
		begin++;
	}

	std::cout << std::endl;
}

int main()
{
	set<int> s1;//使用空构造构造一个空的set

	//向s1中插入元素,使s1不在为空
	s1.insert(5);
	s1.insert(8);
	s1.insert(6);
	s1.insert(3);
	s1.insert(9);

	print(s1.begin(), s1.end());

	//使用拷贝构造构造一个和s1具有相同元素的set s2
	set<int> s2(s1);
	print(s2.begin(),s2.end());

	//使用迭代器区间构造构造一个和s1相同的set s3
	set<int> s3(s1.begin(),s1.end());
	print(s3.begin(), s3.end());


	//使用数组、vector迭代器区间构造set s4、s5
	int array[5] = {1,2,3,4,5};
	vector<int> v(array,array+5);//使用数组构造vector
	
	set<int> s4(array,array+5);
	print(s4.begin(), s4.end());

	set<int> s5(v.begin(),v.end());
	print(s5.begin(), s5.end());


	//使用list迭代器构造set
	list<int> lt(array,array+5);
	set<int> s6(lt.begin(),lt.end());
	print(s6.begin(), s6.end());


	//使用string迭代器构造
	string str = "abcd";

	set<char> s7(str.begin(),str.end());
	auto it = s7.begin();
	while (it != s7.end())
	{
		std::cout << *it << " ";
		it++;
	}
	std::cout << std::endl;
	return 0;
}

3)迭代器

函数原型:

正向迭代器

iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;

反向迭代器

reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;

正向const迭代器

const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;

反向const迭代器

const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

使用举例:

int main()
{
	set<int> s1;
	s1.insert(5);
	s1.insert(8);
	s1.insert(6);
	s1.insert(3);
	s1.insert(9);

	//正向迭代器遍历
	set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//反向迭代器遍历
	set<int>::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
	return 0;
}

4)容量相关的接口

函数原型:

判空:bool empty() const;
计算size:size_type size() const;
计算max_size:size_type max_size() const;

使用示例:

int main()
{
	set<int> s1;
	s1.insert(5);
	s1.insert(8);
	s1.insert(6);
	s1.insert(3);
	s1.insert(9);

	cout << s1.size() << " " << s1.max_size() << endl;

	string str = "abcde";
	set<char> s2(str.begin(),str.end());

	cout << s2.size() << " " << s2.max_size() << endl;
	return 0;
}

5)基本操作(增、删、查)

函数原型:

插入元素
iterator insert (iterator position, const value_type& val);
pair<iterator,bool> insert (const value_type& val);
template <class InputIterator> void insert (InputIterator first, InputIterator last);

删除元素
void erase (iterator position);
size_type erase (const value_type& val);

//交换
void swap (set& x);

//查找
iterator find (const value_type& val) const;

//统计次数(均为1)
size_type count (const value_type& val) const;

 

使用举例:

void print(set<int>::iterator begin, set<int>::iterator end)
{
	while (begin != end)
	{
		std::cout << *begin << " ";
		begin++;
	}

	std::cout << std::endl;
}

int main()
{
	set<int> s1;
	s1.insert(5);
	s1.insert(8);
	s1.insert(6);
	s1.insert(3);
	s1.insert(9);

	print(s1.begin(),s1.end());
	//向s1中插入一个值
	s1.insert(15);//set中没有和要插入的值相同的值
	print(s1.begin(), s1.end());

	s1.insert(3);//要插入的值set中已经存在
	print(s1.begin(), s1.end());


	//删除
	s1.erase(15);
	print(s1.begin(), s1.end());


	//swap---交换两个set
	set<int> s2;
	s2.insert(50);
	s2.insert(80);
	s2.insert(60);
	s2.insert(30);
	s2.insert(90);

	s1.swap(s2);
	print(s1.begin(), s1.end());
	print(s2.begin(), s2.end());

	//查找
	auto it = s1.find(30);
	cout << *it << endl;
	s1.erase(it);
	print(s1.begin(), s1.end());

	//count
	cout << s1.count(50) << endl;

	return 0;
}

3、map的介绍

  • 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通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
注意:
  • map按照key值进行比较,因此map中的两个或两个以上元素的value值是可以相等的。

4、map的使用

1)模板类参数

  • Key键值对中key的类型
  • T键值对中value的类型
  • Compare是比较方式,默认是小于。map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
  • Alloc是set中元素空间的管理方式,即空间配置器。

2)构造函数

空构造:explicit map (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

迭代器区间构造

template <class InputIterator>

map (InputIterator first, InputIterator last, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

拷贝构造:map (const map& x);

3)迭代器

正向迭代器

iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;

反向迭代器

reverse_iterator rend();
const_reverse_iterator rend() const;
reverse_iterator rend();
const_reverse_iterator rend() const;

正向const迭代器

const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;

反向const迭代器

const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

4)容量相关

判空:bool empty() const;

计算size:size_type size() const;

计算max_size:size_type max_size() const;

5)operator[]

mapped_type& operator[] (const key_type& k);
//函数功能:返回key对应的value,如果不存在则插入

A call to this function is equivalent to:(*((this->insert(make_pair(k,mapped_type()))).first)).second

注意:在元素访问时,有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过key找到与key对应的value然后返回其引用,不同的是:当key不存在时,operator[]用默认value与key构造键值对 然后插入,返回该默认value,at()函数直接抛异常。
int main()
{
	map<char, int> m1;//构造一个空的map
	/*
	operator[]的原理是:
	用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
	如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
	如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
	operator[]函数最后将insert返回值键值对中的value返回*/

	m1['a'] = 65;

	return 0;
}

6)基本操作(增、删、该、查)

插入

按照键值对插入:pair<iterator,bool> insert (const value_type& val);

迭代器区间插入:iterator insert (iterator position, const value_type& val);

迭代器区间插入:template <class InputIterator> void insert (InputIterator first, InputIterator last);

删除

迭代器删除:void erase (iterator position);

key值删除:size_type erase (const key_type& k);

迭代器区间删除:void erase (iterator first, iterator last);

交换

void swap (map& x);

清空

void clear();

查找

iterator find (const key_type& k);

const_iterator find (const key_type& k) const;

统计

size_type count (const key_type& k) const;

使用举例

int main()
{
	map<char, int> m1;//构造一个空的map
	/*
	operator[]的原理是:
	用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
	如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
	如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
	operator[]函数最后将insert返回值键值对中的value返回*/

	m1['a'] = 65;
	m1.insert(pair<char, int>('a', 65));
	m1.insert(pair<char, int>('b', 66));
	m1.insert(pair<char, int>('c', 67));
	m1.insert(pair<char, int>('d', 68));
	m1.insert(pair<char, int>('e', 69));
	m1.insert(pair<char, int>('f', 70));

	auto it = m1.find('a');//key值查找

	//删除
	m1.erase('b');//key值删除
	m1.erase(it);//迭代器删除
	m1.erase(m1.begin(),m1.end());//迭代器区间删除

	//清空
	m1.clear();

	//拷贝构造
	map<char, int> m2(m1);
	m1.swap(m2);
	

	return 0;
}

三、multiset和multimap的介绍和使用

1、multiset介绍

  • multiset是按照某种特定顺序存储元素的容器,与set的区别是multiset中的元素是可以重复的。
  • 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
  • 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
  • multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。
  • multiset底层结构为二叉搜索树(红黑树)。
注意
  • multiset中再底层中存储的是<value, value>的键值对
  • mtltiset的插入接口中只需要插入即可
  • 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
  • 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
  •  multiset中的元素不能修改
  •  在multiset中找某个元素,时间复杂度为
  • multiset的作用:可以对元素进行排序

2、multiset的使用

int main()
{
	int array[] = {1,2,5,8,6,4,3,9,5,7,6,8,10,1};

	//使用迭代器区间进行构造
	multiset<int> ms1(array, array + 14);//允许存在重复元素
	return 0;
}

3、multimap介绍

  • Multimaps是关联式容器,它按照特定的顺序,存储由keyvalue映射成的键值对<key, value>,其中多个键值对之间的key是可以重复的。
  • multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内容。keyvalue的类型可能不同,通过multimap内部的成员类型value_type组合在一起,value_type是组合keyvalue的键值对:
  • typedef pair<const Key, T> value_type;
  • 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序的。
  • multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍历multimap中的元素可以得到关于key有序的序列。
  • multimap在底层用二叉搜索树(红黑树)来实现。

​​​​​​​注意:map和multimap唯一的区别就在于multimap中允许存在重复的键值对,而map中不能。还需注意的是multimap中没有重载[]。

以上是关于C++---map和set的使用的主要内容,如果未能解决你的问题,请参考以下文章

代码片段 - Golang 实现集合操作

C++map和set

C++map和set

peptide map DDA和IMS有啥区别

C++---map和set的使用

C++---map和set的使用