【C++】-- STL之map和set详解(三)

简介: 【C++】-- STL之map和set详解

第三种方式:借助计数排序思想,使用operator[ ]运算符重载获取value

mapped_type& operator[] (const key_type& k);//返回k对应的value的引用

返回:

(*((this->insert(make_pair(k,mapped_type()))).first)).second

即:

1. mapped_type& operator[](const key_type& k)
2. {
3.  pair<iteerator, bool> ret = insert(make_pair(k, mapped_type()));
4.  return ret.first->second;
5. }

operator[ ]的本质就是插入:

①如果k不在map中,先插入<k,V( )>,返回节点中V对象的引用

②如果k已经在map中,返回k所在节点中对应V对象的引用

1.  //第三种统计方法-计数排序
2.  string arr[] = { "篮球","足球","排球","羽毛球","足球","乒乓球","足球","排球","羽毛球","篮球","足球" };
3.  map<string, int> countMap;
4. 
5.  for (const auto& str : arr)
6.  {
7.    countMap[str]++;//等价于countMap.operator[](str),会调用mapped type()的默认构造函数构造一个匿名对象。其中str是key,++的是key对应的value,即返回值
8.  }
9. 
10.   for (const auto& e : countMap)
11.   {
12.     cout << e.first << ":" << e.second << endl;
13.   }

这三种方式中,operator[ ]最简洁,更好使用。

计数结束后,排序有2种方式:

第一种排序:用sort排序

可以使用sort进行排序,先包含sort的头文件:

#include<algorithm>

vector里面如果要存pair,得把每个pair拿出来拷贝,再插入到vector中,而且string是深拷贝,代价大。

sort要排序,必须支持整数比较大小,传的是迭代器,迭代器指向的数据必须要能比较大小,v里面存的是pair,需要重载pair的比较大小。  sort的第3个参数是compare,要传对象,用实际对象推compare的类型,可以用仿函数比较,给sort的第3个参数传个匿名对象

sort的第3个参数是Compare比较方式,默认是按小于比较的,要找排名前面的球类,必须要传入大于的比较方式,就需要重新写仿函数:

1. template <class RandomAccessIterator, class Compare>
2.  void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

大于的比较方式的仿函数:

1. struct MapItCompare
2. {
3.  bool operator()(map<string, int>::iterator x, map<string, int>::iterator y)
4.  {
5.    return x->second > y->second;
6.  }
7. };
1. void Map_test2()
2. {
3.  string arr[] = { "篮球", "足球", "排球", "羽毛球", "足球", "乒乓球", "足球", "排球", "羽毛球", "篮球", "足球" };
4.  1.统计计数
5.  map<string, int> countMap;
6.  for (const auto& str : arr)
7.  {
8.    countMap[str]++;
9.  }
10. 
11. 2.排序(第一种用sort排序)
12.   vector<map<string, int>::iterator> v;
13.   map<string, int>::iterator countMapIt = countMap.begin();
14. 
15.   while (countMapIt != countMap.end())
16.   {
17.     v.push_back(countMapIt);//把迭代器放进vector中,不创建节点,不拷贝新数组
18.     countMapIt++;
19.   }
20.   sort(v.begin(), v.end(), MapItCompare());
21. }

统计计数完毕后:

排序完毕后:

这就找出了排名前3的球类。

第二种排序:用map排序:map这个结构是天生的可以用来排序的结构,不过map的比较方式默认是less,也就是按照升序排的:

1. template < class Key,                                     // map::key_type
2. class T,                                       // map::mapped_type
3. class Compare = less<Key>,                     // map::key_compare
4. class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
5.            > class map;

但是现在需要按照降序排,就要传比较方式:

1.  //第二种排序,借助map排序
2.     map<int, string,greater<int>> sortMap;//将次数作为first,将字符串作为second,比较方式为大于greater
3.  for (auto e : countMap)
4.  {
5.    sortMap.insert(make_pair(e.second, e.first));
6.  }

由于int作为key,所以有相同key的球类只存第一种,篮球、排球和羽毛球的个数都是2(举的例子有点不恰当,应该往所有球类的个数都不相同),只会出现篮球,不会出现排球和羽毛球:

这种方式用了拷贝,如果不想拷贝的话,可以存到set中。

第三种排序方式:

给set的迭代器传个仿函数:

