【问题标题】:Sorting multimap with both keys and values使用键和值对多图进行排序
【发布时间】:2015-12-24 01:48:12
【问题描述】:

我正在尝试通过为它编写一个比较函数来使用标准排序函数对其中包含一组对的多图进行排序,但我遇到了一些错误。我正在尝试使用值对地图进行排序,然后再次使用键对其进行排序。比较功能导致一些错误。你能指出我哪里出了问题。

#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

bool cmp(const pair<int,int>& a, const pair<int,int>& b)
{
    return a.second < b.second;
}

int main() {
    // multimap of int ssId, int phone numbers
    multimap <int, int> m;
    m.insert(make_pair(1, 8));
    m.insert(make_pair(1, 5));
    m.insert(make_pair(2, 4));
    m.insert(make_pair(2, 3));
    m.insert(make_pair(3, 1));

    sort(m.begin(), m.end(), cmp);
    return 0;
}

输出应该是这样的:

1 5
1 8
2 3 
2 4
3 1

【问题讨论】:

  • 1) std::multimap 仅按其键排序,构建后无法重新排序。 2) 无论如何你都不能使用std::sort,因为它需要随机访问迭代器,而std::multimap 只提供双向迭代器。

标签: c++ algorithm sorting dictionary multimap


【解决方案1】:

这是一个老问题,但如果他们正在寻找,可能对其他人有用。

对于这种我们希望对相同键的值进行排序的场景, 而不是使用

multimap <int, int> m;

使用

map<int,vector<int>> and then sort the individual vector.
or even better, just:
vector<pair<int,int>> and then sort the vector

vector<pair<int, int>> vec{{1,8}, {1,5},{2,4} ,{2,3}, {3,1}};
sort(begin(vec), end(vec));

pair 的内部排序会按第一个元素进行排序,当第一个元素相同时,它会按第二个元素对这些对进行排序。

