【问题标题】:C++ How to Sort Vector making use of TemplateC++如何利用模板对向量进行排序
【发布时间】:2012-11-16 08:34:39
【问题描述】:

C++如何利用模板对向量进行排序

大家好,感谢您查看我的问题。

我有一个这样的 Templates.h 文件..

/* Template Less Than */

template<typename T>
bool lessThan(T a,T b)
{
return a<b;
}

/* Template greater Than */

template<typename T>
bool greaterThan(T a,T b)
{
return a>b;
}

/* Template Equals */

template<typename T>
bool equals(T a,T b)
{
return a==b;
}

然后我就上了这门课

Map2D

关于 Map2D..

class Map2D
{
protected:
int x;
int y;

public:
Map2D();
Map2D(int,int);
int getX();
int getY();
};

在我的 main.cpp 中,我得到了 Map2D 的矢量类

vector<Map2D> map2d;

所以现在我需要按 X Ascending 对其进行排序.. 我如何利用模板文件对其 X Ascending 的向量进行排序.. 考虑我稍后需要重载​​另一个 DESCENDING..

通常我会使用

sort(map2d.begin(),map2d.end(),sortByX);

并且 sortByX 将是一个由 it () 运算符重载的结构。

但是现在的问题是,因为我得到了一个小于和大于的模板。我如何利用它通过 Templates.H 的模板通用函数通过升序对 X 进行排序,然后通过降序对另一个 X 进行排序。

更新:

我想我需要重载类 Map2D 运算符 > 、

但我的问题是如何借助 MyTemplates.h 函数(例如 lesserThan、greaterThan、equals)重载它

谢谢。

