[英]How to sort a range based on the value of some transformation of its values?
令arr
是某种类型T
的数组,而func(const &T)
某个计算量大的函数。 要按func(T)
的值对arr
进行排序,我们可以天真地写。
std::sort(arr.begin(), arr.end(), [](const T& a, const T&b) {
return func(a) < func(b);
}
然而,这将平均调用func
O(nlogn) 次。 显然,我们只需要 n 次调用。 有没有任何惯用和简洁的方法来做到这一点?
我知道以下两种解决方案,但我想找到一种更好的解决方案。
将T
和func
的返回值打包在一个结构中并对其进行排序。 这在计算上是最佳的,但它也会在排序之前完成初始数组的一个完整副本,然后再执行另一个完整副本以将值放回arr
创建第二个数组并并行排序数组。 据我所知,没有惯用的方式来对两个数组进行排序。 可以通过编写自定义迭代器和交换函数来完成。 这已经足够了,但它也需要比理想情况更多的样板代码。
理想的解决方案是基于 STL 的,尽可能少的样板代码,但欢迎所有贡献。
您需要的是对函数结果的一种记忆。 如果您的函数fun
没有副作用并且在std::sort
使用它,我推断它不会,我会想到这样的事情:
#include <unordered_map>
template<class T, class U>
class caller{
public:
const U &call(const T& t) const{
auto found = memoized.find(t);
if (found != memoized.end())
return found->second;
return memoized.insert(std::make_pair(t, fun(t))).first->second;
}
private:
mutable std::unordered_map<T, U> memoized;
};
它的用法如下所示:
caller<T, decltype(func(std::declval<T>()))> c;
std::sort(arr.begin(), arr.end(), [](const T& a, const T&b) {
return c.call(a) < c.call(b);
}
在制作第一个解决方案后,我玩了一些,并制作了一个更通用的、符合 C++17 的解决方案。 它应该适用于每个带有一个可复制和可散列参数的函数。 看一看:
#include <unordered_map>
int fii(int){
return 0;
}
template<class T, auto fun>
class memoizer{
public:
const auto &call(const T& t) const{
auto found = memoized.find(t);
if (found != memoized.end())
return found->second;
return memoized.insert(std::make_pair(t, fun(t)))
.first->second;
}
private:
mutable std::unordered_map<T, decltype(fun(T()))> memoized;
};
auto memoized_fii = memoizer<int, fii>{};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.