如何按照值对STL map进行排序?
例如,我有一个map m
:
map<int, int> m;
m[1] = 10;
m[2] = 5;
m[4] = 6;
m[6] = 1;
我想按照 m
的值对该映射表进行排序。因此,如果我打印映射表,我希望得到以下结果:
m[6] = 1
m[2] = 5
m[4] = 6
m[1] = 10
我该如何以这种方式对地图进行排序?有没有办法在处理值排序的同时处理键和值?
如何按照值对STL map进行排序?
例如,我有一个map m
:
map<int, int> m;
m[1] = 10;
m[2] = 5;
m[4] = 6;
m[6] = 1;
我想按照 m
的值对该映射表进行排序。因此,如果我打印映射表,我希望得到以下结果:
m[6] = 1
m[2] = 5
m[4] = 6
m[1] = 10
我该如何以这种方式对地图进行排序?有没有办法在处理值排序的同时处理键和值?
set<pair<K, V>>
中,其中 set
是使用仅比较键值对第二个值的小于函数构建的。这样即使您的值不都是不同的,您的代码仍然可以正常工作。vector<pair<K, V>>
中,然后使用相同的小于函数对该向量进行排序。vector<pair<K,V>> v(m.begin(), m.end());
。 - juanmirocksmyset.insert(make_pair(1, 1));
和myset.insert(make_pair(2, 1))
,那么第二个pair将不会被插入,因为对于该集合,如果函数对象只比较pair的第二个值,那么这两个项是相同的。 - honk你可以构建第二个映射表,将第一个映射表的值作为键,第一个映射表的键作为值。
只有在所有值都不相同时才能使用此方法。如果无法假定这一点,则需要构建 multimap 而不是 map。
我想知道如何按值对STL map进行排序。
你不能,根据定义。map是一种按键排序其元素的数据结构。
在这种情况下,您应该使用 Boost.Bimap。
bimap<multiset_of<int>, set_of<double>>
。 - rlbond根据 @swegi 的想法,我使用 C++11 中的 multimap
实现了一个解决方案:
map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}};
multimap<int, int> mm;
for(auto const &kv : m)
mm.insert(make_pair(kv.second, kv.first)); // Flip the pairs.
for(auto const &kv : mm)
cout << "m[" << kv.second << "] = " << kv.first << endl; // Flip the pairs again.
我还根据@Chris的想法使用了一个pair向量来实现基于C++11的解决方案。为了正确排序,我提供了一个lambda表达式作为比较函数:
map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}};
using mypair = pair<int, int>;
vector<mypair> v(begin(m), end(m));
sort(begin(v), end(v), [](const mypair& a, const mypair& b) { return a.second < b.second; });
for(auto const &p : v)
cout << "m[" << p.first << "] = " << p.second << endl;
第一种解决方案更加紧凑,但两种解决方案的性能应该差不多。将元素插入到 multimap
中的时间复杂度为 O(log n),但是需要对 n 个元素进行操作,因此总时间复杂度为 O(n log n)。而对于第二种解决方案,对向量进行排序也会产生 O(n log n) 的时间复杂度。
我还尝试过 @Chris 的想法,即使用一组成对的集合。然而,如果值不都是不同的,则无法使用。使用一个只比较成对元素的第二个元素的函数对象是没有帮助的。如果你先将 make_pair(1, 1)
插入到集合中,然后再尝试插入 make_pair(2, 1)
,那么第二个成对元素就不会被插入,因为该集合认为这两个成对元素是相同的。你可以在 Ideone 上看到这种效果。
我刚在我的C++书中做了一个类似的问题。虽然我想出的答案可能不是很有效率:
int main()
{
string s;
map<string, int> counters;
while(cin >> s)
++counters[s];
//Get the largest and smallest values from map
int beginPos = smallest_map_value(counters);
int endPos = largest_map_value(counters);
//Increment through smallest value to largest values found
for(int i = beginPos; i <= endPos; ++i)
{
//For each increment, go through the map...
for(map<string, int>::const_iterator it = counters.begin(); it != counters.end(); ++it)
{
//...and print out any pairs with matching values
if(it->second == i)
{
cout << it->first << "\t" << it->second << endl;
}
}
}
return 0;
}
//Find the smallest value for a map<string, int>
int smallest_map_value(const map<string, int>& m)
{
map<string, int>::const_iterator it = m.begin();
int lowest = it->second;
for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it)
{
if(it->second < lowest)
lowest = it->second;
}
return lowest;
}
//Find the largest value for a map<string, int>
int largest_map_value(const map<string, int>& m)
{
map<string, int>::const_iterator it = m.begin();
int highest = it->second;
for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it)
{
if(it->second > highest)
highest = it->second;
}
return highest;
}
vector<pair<int, int>>
而不是使用 maps<int, int>
。这样做的好处是你可以直接使用带有比较器函数的 vector<pair<int, int>>,虽然你会失去使用 map 的一些优点,例如更少的查找时间。bool compare(pair<int, int> a, pair<int, int> b)
{
return (a.second < b.second);
}
#include <map>
#include <set>
#include <algorithm>
#include <functional>
int main() {
// Creating & Initializing a map of String & Ints
std::map<std::string, int> mapOfWordCount = { { "aaa", 10 }, { "ddd", 41 },
{ "bbb", 62 }, { "ccc", 13 } };
// Declaring the type of Predicate that accepts 2 pairs and return a bool
typedef std::function<bool(std::pair<std::string, int>, std::pair<std::string, int>)> Comparator;
// Defining a lambda function to compare two pairs. It will compare two pairs using second field
Comparator compFunctor =
[](std::pair<std::string, int> elem1 ,std::pair<std::string, int> elem2)
{
return elem1.second < elem2.second;
};
// Declaring a set that will store the pairs using above comparision logic
std::set<std::pair<std::string, int>, Comparator> setOfWords(
mapOfWordCount.begin(), mapOfWordCount.end(), compFunctor);
// Iterate over a set using range base for loop
// It will display the items in sorted order of values
for (std::pair<std::string, int> element : setOfWords)
std::cout << element.first << " :: " << element.second << std::endl;
return 0;
}
地图已根据第一个键排序,如果你想根据第二个值进行排序,请将第二个值作为键。否则使用另一个容器,例如vector>。
boost::bimap
。 - Alexandre C.