【问题标题】:Binary search in a sorted list with all nodes as struct C++在所有节点为 struct C++ 的排序列表中进行二进制搜索
【发布时间】:2013-01-14 23:23:13
【问题描述】:

我有一个包含所有元素的列表作为表单结构

typedef struct person_node{
    string name;
    string country;
}person;

std::list<person> list;

列表已经按人名排序

如何使用内置的 binary_search() 函数?

我已经知道如何在只有数字作为数据的列表上使用这个 binary_search(),但我想知道如何将它用于这样的列表。

我将这个二进制函数用作:

binary_search (list.begin(), list.end(), value, compare_function);

唯一我不知道的是,“如果我需要在列表中查找特定名称,我应该输入什么来代替 value?”

我还希望 一个迭代器 指向该节点(如果找到)。

【问题讨论】:

  • 您正在搜索的值。由于您没有解释您要搜索的内容,我不确定我们还能告诉您什么。
  • 你应该输入正确初始化的person_node; person_node Temp; Temp.name = "r20rock"; binary_search(l.begin(), l.end(), Temp, comp);
  • list 的二分搜索没有什么意义(只有与遍历成本相比,键的比较非常昂贵时才有意义清单,我怀疑是这种情况)。找到分裂点的成本与列表的大小成线性关系,并且需要访问所有先前的节点。
  • @DavidRodríguez-dribeas 好的,如果我同意为此使用 vector,我将如何获得我正在寻找的节点的位置?
  • @r20rock:如果你使用vector,那么这个问题更有意义,你可以使用 Jerry Coffin 在他的回答中提到的方法(std::lower_boundstd::upper_bound

标签: c++ list stl binary-search


【解决方案1】:

您输入一个person,其中包含您要查找的name

还要注意binary_search 很少有用(它只告诉您该项目是否存在,而不是它在集合中的位置。它在std::list 上是双重无用的,因为它需要随机访问迭代器来工作得很好(std::list 没有提供)。

因此,您可能想要的是std::vector&lt;person&gt;std::deque&lt;person&gt;,您可能希望使用std::lower_boundstd::upper_bound 进行搜索。 std::lower_boundstd::upper_bound 将各自返回一个指向他们找到的项目的迭代器,让您可以访问该对象。

【讨论】:

  • @Jerryy Coffin 好的,如果我同意为此使用向量,我将如何获得我正在寻找的节点的位置?
  • @r20rock:如果你使用带有 lower_bound 或 upper_bound 的 std::vector,那将返回一个迭代器到它找到的项目。
  • ,还有一个疑问,当节点为struct时如何使用lower_bound?我的第三个论点应该是什么?
  • @r20rock:您的第三个参数是person,其name 设置为您要搜索的值。您可能还需要传递第四个参数,它将是一个函数(或仿函数),例如 bool cmp(person const &amp;a, person const &amp;b) { return a.name &lt; b.name; } 如果您使用的是足够新的编译器,您可能希望将其编写为 lambda。
【解决方案2】:

第三项以您可以调用的方式描述您正在搜索的内容

compare_function(*iter, value )

compare_function( value, *iter )

其中iter 是您集合中的有效迭代器。如果*iter 必须出现在列表中的value 之前,这应该在第一种情况下返回true 以保持排序,在第二种情况下反之亦然。

因此,请注意,如果您的 compare_function 支持这两个重载,您实际上可以传入 string 作为第三个参数。原型是:

template <class ForwardIterator, class T, class Compare>
   bool binary_search ( ForwardIterator first, ForwardIterator last,
                   const T& value, Compare comp );

而且T不一定是迭代器的值类型。

顺便说一句,虽然您可以将它用于std::list,但对于非随机访问的迭代器来说效率极低,因为每个std::advance 语句都是O(N),因此整个操作是O(N log N)。即使是普通的std::find 也会更快。

如果您可以有重复项,请使用vectormultiset,如果您不允许重复项,请使用set

此外,binary_search 本身也会返回 true/false 来判断该项目是否存在并且没有为您找到该项目(因此您不会知道他们的国家/地区)。如果您有重复项,您可以使用std::equal_range 获取所有此类值的列表。如果你不这样做,你可以使用std::lower_bound,它将为你提供一个迭代器,指向名称等于或大于你的名称的第一个项目,然后检查它是否相等,而不是更大。

【讨论】:

  • 实际上,它支持双向迭代器。并不是说这是个好主意。
  • 它支持双向,这意味着您可以前进或后退,但不能像使用 binary_search 那样“跳跃”。如果它使用std::advance 跳转,那么对于列表来说这是一个 O(N) 操作。就我个人而言,我宁愿它编译失败来标记用户对 STL 的不良使用。
  • @CashCow 好的,如果我同意为此使用向量,我将如何获得我正在寻找的节点的位置?
  • 您使用 std::lower_bound 并返回一个迭代器。您可以先检查这是否是“结束”迭代器,在这种情况下找不到您的项目。然后检查该值是否与您要查找的值匹配。然后你知道该项目存在。要找出它在集合中的位置,请减去 begin() (或使用 std::distance)
猜你喜欢
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 2015-05-16
  • 1970-01-01
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
  • 2013-10-29
相关资源
最近更新 更多