【问题标题】:how to sort elements by one measure如何按一种度量对元素进行排序
【发布时间】:2011-07-22 17:36:07
【问题描述】:

在 C++ 中,我不太了解如何通过定义自定义函数对元素进行排序。

Cppreference.com 说对于比较功能:

comp - 比较函数,如果第一个参数返回真​​​ 小于秒。

​bool cmp(const Type1 &a, const Type2 &b);​

我自然会认为,对于排序元素,我需要定义一个度量,排序函数会根据度量对它们进行排序。

在我的实际示例中,我想根据图像文件与相机的距离对图像文件进行排序。我有一个 boost::filesystem::path 向量链接到图像序列的目录

vector<boost::filesystem::path> path_vec

我自然会认为我需要写一个类似的函数

double z_distance( boost::filesystem::path filename, integer time )

什么会为所有元素返回一个双精度,并为每一帧按升序或降序对它们进行排序(因此参数中的变化时间)。

你能告诉我如何将这个返回单个值的函数转换为排序函数所需的布尔函数吗?

如果我只能传递函数名而不是函数的完整调用,我该如何传递参数?

【问题讨论】:

    标签: c++ visual-studio-2010 function sorting iterator


    【解决方案1】:

    当你定义时

     bool nearer(const boost::filesystem::path& a, const boost::filesystem::path& b)
     {
       int somevalue = 0;
       return z_distance(a, somevalue) < z_distance(b, somevalue);
     }
    

    你可以的

     std::sort(path_vec.begin(), path_vec.end(), nearer);
    

    但是,我不知道如何处理函数z_distance() 的第二个参数。也许您可以从文件中获取它,或者您必须使用仿函数而不是函数进行比较。对于函子,请参阅@templatetypedef 给出的答案。

    由于您标记了 VC++10,您还可以使用 C++0x 功能:编写 lambda 表达式(即席函数)来传递参数:

     int somevalue = 0;
     std::sort(path_vec.begin(), path_vec.end(), 
       [=](const boost::filesystem::path& a, const boost::filesystem::path& b) -> bool
       {
         return z_distance(a, somevalue) < z_distance(b, somevalue);
       }
     );
    

    【讨论】:

    • 我建议最好使用 const TYPE&amp; 而不是 TYPE 作为复制运算符,否则会被大量调用。所以bool nearer(const boost::filesystem::path &amp;a, const booost::filesystem::path &amp;b)... 或者在 lambda 的情况下,[=](const boost::filesystem::path &amp;a, const booost::filesystem::path &amp;b)...
    • @Soren:我同意,更改了代码。写的时候有点懒,不想在展示概念的时候写太多东西。
    【解决方案2】:

    有很多方法可以做到这一点。

    如果您碰巧知道z_distance 的第二个参数始终是某个固定值,那么您可以通过编写一个实际进行比较的辅助函数来将该函数转换为比较器。例如:

    bool CompareByDistance(const boost::filesystem::path& lhs,
                           const boost::filesystem::path& rhs) {
        return z_distance(lhs, kSecondArg) < z_distance(rhs, kSecondArg);
    }
    

    如果你不知道z_distance函数的第二个参数应该是什么,或者只能在运行时确定,那么你可能需要使用一个函数对象。函数对象(有时称为 functor)是模仿常规函数的对象。您可以通过传入一些参数来调用它,但由于它是一个对象,因此最终被调用的函数除了参数之外还可以访问本地状态。您可以构建的一个这样的函数对象可能如下所示:

    class CompareByDistance {
    public:
        /* Constructor takes in the time that you want to sort at,
         * then stores it for later.
         */
        CompareByDistance(int time) : mTime(time) {
    
        }
    
        /* This is the function call operator that is called when you try
         * treating a CompareByDistance object as a function.  Note how it
         * uses the mTime field as a parameter to `z_distance`.
         */
        bool operator()(const boost::filesystem::path& lhs,
                        const boost::filesystem::path& rhs) const {
            return z_distance(lhs, mTime) < z_distance(rhs, mTime);
        }
    private:
        const int mTime; // Store mTime for later
    };
    

    现在,如果你想在某个时间 t 对所有内容进行排序,你可以这样写

    sort(elems.begin(), elems.end(), CompareByDistance(t));
    

    有关函子的更多信息,作为一个无耻的插件,这里是我为一年前教授的 C++ 课程写的 a chapter on functors。

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      重载operator&lt; 以返回 &A

      所以

       bool operator<(const SomeType& a, const SomeType& b)
       {
         return z_distance(a, 0) < z_distance(b, 0);
       }
      

      而且你应该可以这样称呼它。

       std::vector<SomeType> vec;
       std::sort(vec.begin(), vec.end());
      

      【讨论】:

        【解决方案4】:

        好吧,这就是你困惑的地方......

        该函数一次比较两个元素,根据结果重新调整内部容器(树或其他)。因此,在 STL 函数中,所有 C++ 需要知道的是,根据您的函数,元素 A 小于元素 B。

        所以,不管你在乎的是,你的比较功能可以比较他们的距离、人名或任何你想要的东西。如果一个元素小于另一个元素,该函数只需返回 true,C++ 将处理如何使用它进行排序。

        【讨论】:

        • PS:该函数将在您的 STL 容器的全部内容上运行很多次,一次两个元素 - 抱歉,我应该在帖子中这么说。这就是为什么它不需要返回一个双精度,一个布尔就足够了。
        猜你喜欢
        • 2017-01-26
        • 2019-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-02-12
        • 1970-01-01
        • 1970-01-01
        • 2012-01-27
        相关资源
        最近更新 更多