【讨论】:

    【解决方案2】:

    在 C++ 中没有直接的方法可以做到这一点,因为 multimap 是有序的,其顺序不能更改,但是有一个使用额外的 multimap 的解决方法。它将完全输出您喜欢的内容。类似的方法适用于字符串到整数,反之亦然多图。

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        multimap <int, int> m;
        m.insert(make_pair(1, 8));
        m.insert(make_pair(1, 5));
        m.insert(make_pair(2, 4));
        m.insert(make_pair(2, 3));
        m.insert(make_pair(3, 1));
        multimap<int, int> R;
        for (auto i=m.begin(); i!=m.end(); i++)
            R.insert({i->second,i->first});
        m.clear();
        for (auto i=R.begin(); i!=R.end(); i++)
            m.insert({i->second,i->first});
        R.clear();
        for (auto i=m.begin(); i!=m.end(); i++)
            cout<<i->first<<"\t"<<i->second<<endl;
        return 0;
    }
    

    【讨论】:

    • 记住在 multimap m 和 multimap R 的声明中切换键值数据类型。
    【解决方案3】:

    你不能那样做。 C++ STL 中的 Multimap 是有序的,并且不能/不得更改顺序(我认为最重要的是它使用 平衡二叉树 作为我认为的键,但不确定)。

    您可以做的是实例化一个新的multimap 对象,传递一个适合您需要的比较器(研究严格的弱顺序)。

    默认情况下,使用less,与升序比较。在下面的示例中,您可以看到 greater 比较器对象传递给比较器的模板参数,它按降序进行比较。 比较器只比较键,不比较值。

    如果需要,您可以传递自己的比较器,也可以为要存储在地图中的类型(键)定义自己的 &lt; 运算符。

    请参阅下面的示例了解用法。

    // multimap
    #include <map>
    #include <iostream>
    #include <functional>
    #include <iomanip>
    
    using namespace std;
    
    template<class T> void print(T start, T end) {
        while (start != end) {
            std::cout << start->first << ":" << start->second << " ";
            start++;
        }
    }
    
    template<class T, class U> void fillMap(multimap<T, T> & m, U start, U end) {
        for (; start != end; ++start) {
            m.insert(pair<T, T>(*start, *start));
        }
    }
    
    int main() {
        int t[] = {2, 10, 8, 4, 5, 5, 3, 10, 7, 2};
        //1. standard initialization - default constructor
        multimap<int, int > m1;
        fillMap(m1, t, t + 10);
        //2. iterator constructor
        multimap<int, int> m2(m1.begin(), m1.end());
        //2b. iterator constructor - wrong
        //multimap<int, int> m2(t, t+10);
        print(m2.begin(), m2.end());
        cout << endl;
        //3. copy constructor
        multimap<int, int> m3(m2);
        print(m3.begin(), m3.end());
        cout << endl;
    
        //4. providing different comparator
        multimap<int, int, greater<int> > m4(m1.begin(), m1.end());
        print(m4.begin(), m4.end());
        cout << endl;
        //5. Not allowed - source and target object are not of the same type 
        //multimap<int, greater<int> > s5 (s3);
    
        //6. assignment
        multimap<int, int> m6;
        m6 = m3;
        print(m6.begin(), m6.end());
        cout << endl;
        //7. Not allowed - assignment of incompatible multimap objects
        //m6 = m4;
        return 0;
    }
    

    【讨论】:

    • C++ 标准库映射和集合通常实现为自平衡二叉树(红黑树)。
    • @user2407394 你会这么友善和详细吗?我不确定是什么意思。
    • 当然,虽然 OP 对他的问题的解释不是很清楚。他的问题是让条目按相同键的值排序。例如 (1,5) 和 (1,3) 应该排序为 (1,3) 和 (1,5).. 您的回答只是提到按不同顺序对键进行排序..
    • 我明白了。我的回答从“你不能那样做”开始,然后解释了如何在 STL 中使用 multimap。我相信这是一个有用的答案。您说得对,我没有为 OP 提供解决方案;这不会使答案变得不那么有用IMO。至少我试图给出一个提示......
    【解决方案4】:

    您正在尝试对 严格排序 容器进行排序。这是不可能的,因为整个multimap 中的两个元素的swap 通常会违反其弱排序。例如,对于 cmp,您提供(想象一下)“排序”m 将是:

    3 1
    2 3
    2 4
    1 5
    1 8

    如您所见,违反了m 的顺序。

    关联容器不关心值的顺序。如果您需要订购它们,那么

    • 使用另一个有序容器作为值(例如std::map&lt;int, std::set&lt;int&gt;&gt;
    • std::set&lt;std::pair&lt;int, int&gt;, cmp&gt; 与自定义cmp 排序一起使用。但请注意它不是地图:

      1. 您将无法仅通过ssId 访问元素,但您可以通过lower_bound()upper_bound() 访问范围
      2. std::set 的元素是不可变的。这意味着要更改 std::set 的元素,您必须将它们从集合中删除,然后插入更新的值。

    std::set< std::pair<int, int> > m;
    
    m.insert(make_pair(1, 8));
    m.insert(make_pair(1, 5));
    m.insert(make_pair(2, 4));
    m.insert(make_pair(2, 3));
    m.insert(make_pair(2, 1));
    m.insert(make_pair(2, 5));
    m.insert(make_pair(2, 2));
    m.insert(make_pair(2, 0));
    m.insert(make_pair(3, 1));
    
    for(auto&& x : m) {
        std::cout << x.first << ' ' << x.second << std::endl;
    }
    
    auto b = m.lower_bound(std::make_pair(2, 2));
    auto e = m.lower_bound(std::make_pair(2, 4));
    
    std::cout << std::endl;
    
    for(auto i = b; i != e; ++i) {
        std::cout << i->first << ' ' << i->second << std::endl;
    }
    

    会产生

    1 5
    1 8
    2 0
    2 1
    2 2
    2 3
    2 4
    2 5
    3 1

    2 2
    2 3

    注意,std::pairstd::tuple 已经有字典比较运算符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-02
      • 2011-09-26
      • 2010-09-26
      • 2015-10-01
      • 1970-01-01
      • 2020-10-02
      • 2019-07-07
      • 1970-01-01
      相关资源
      最近更新 更多