【问题讨论】:

  • 对不起,您是否暗示您想在编译时执行此操作?或者您只是想在运行时使用您的模板化函数?
  • @SingerOfTheFall 想创建一个函数,可以利用greaterThan lesserThan对int x进行升序和降序排序
  • 你的课最后少了一个分号
  • 您可能希望知道您的lessThan 模板在所有意图和目的上都与std::less相同。你重新发明轮子是为了什么? (你仍然需要一个 operator&lt;() 来为你的 Map2D 类做这个工作。
  • 与显然广泛的意见相反,如果您的模板编码正确并且operator &lt;() 遵循严格的顺序,则不需要重载operator &gt;() 和operator ==() 来执行greaterThan&lt;T&gt; and equals它应该。

标签: c++ templates sorting vector


【解决方案1】:

为您的类定义一个比较器或更简单的 operator&lt;() 重载(无论如何您都需要这样做才能使您的模板正常工作)。

首先,修复你的模板:

template<typename T>
bool lessThan(const T& a, const T& b)
{
    return a<b;
}

template<typename T>
bool greaterThan(const T& a, const T& b)
{
    return b<a;
}

template<typename T>
bool equals(const T& a, const T& b)
{
    return !(a<b || b<a);
}

接下来,在你的类上定义一个运算符

class Map2D
{
protected:
    int x;
    int y;

public:
    Map2D();
    Map2D(int,int);
    int getX();
    int getY();

    // this sample sorts on X dominantly, and Y if X is the same
    bool operator <(const Map2D& obj) const
    {
        return (x < obj.x || (x == obj.x && y < obj.y));
    };
}

现在只需调用排序:

std::sort(map2d.begin(), map2d.end());

使用您的 lessThan 模板调用:

std::sort(map2d.begin(), map2d.end(), lessThan<Map2D>);

或您的大于模板:

std::sort(map2d.begin(), map2d.end(), greaterThan<Map2D>);

【讨论】:

  • 我可以使用我拥有的 templates.h 函数而不是使用我自己的算法吗,与重载运算符 和 == 的目的相同
  • @user1578897 是的,你可以。使用 lessThan 见上文
  • 如果我想比较 y。我应该如何改变。因为在这种情况下它只适用于 X
  • @user1578897 你的意思是比较 Y 而不是先比较 X,然后比较 Y,就像上面的编码一样?
【解决方案2】:

在 C++11 中,您可以编写一个 lambda 函数来执行此操作。

使用 boost,如果你想要一个“on-step on the fly”函子,它必须是这样的:

bind( less<int>, bind(&Map2D::getX(),_1), bind(&Map2D::getX(),_2) )
// or your lessThan<int> which already exists in C++ as less<int>

不确定这是否会完全有效。 (第 2 和第 3 绑定会正确转换为占位符吗?)更容易编写一个非常通用的仿函数来组合您正在尝试做的事情,即从您的类中提取某些内容(转换)然后将其传递给谓词。

template< typename Trans, typename Pred >
struct Comparator
{
    Comparator( Trans t , Pred p ) : trans( t ), pred ( p )
    {
    }

    template< typename T >
    bool operator()( T const& t1, T const& t2 ) const
    {
         return pred( trans(t1), trans(t2) );
    }
private:
    Trans trans;
    Pred pred;
};


template< typename Trans, typename Pred >
Comparator< Trans, Pred > makeComparator( Trans t, Pred p )
{
     return Comparator( t, p );
}

// then in your code

std::sort( map2d.begin(), map2d.end(), 
    makeComparator( boost::bind( &Map2D::getX(), _1 ), lessThan<int> ) );

应该可以工作,并且您保持 Comparator 通用。

(不确定 boost 是否已经提供类似的功能)。

【讨论】:

    【解决方案3】:

    您的代码存在一些问题:

    1. 类末尾缺少分号。
    2. 您的比较模板应返回 bool 而不是 T。
    3. 你错过了类中的比较运算符:

      bool operator<(const Map2D &m) const {return /* some code here */ }
      bool operator>(const Map2D &m) const {return /* some code here */ }
      bool operator==(const Map2D &m) const {return /* some code here */ }
      

      或修复您的模板以仅使用 operator&lt;() 进行所有比较(顺便说一句,这是一种常见做法)。

    当您修复上述问题时,您只需像这样使用您的模板:

    sort(map2d.begin(),map2d.end(), lessThan<Map2D>);
    sort(map2d.begin(),map2d.end(), greaterThan<Map2D>);
    

    顺便说一句,您不需要自定义模板来以如此简单的方式对您的课程进行排序。重用 STL 中已有的内容:

    sort(map2d.begin(),map2d.end()); // less
    sort(map2d.begin(),map2d.end(), std::greater<Map2D>());
    

    您可以在 functional 标头中找到它们。您也不能使用 operator==() 进行排序,但它可能对 C++11 中引入的 unordered containers 有用。

    编辑:如果您对 Map2D 类的排序算法是固定的(lessThan 不会随时间变化),那么我建议您遵循我的回答。否则,如果现在您想按 X 排序,几行后按 Y 排序,@MikeSeymour 的答案可能更适合您的需求。

    【讨论】:

      【解决方案4】:

      如果你在 C++11 中,你可以这样写:

      std::sort(map2d.begin(), map2d.end(), [](const Map2D& a, const Map2D& b) {
          return lessThan(a.getX(), b.getX()); } ); // accending
      std::sort(map2d.begin(), map2d.end(), [](const Map2D& a, const Map2D& b) {
          return greaterThan(a.getX(), b.getX()); }); // decending
      

      否则你必须实现比较函子,即

      struct compare
      {
          bool operator () (const Map2D& a, const Map2D& b)
          {
              return lessThan(a.getX(), b.getX());
          }
      };
      

      然后

      std::sort(map2d.begin(), map2d.end(), compare());
      

      但实际上,使用 lessThan、greaterThan 并不是一个好的样式,因为您可以直接比较 x。如果你想对 Map2D 进行一些特殊的比较,最好只为 Map2D 对象使用这些比较函数。

      更新:您也可以只使用函数指针作为比较器,即:

      bool compare(const Map2D& a, const Map2D& b)
      {
          return lessThan(a.getX(), b.getX());
      }
      

      然后

      std::sort(m.begin(), m.end(), compare);
      

      但您可能会损失一些性能(请参阅下面的 cmets)。

      【讨论】:

      • 对于这么简单的任务来说,这看起来有点过头了。
      • @MateuszPusz:你什么意思?这正是为std::sort 提供自定义比较器的方法。
      • @MikeSeymour 实际上,这样的比较器将与提供的实现一起使用。但是,在我看来,通过 getter 取消隐藏所有类实现以便将所有数据提供给某些外部函数进行比较并不是一个好习惯。我认为在所有情况下都应该首选 operator
      • @MateuszPusz:有很多方法可以定义二维点的排序;如果您确实(任意)选择重载operator&lt; 以按x 排序,那么您仍然需要像这样的自定义比较器按y 排序。
      • @MikeSeymour 好的,我不能不同意 :-)
      【解决方案5】:

      您首先需要重载运算符 &lt;、&gt; 和 == 以在模板中使用 Map2D:

      class Map2D
      {
      protected:
         int x;
         int y;
      public:
         Map2D();
         Map2D(int,int);
         int getX();
         int getY();
         bool operator<(const Map2D& other)const //less then
         {
            return x < other.x;
         }
         //other operators is same manner
      }
      

      完成后,您只需使用它:

      sort(map2d.begin(),map2d.end(),lessThan<Map2D>);
      

      【讨论】:

      • 嗨,丹尼斯,感谢您的回答,它与我想要实现的目标非常接近。但是我如何拉入 MyTemplates.h 以在 Map2D 运算符中重载,可以说比重载运算符
      • 没听懂你的意思,抱歉。你想如何重载
      • operator
      • 确实
      【解决方案6】:

      你真的不能。您需要定义仿函数(函数或适当重载operator() 的类)来进行您需要的特定对象成员比较,而您的函数模板不会这样做。你需要这样的东西:

      struct compare_x_less {
          // NOTE: you'll need to declare `get_X() const` for this to work.
          // You should do that anyway.
          bool operator()(Map2D const & a, Map2D const & b) {
              return a.get_X() < b.get_X();
          }
      };
      
      // and similarly for `compare_x_greater` and any other comparisons you need
      
      std::sort(map2d.begin(),map2d.end(),compare_x_less());
      

      在 C++11 中,lambda 可以为您节省一些打字时间:

      std::sort(map2d.begin(),map2d.end(),[](Map2D const & a, Map2D const & b) {
              return a.get_X() < b.get_X();
          });
      

      【讨论】:

      • 如果我用函数重载类 Map2D,我能用那些通用函数排序吗?
      • @user1578897:你的意思是如果你超载operator&lt;和operator&gt;为Map2D?是的;但是您必须选择一种任意顺序(例如,通过x 或y)。这可能有意义,也可能没有意义,具体取决于您打算如何使用这些 2D 点。
      • 你不仅可以在这里使用仿函数和 lambda,还可以使用普通的比较函数,只要内部状态不需要进行操作。
      • @MateuszPusz:确实,任何函子都可以。我举了一个使用函数类的例子,因为那是我一直使用的;它比函数指针更容易内联,因为函数本身可以从模板参数中推导出来。
      • @Mike Seymour 我也认为函子更容易使用,但这并不意味着你不能使用你在答案中的第一句话可能意味着的普通函数。
      【解决方案7】:
      sort(map2d.begin(),map2d.end(),lessThan<map2d>);
      

      请注意,lessThan 是一个谓词函数,它应该返回而不是 bool 类型的 T 值

      一些补充说明:

      // usage
          /* Some moments to mention: if you omit third argument, default argument less<T> will be used,
          which is enough for built-in types, also you can use predicates already defined in STL:
          greater<T>, less<T> or you can provide your own predicate */
          sort(map2d.begin(),map2d.end(),lessThan<map2d>);
      
      // header file, where we define predicats which we shall provide as argument to algorithm sort
      
      // predicate expected by function sort has to obey the following rules:
      // 1. return bool 2. accept 2 parameters
      
      /*2 variants of predicat*/
      
      // 1) operator< is overloaded for class T, so we can use it to compare instances of that class
      template<typename T>
      bool lessThan(T a,T b)
      {
      return a < b;
      }
      
      /* 2) operator< not overloaded, when we have to get values of class members by which we are going to compare them
      this could be done in various ways, for ex. by means of getters();*/
      
      template<typename T>
      bool lessThan(T a,T b)
      {
      return a.getValueOfMember() < b.getValueOfMember();
      }
      

      【讨论】:

      • 我如何调整它以便 lessThan 可以通过 X 或 Y 比较它
      • 只有在operator&lt; 为Map2D 过载时才有效;在这种情况下,根本不需要提供比较器。
      • @MikeSeymour,这可能是最好的方法。
      • @spin_eight 如果我想通过 int y 或 int x 进行比较,我该如何将其推入。所以它可以按 x 或 y 以升序/降序排序
      【解决方案8】:

      一个好方法,我不认为它是最好的。 您可以在类中重载运算符 (sort(map2d.begin(), map2d.end()) 进行升序。和sort(map2d.rbegin(), map2d.rend()) 用于下降.. 这解决了你的问题。

      或者: 您可以创建 2 个函数来比较 1 个与 x 相关和另一个与 Y 相关。 如:

      int cmpx(const void* A, const void *B){
          Map2D a = *(Map2D *)A;
          Map2D b = *(Map2D *)B;
          if(a.x < b.x) return -1;
          if(a.x == b.x) return 0;
          return 1;
      }
      // And use
      qsort(map2d.begin(), (int)map2d.size(), sizeof(Map2D), cmpx);
      

      Y 也是如此。 不确定map2d.rbegin() 是否会按顺序排序,或者你也必须自己做。

      【讨论】:

      • 我认为你的答案是关于我在寻找什么。重载类本身。但是我如何重载,以便我可以发送 X 或 Y 以在类本身中与模板函数进行比较。
      • 提供相同数据但顺序不同的反向迭代器如何按降序对容器进行排序?为什么需要 operator!=()?
      猜你喜欢
      • 1970-01-01
      • 2013-10-10
      • 1970-01-01
      • 2016-01-22
      • 2013-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-09
      相关资源
      最近更新 更多