我想要反转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
有与之相关的状态。比较器是否允许有状态?
答案 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::less
和std::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]已经排序,则范围插入具有线性复杂度。