【问题标题】:Searching a C++ Vector<custom_class> for the first/last occurence of a value在 C++ Vector<custom_class> 中搜索第一次/最后一次出现的值
【发布时间】:2010-12-11 13:43:37
【问题描述】:

我正在尝试找出最佳方法来搜索“Tracklet”类型的向量(我自己构建的一个类),以查找其中一个变量的给定值的第一次和最后一次出现。例如,我有以下类(本例已简化):

class Tracklet {
    TimePoint *start;
    TimePoint *end;
    int angle;

    public:
        Tracklet(CvPoint*, CvPoint*, int, int);
}

class TimePoint {
    int x, y, t;

    public:
        TimePoint(int, int, int);
        TimePoint(CvPoint*, int);
        // Relevant getters and setters exist here   
};

我有一个向量“vector&lt;Tracklet&gt; tracklets”,我需要在结束时间点搜索具有给定值“t”的任何轨迹。该向量按结束时间排序(即tracklet.end-&gt;t)。

我很乐意编写一个搜索算法,但不确定该采用哪条路径。我不确定二进制搜索是否合适,因为我似乎记得它不一定会找到第一个。我正在考虑一种方法,我使用二进制搜索来查找具有正确时间的元素的索引,然后迭代返回以找到第一个并转发以找到最后一个。我确信有比这更好的方法,因为它通过迭代浪费了二进制搜索 O(log n)。

希望这是有道理的:我很难解释一下! 干杯!

【问题讨论】:

    标签: c++ search class vector opencv


    【解决方案1】:

    只要您的向量保持排序状态,二分查找似乎是您最好的选择。在性能方面,这与在二叉树结构中执行查找基本相同。

    【讨论】:

      【解决方案2】:

      向量按时间排序

      开始时间还是结束时间?

      天真的 O(n) 搜索有什么问题?请记住,您只是在搜索而不是排序。您也可以使用排序容器(如果这不违反基本设计)。

      【讨论】:

      • 结束时间,抱歉,将编辑问题。该列表将非常大(超过 2000 个元素)并且效率非常重要(我需要大约每秒处理一次,程序等待尽可能少),所以我试图最小化搜索时间尽可能的。
      • 什么样的效率:插入/删除/查找?如果是这意味着如果您想快速查找,则 std::set 更适合此目的(甚至是 hash_map)。从 vector 移动到 set(其中数据集的大小约为 10K)时,我获得了显着的性能提升。另请参阅bigzaphod.org/set.vs.vector
      【解决方案3】:

      我只会使用findfind_end,然后只有在测试显示太慢时才做一些更复杂的事情。

      如果您真的很关心查找性能,您可以考虑使用不同的数据结构,例如以时间戳为键的map,以元素的vectorlist 为值。

      【讨论】:

      • 我担心 find 和 find_end 的时间复杂度很高。向量会很大,我真的需要尽量减少延迟。
      【解决方案4】:

      如果向量已排序并包含该值,std::lower_bound 将为您提供一个迭代器,指向具有给定值的第一个元素,std::upper_bound 将为您提供一个迭代器,指向包含该值的最后一个元素之后的一个元素。将该值与返回的元素进行比较,以查看它是否存在于向量中。这两个函数都使用二分查找,所以时间是 O(logN)。

      要比较tracklet.end-&gt;t,请使用:

      bool compareTracklets(const Tracklet &tr1, const Tracklet &tr2) {
          return (tr1.end->t < tr2.end->t);
      }
      

      并将 compareTracklets 作为第四个参数传递给 lower_boundupper_bound

      【讨论】:

      • 这可能是可能的,但我如何让它检查tracklet.end-&gt;t?我对 C++ 比较陌生 :)
      • 您使用了比较函数或对象。我已经用一个例子编辑了我的答案。
      【解决方案5】:

      dirkgently referred 到一个甜蜜的优化比较。但实际上我不会为此使用std::vector

      通常,在决定使用 STL 容器时,我不会真正考虑性能方面,但我会考虑它的接口以及我希望使用的操作类型。

      std::set<T>::find
      std::set<T>::lower_bound
      std::set<T>::upper_bound
      std::set<T>::equal_range
      

      真的,如果您想要一个有序的序列,在键/值设置之外,std::set 比其他任何方法都更容易使用。

      • 您不必担心在“坏”位置插入
      • 添加/删除元素时不会出现迭代器失效的问题
      • 您有内置的搜索方法

      当然,您还希望您的比较谓词在任何情况下都能真正发挥作用(希望编译器内联 operator() 实现)。

      但实际上,如果您不相信,请尝试使用std::vector 和手动插入/搜索(使用&lt;algorithm&gt; 标头)的构建,然后尝试使用std::set 的另一个构建。

      比较实现的大小(代码行数),比较bug的数量,比较速度,然后再决定。

      大多数情况下,您所追求的“优化”实际上是 pessimization,而在极少数情况下并非如此,它太复杂以至于不值得。

      优化

      • 不要
      • 仅限专家:不要,我们是认真的

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-10
        • 1970-01-01
        • 2017-03-06
        • 2023-03-09
        • 2015-06-06
        • 1970-01-01
        • 2021-05-28
        相关资源
        最近更新 更多