繁体   English   中英

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

[英]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 次调用。 有没有任何惯用和简洁的方法来做到这一点?

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

  • Tfunc的返回值打包在一个结构中并对其进行排序。 这在计算上是最佳的,但它也会在排序之前完成初始数组的一个完整副本,然后再执行另一个完整副本以将值放回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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM