服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++中set/multiset与map/multimap的使用详解

C++中set/multiset与map/multimap的使用详解

2023-03-02 15:44蒋灵瑜的笔记本 C/C++

这篇文章主要为大家详细介绍了C++中set/multiset与map/multimap的使用,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下

一、关联式容器

vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。

而关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。 (插入删除只需挪动指针指向,无需挪动数据,查找时间logN)

关联式容器有两种,一种是map、set、multimap、multiset采用树形结构,他们的底层都是红黑树,另一种是哈希结构。

 

二、set的介绍

C++中set/multiset与map/multimap的使用详解

1、set是关联式容器,它表面上只存放value,实际底层中存放的是由<value,value>组成的键值对。

2、set调用find将采用中序遍历,可以用于排序+去重。

3、为了保证元素的唯一性,set中的元素均为const,所以并不能对元素进行修改,但可以进行插入删除。

1、接口count与容器multiset

count和find的作用一样,都是用于查找set中是否存在某个元素。

其实count是为了容器multiset设计的,该容器允许插入重复的元素,此时count会返回红黑树中被搜索元素的个数。

#include <iostream>
#include <set>

int main ()
{
std::set<int> myset;

// set some initial values:
for (int i=1; i<5; ++i) myset.insert(i*3);    // set: 3 6 9 12

for (int i=0; i<10; ++i)
{
  std::cout << i;
  if (myset.count(i)!=0)
    std::cout << " is an element of myset.\n";
  else
    std::cout << " is not an element of myset.\n";
}

return 0;
}

2、接口lower_bound和upper_bound

lower_bound返回大于等于目标值的迭代器,upper_bound返回大于目标值的迭代器,在set中用于返回目标值的迭代器。(比如找到两个边界的迭代器,就可以使用erase对数据进行删除)

#include <iostream>
#include <map>

int main ()
{
std::map<char,int> mymap;
std::map<char,int>::iterator itlow,itup;

mymap['a']=20;
mymap['b']=40;
mymap['c']=60;
mymap['d']=80;
mymap['e']=100;

itlow=mymap.lower_bound ('b');  // itlow points to b
itup=mymap.upper_bound ('d');   // itup points to e (not d!)

mymap.erase(itlow,itup);        // a => 20  e => 100

// print content:
for (std::map<char,int>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
  std::cout << it->first << " => " << it->second << '\n';

return 0;
}

 

三、map的介绍

C++中set/multiset与map/multimap的使用详解

map是关联式容器,根据特定的存储顺序,用于存储由键值及其映射值组合的元素。

可以看到Alloc中有一个键值对pair,这个pair是一个key/value结构的struct模板类。这个类将一对键值耦合在一起,所以,map的存储方式是通过在搜索二叉树中存储键值对pair,而搜索二叉树的k/v模型是在节点中存储key和value,并不相同。pair的结构:

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)
	{}
};

C++中set/multiset与map/multimap的使用详解

1、接口insert

C++中set/multiset与map/multimap的使用详解

make_pair是一个函数模板:

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

2、接口insert和operator[]和at

使用map统计每个字符出现个数

C++中set/multiset与map/multimap的使用详解

写法2的[]详解:

Value& operator[] (const Key& k)
{
	pair<iterator,bool> ret=insert(make_pair(k,Value() ) );
	//在结构体pair中找到first(一个map的迭代器),->解引用找到该迭代器的pair,再找该pair的second(即value)
	return ret.first->second;
}
//map的insert
pair<iterator,bool> insert (const value_type& pair);
//插入
dict["迭代器"];//在dict中找不到"迭代器"这个key,将新增一个节点,该节点的key为"迭代器",value为value类型的默认构造
//修改
dict["迭代器"]="iterator";//将key为"迭代器"的节点的value修改为"iterator"

不难看出map的operator[]兼具查找、插入、修改三种功能。(注意如果搜寻值不在map中,map可是会帮你新增一个节点的,map底层的红黑树将发生改变)

使用operator[],编译器会去调用insert(pair<const key,value()>)进行插入,如果没有找到key所对应的节点,则会新增一个节点并将该节点中pair的value置为value类型的默认构造;如果找到了,则返回该节点pair中value的引用。(可读可写)

at的功能和[]一样,区别在于用at找不到key将不会发生插入新节点,而是抛出异常。

