如何根据某个值的值转换对其范围进行排序?

时间:2019-04-13 17:54:56

标签: c++ performance sorting boost transform

arr是某种类型的数组Tfunc(const &T)是一些计算量大的函数。要按arr的值对func(T)进行排序,我们可以天真地写。

std::sort(arr.begin(), arr.end(), [](const T& a, const T&b) {
    return func(a) < func(b);
}

但是,这平均会调用func O(nlogn)次。显然,我们只需要n个调用即可。有没有惯用而简洁的方法来做到这一点?

我知道以下两种解决方案,但我想找到一个更好的解决方案。

  • Tfunc的返回值打包到一个结构中并对其进行排序。这在计算上是最佳的,但它也可以在排序之前对初始数组进行一个完整复制,然后对它进行另一个完整复制以将值放回arr

  • 创建第二个数组并对其进行并行排序。据我所知,还没有惯用的方式对两个数组进行排序。可以通过编写自定义迭代器和交换函数来完成。足够好了,但它还需要比理想代码还要多的样板代码。

理想的解决方案是基于STL并尽可能减少样板代码,但欢迎所有贡献。

1 个答案:

答案 0 :(得分:2)

第一个非一般性解决方案

您需要的是一种功能结果的记忆。如果您的函数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>{};