在C ++中反转集合的内容

时间:2011-11-03 10:24:55

标签: c++ stl

我想要反转std::set的内容(不仅仅是反向迭代它,而是反转它的内容)。我发现std::set将比较作为其构造函数的函数对象。因此,我想出了以下代码来做同样的事情:

#include <set>
using namespace std;
struct Comparator
{
    Comparator(bool g) : m_g(g){}
     bool operator()(int i1, int i2) const
    {
        if(m_g)
        {
            return i1>i2;
        }
        return i1<i2;
    }
        bool m_g;
};

int main(int argc, char** argv)
{
    Comparator l(false);
    set<int,Comparator> a(l);
    a.insert(1);
    a.insert(2);
    a.insert(3);
    Comparator g(true);
    set<int,Comparator> b(g);
    copy(a.begin(), a.end(), inserter(b, b.begin()));
    a = b;
    return 0;
}

这似乎适用于VC9。但这段代码是否正确?我怀疑是因为Comparator有与之相关的状态。比较器是否允许有状态?

7 个答案:

答案 0 :(得分:6)

是的,这是合法的。考虑如果不允许比较器具有状态,则允许您将比较器作为构造函数参数传递是没有意义的。 :)

只要比较器提供严格的弱排序,它就没问题了(除其他外,这意味着它必须是一致的。你不能在中途改变它的状态,所以它以不同的方式命令元素)

答案 1 :(得分:4)

没关系,但它不必要复杂。

您可以使用标准库中的std::less(该模板参数的默认值!)或std::greater。它们由<functional>提供。

答案 2 :(得分:2)

更通用的解决方案。 boost :: assign和c ++ 11只是为了方便(以及有趣的自动反转

    # include <iostream>
# include <set>
# include <boost/assign.hpp>


using namespace boost::assign;

template <typename CL , typename Pred>
struct revPred {
    revPred (Pred pred) : pred_(pred) {}
bool operator()(const CL & a, const CL& b)
{
 return pred_(b,a);
 }
Pred pred_;
};

template <typename CL , typename Pred, typename alloc>
inline
std::set<CL,revPred<CL,Pred>,alloc> reverseSet(const std::set<CL,Pred,alloc> & set) {
    std::set<CL,revPred<CL,Pred>,alloc> res(revPred<CL,Pred>(set.key_comp()));
    std::copy(set.begin(), set.end(), std::inserter(res, res.begin())); 
    return res;
    }

int main()
{
 std::set<int> s; s += 0 , 1 , 2 , 3;
 std::for_each(s.begin(), s.end(), [](int x) { std::cout << x << " "; }); 
 std::cout << std::endl;
 auto reverse = reverseSet(s);
 std::for_each(reverse.begin(), reverse.end(), [](int x) { std::cout << x << " "; }); 
 std::cout << std::endl;
 return 0; 
}

答案 3 :(得分:1)

您的代码没有任何问题。

具有状态的比较器没有任何问题。

答案 4 :(得分:1)

这没关系,因为你的比较没有动态变化,而且确实提供了严格的弱排序。

但是,如果您这样做,即使订单类型发生变化,集合的类型也是相同的,我可能会建议另一个想法。而不是这种比较,您使用两个不同的集合类型std::lessstd::greater并使用像标准库那样的迭代器接口,而不是依赖于所有模板参数的容器接口。

最后,如@parapura rajkumar的回答所述,你应该使用迭代器对构造函数而不是std::copy

// Assuming my other comments don't apply, modify as needed if they do:
Comparator g(true);
set<int, Comparator> b(a.rbegin(), a.rend(), g);

答案 5 :(得分:0)

您不需要提供维护状态的函数对象。只需使用正常功能就可以完成这项工作。 PLS。不介意使用lambda。用作快捷方式进行打印。

typedef bool (*Cmp)(int x, int y);

bool Compare(int x, int y)
{
    return x < y;
}


bool CompareR(int x , int y)
{
    return !Compare(x, y);
}

 void SetReverse()
{

    std::set<int, Cmp> s1(Compare);

    s1.insert(1);
    s1.insert(3);
    s1.insert(2);
    s1.insert(4);

    std::for_each(s1.begin(), s1.end(), [](int x) { std::cout << x << "\n"; });

    std::set<int, Cmp> s2(CompareR);

    s2.insert(s1.begin(), s1.end());
    std::for_each(s2.begin(), s2.end(), [](int x) { std::cout << x << "\n"; });

          s1 = s2;

}

答案 6 :(得分:0)

如果你有足够大的集合,你已经支付了O(NlogN)惩罚来制作一个平衡的二叉树。盲目插入目的地集合,您将不得不再次支付罚金。

考虑使用其中一个插入重载。

 void insert ( InputIterator first, InputIterator last );
 iterator insert ( iterator position, const value_type& x );

如果[first,last]已经排序,则范围插入具有线性复杂度。