【问题标题】:How do I (C++ STL) binary_search for Abstract classes?我如何(C++ STL)二进制搜索抽象类?
【发布时间】:2011-08-15 20:21:12
【问题描述】:

可以使用 STL 二进制搜索算法(binary_search、upper_bound、lower_bound)在基指针向量中搜索派生对象,如下所示。由于 Base 是抽象的(受保护的构造函数),因此必须为搜索函数实例化一个 Derived 对象,这有点难看。

我想在给定时间以上的第一个 Derived 向量中搜索。我可以在不随意选择和实例化我的许多继承类之一的情况下做到这一点吗?

#include <algorithm>
#include <vector>
#include <stdio.h>
using namespace std;

class Base {
protected:
  Base(double t, int d) : data(d), time(t) {}
public:
  double time;
  int data;
  virtual void print() { 
    printf("Base: data = %d, time = %.1f\n",data,time); 
  }
};

class Derived : public Base {
public:
  Derived(double t, int d) : Base(t,d) {}
  virtual void print() { 
    printf("Derived: data=%d, time=%.1f\n",data,time);
  }
};

struct BaseTimeComp {
  bool operator()(Base* a, Base* b) { return a->time < b->time; }
};

int main()
{
  vector<Base*> v;
  for(int i=0; i<5; i++) { v.push_back(new Derived(i+0.4,i)); }

  Base* pLow = *(lower_bound(v.begin(),v.end(),
                             new Derived(3.5,0), //NOT "new Base(3.5,0)"
                             BaseTimeComp()));
  printf("lower bound for time=3.5:\n");
  pLow->print();
}

程序打印: 时间=3.5 的下限: 推导:数据=4,时间=4.4

【问题讨论】:

    标签: c++ stl abstract binary-search


    【解决方案1】:

    比较的目标不必与容器内容的类型相同,只要是你可以比较容器的东西:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        vector<int> v;
    
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
    
        int i = *(lower_bound(v.begin(), v.end(), 1.5));  // <<< NOTE: floating point "value"
    
        cout << i << endl;
    }
    

    你认为你必须做出某种Base 的假设是错误的。您可以定义一个适合您的比较的BaseKey,只要您的显式(或隐式)比较运算符知道该做什么。

    下面的评论也是错误的,正如这个更复杂的例子所示:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    struct A {
        int x;
        A(int _x) :x(_x) { }
    
        bool operator < (double d) { return x < d; }
    };
    
    int main()
    {
        vector<A> v;
    
        v.push_back(A(1));
        v.push_back(A(2));
        v.push_back(A(3));
    
        int i = (lower_bound(v.begin(), v.end(), 1.5))->x;
    
        cout << i << endl;
    }
    

    您还可以显式使用比较类型(这有助于解决操作顺序问题,例如您可能在 upper_bound 中发现的问题):

    class CompareADouble {
    public:
        bool operator () (const double d, A& a) { return d < a.x; }
    };
    
    int main()
    {
        vector<A> v;
    
        v.push_back(A(1));
        v.push_back(A(2));
        v.push_back(A(3));
    
        int i = (upper_bound(v.begin(), v.end(), 1.5, CompareADouble()))->x;
    
        cout << i << endl;
    }
    

    一个binary_search 示例提供了与多态性的比较:

    class CompareADouble {
    public:
        bool operator () (const double d, A& a) { return d < a.x; }
        bool operator () (A& a, const double d) { return a.x < d; }
    };
    
    ...
    
        bool exists = binary_search(v.begin(), v.end(), 1.5, CompareADouble());
        cout << exists << endl; // false
    
        exists = binary_search(v.begin(), v.end(), 1.0, CompareADouble());
        cout << exists << endl; // true because 1.0 < 1 == false && 1 < 1.0 == false
    

    【讨论】:

    • -1:这不起作用。在此特定示例中,1.5 将简单地转换为int 作为lower_bound 的参数。在更复杂的示例中,它根本无法编译。
    • 我邀请您编译更复杂的示例或解释它必须有多复杂......
    • @Ben:现在尝试使用upper_boundbinary_search,或者使用自定义比较器函数/函子...
    • @Ben:很有趣。我不认为它会编译(尽管我相信它只能通过利用lower_bound 等的特定实现来编译)。好的,那么在我取消投票之前的最后一个问题:binary_search 使用自定义比较器?
    • @Ben:即使在lower_bound 的情况下,我认为定义比较器的两个排列也是最安全的。从技术上讲,STL 实现可以选择在任一方向进行比较。
    【解决方案2】:

    你可以传递一个空指针,并设计你的比较函数忽略它,只测试另一个对象的特定属性。

    【讨论】:

    • +1:冷酷!但我想它会起作用的。仿函数每次都必须检查它的哪个参数是NULL,并相应地翻转逻辑。
    【解决方案3】:

    在某种程度上,您可以使用静态方法:

    class Base {
    ...
    public:
      static Base *newSearchInstance(double t, int d) {return new Base(t,d);};
    ...
    };
    

    在对 LowerBound 的调用中:

    Base* pLow = *(lower_bound(v.begin(),v.end(),
                             Base::newSearchInstance(3.5,0), //<------
                             BaseTimeComp()));
    

    这意味着您不必了解任何派生类,但是获取 Base 类型的实例首先违背了 Base 是抽象的目的。您也可以将构造函数公开。

    【讨论】:

    • 是的,这确实违背了目的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-24
    • 1970-01-01
    相关资源
    最近更新 更多