1. // 利用set排序  --不拷贝pair数据
2.  set<map<string, int>::iterator, MapItCompare> sortSet;//set传模板参数,传MapItCompare类型
3.  countMapIt = countMap.begin();
4.  while (countMapIt != countMap.end())
5.  {
6.    sortSet.insert(countMapIt);
7.    ++countMapIt;
8.  }

第四种比较方式: 用优先级队列,向优先级队列中存放迭代器,减少拷贝,要找个数最大的,要建小堆

1. struct MapItCompare
2. {
3.  bool operator()(map<string, int>::iterator x, map<string, int>::iterator y)
4.  {
5.    return x->second < y->second;
6.  }
7. };
1.  typedef map<string, int>::iterator MapIt;
2.  priority_queue<MapIt, vector<MapIt>, MapItCompare> pq;
3. 
4.  map<string, int>::iterator countMapIt = countMap.begin();
5.  while (countMapIt != countMap.end())
6.  {
7.    pq.push(countMapIt);
8.    countMapIt++;
9.  }

堆顶元素就是找到的个数最多的球类,足球:

(4)删除erase( )

size_type erase (const key_type& k);//通过k删除
1.  map<string, string> dict;
2.  dict.insert(make_pair("spring", "春天"));
3.  dict["spring"] += "、温泉";
4.  dict["summer"] = "夏天";
5.  dict["autumn"] = "秋天";
6.  dict["winter"] = "冬天";
7. 
8.  auto mit = dict.begin();//同map<string, int>::iterator mit = m.begin();
9.  while (mit != dict.end())
10.   {
11.     cout << mit->first << ":" << mit->second << endl;
12.     mit++;
13.   }
14.   cout << endl;

dict.erase("spring");

再遍历打印:

四、multiset 和 multimap

set中和map中存储的元素不可以重复,但是multiset和multimap中的元素是可以重复的,它们中的元素不可以修改,但是可以插入和删除:

multiset:头文件为#include<set>

1. template < class T,                        // multiset::key_type/value_type
2. class Compare = less<T>,        // multiset::key_compare/value_compare
3. class Alloc = allocator<T> >    // multiset::allocator_type
4.            > class multiset;
1.     multiset<int> mls1;
2.  int arr[] = { 2,3,2,5,3,3};
3. 
4.  mls1.insert(arr, arr + 6);
5.  for (auto e : mls1)
6.  {
7.    cout << e << endl;
8.  }

允许存在key相同的元素:

 

multimap:头文件为#include<map>

1. template < class Key,                                     // multimap::key_type
2. class T,                                       // multimap::mapped_type
3. class Compare = less<Key>,                     // multimap::key_compare
4. class Alloc = allocator<pair<const Key,T> >    // multimap::allocator_type
5.            > class multimap;
1.  multimap<string,string> mlp1;
2.  mlp1.insert(make_pair("spring", "春天"));
3.  mlp1.insert(make_pair("summer", "夏天"));
4.  mlp1.insert(make_pair("autumn", "秋天"));
5.  mlp1.insert(make_pair("winter", "冬天"));
6. 
7.  mlp1.insert(make_pair("spring", "温泉"));
8. 
9.  for (auto e : mlp1)
10.   {
11.     cout << e.first << ":" << e.second << endl;
12.   }

允许存在key相同的pair:

相关文章
|
4天前
|
安全 编译器 容器
C++STL容器和智能指针
C++STL容器和智能指针
|
6天前
|
算法 安全 Linux
|
1月前
|
C++ 容器
【C++】map和set封装
【C++】map和set封装
23 2
|
1月前
|
存储 C++ 容器
【C++】map和set深度讲解(下)
【C++】map和set深度讲解(下)
41 2
|
1月前
|
存储 自然语言处理 Java
【C++】map和set深度讲解(上)
【C++】map和set深度讲解(上)
28 2
|
1月前
|
存储 C++ 容器
【C++】开散列实现unordered_map与unordered_set的封装
【C++】开散列实现unordered_map与unordered_set的封装
28 0
|
6天前
|
C++ 容器
C++中自定义结构体或类作为关联容器的键
C++中自定义结构体或类作为关联容器的键
13 0
|
6天前
|
存储 算法 搜索推荐
【C++】类的默认成员函数
【C++】类的默认成员函数
|
6天前
|
存储 安全 编译器
【C++】类和对象(下)
【C++】类和对象(下)
【C++】类和对象(下)
|
4天前
|
编译器 C++
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决