3、容器multimap

multimap多个键值对中的key可以重复,所以并没有operator[]。同样的,使用find将返回中序遍历找到的第一个key值所处节点的迭代器。

 

四、map和set相关OJ

1、前K个高频单词

C++中set/multiset与map/multimap的使用详解

struct Compare
{
  bool operator()(const pair<int,string>& a,const pair<int,string>& b)
  {
      return a.first>b.first || (a.first==b.first&&a.second<b.second);
  }
};
class Solution {
public:
  vector<string> topKFrequent(vector<string>& words, int k) {
      vector<string> ret;
      map<string,int> dataMap;
      for(const auto& str : words)
      {
          dataMap[str]++;
      }
      vector<pair<int,string>> v;
      for(auto& kv : dataMap)
      {
          v.push_back(make_pair(kv.second,kv.first));//dataMap的first是string,second是int
      }
      sort(v.begin(),v.end(),Compare());
      for(int i=0;i<k;++i)
      {
          ret.push_back(v[i].second);
      }
      return ret;
  }
};

2、两个数组的交集

C++中set/multiset与map/multimap的使用详解

class Solution {
public:
  vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
      set<int> s1(nums1.begin(),nums1.end());//nums1排序+去重    
      set<int> s2(nums2.begin(),nums2.end());//nums2排序+去重
      vector<int> ret;
      for(auto& e : s1)
      {
          if(s2.find(e)!=s2.end())
          {
              ret.push_back(e);
          }
      }
      return ret;
  }
};

或者将两个数组排序+去重完毕后,使用双指针求解。(可用于找交集,差集)

以上就是C++中set/multiset与map/multimap的使用详解的详细内容,更多关于C++ set/multiset map/multimap的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/gfdxx/article/details/129019357

延伸 · 阅读

精彩推荐
  • C/C++C语言数据结构之深入探索顺序表

    C语言数据结构之深入探索顺序表

    大家好,今天给大家带来的是顺序表,我觉得顺序表还是有比较难理解的地方的,于是我就把这一块的内容全部整理到了一起,希望能够给刚刚进行学习数...

    Iceevov6142022-11-28
  • C/C++C++浅析引用的定义与使用

    C++浅析引用的定义与使用

    引用是C++一个很重要的特性,顾名思义是某一个变量或对象的别名,对引用的操作与对其所绑定的变量或对象的操作完全等价,这篇文章主要给大家总结介绍...

    幻荼4462023-02-24
  • C/C++VC++中内存对齐实例教程

    VC++中内存对齐实例教程

    这篇文章主要介绍了VC++中内存对齐的实现方法,具有很高的实用价值,需要的朋友可以参考下...

    C++教程网11342021-01-29
  • C/C++C/C++实现线性单链表的示例代码

    C/C++实现线性单链表的示例代码

    使用链存储结构的线性存储结构为线性单链表,本文将分别利用C语言和C++实现线性单链表,感兴趣的小伙伴可以跟随小编一起学习一下...

    学编程的闹钟3532022-12-09
  • C/C++C++ STL priority_queue自定义排序实现方法详解

    C++ STL priority_queue自定义排序实现方法详解

    这篇文章主要介绍了C++ STL priority_queue自定义排序实现方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    C语言中文网7212021-10-26
  • C/C++C++实现红黑树应用实例代码

    C++实现红黑树应用实例代码

    红黑树它一种特殊的二叉查找树,这意味着它满足二叉查找树的特征,但是也有许多自己的特性,这篇文章主要给大家介绍了关于C++实现红黑树的相关资料,需要...

    去伪存真11982022-02-17
  • C/C++C++ 虚函数表图文解析

    C++ 虚函数表图文解析

    最近学了设计模式中的简单工厂模式,对多态有了具体的认识。于是补了补多态、虚函数、虚函数表相关的知识,本文介绍了C++ 虚函数表,感兴趣的了解一...

    flight111111082021-11-05
  • C/C++详解C++中单继承与多继承的使用

    详解C++中单继承与多继承的使用

    C++的继承机制相对其他语言是比较复杂的一种,不同于java只支持单继承,C++不仅支持单继承,也支持多继承。本文将详细讲解C++中单继承与多继承的使用,...

    卖寂寞的小男孩4462022-11-15