【问题标题】:STL "closest" method?STL“最接近”的方法?
【发布时间】:2011-04-07 09:10:37
【问题描述】:

如果容器中不存在确切的值,我正在寻找一种 STL 排序,该排序将元素“最接近”返回到目标值。它需要很快,所以基本上我正在寻找一个稍微修改的二进制搜索......我可以写它,但它似乎应该已经存在......

【问题讨论】:

    标签: c++ search binary


    【解决方案1】:

    您是指lower_bound/upper_bound 函数吗?这些执行二进制搜索并返回您正在查找的值上方最接近的元素。

    澄清:lower/upper_bound 的全局版本仅在范围已排序时才有效,因为它们在内部使用某种二进制搜索。 (显然,std::map 中的 lower/upper_bound 方法总是有效的)。你在你的问题中说你正在寻找某种二进制搜索,所以我假设范围是排序的。

    另外,lower_boundupper_bound 都不会返回最近的成员。如果您要查找的值X 不是该范围的成员,则它们都将返回大于X 的第一个元素。否则,lower_bound 将返回等于X 的第一个值,upper_bound 将返回等于X 的最后一个值。

    所以要找到最接近的值,你必须

    • 致电lower_bound
    • 如果返回范围的末尾,所有值都小于X。最后一个(即最高的)元素是最近的一个
    • 如果返回范围的开头,则所有值都大于X。第一个(即最低的)元素是最接近的元素
    • 如果它返回范围中间的元素,请检查该元素和之前的元素 - 更接近 X 的元素就是您要查找的元素

    【讨论】:

    • 这两种方法的方向是正确的,但它们并不是完全他所要求的。 lower_bound 将返回大于或等于给定值的第一个元素,upper_bound 返回小于或等于给定值的最后一个值。这些方法不关心下一个值是否更接近。
    • @Philip: dicroce 写道他正在寻找“稍微修改过的二进制搜索”,所以我假设他的容器已排序。不过,提及它可能是件好事。
    • @Space_Cowboy:如果列表已排序,最接近的值应该是最后一个小于或大于他正在寻找的值的第一个。还是我错过了什么?你能举一个不起作用的例子吗?
    • @nikie:这意味着您必须调用这两个函数并查看两个结果中哪个更接近。然后它工作。或者,您可以使用@Philip Potter 在他的回答中建议的自定义谓词。
    • @Space_Cowboy:我还是不明白。如果我的最后一个元素低于我正在寻找的值,那么之后的下一个元素应该是第一个更大的元素。比较距离并使用更近的距离。无需调用这两个函数。
    【解决方案2】:

    所以您正在寻找与某个值 k 的距离最小的元素?

    使用std::transform 将每个x 转换为x-k。将std::min_element 与返回abs(l) < abs(r) 的比较函数一起使用。然后将k 添加回结果中。

    编辑:或者,您可以将std::min_element 与比较函数abs(l-k) < abs(r-k) 一起使用,并消除std::transform

    EDIT2:这适用于未排序的容器。对于已排序的容器,您可能需要 nikie 的答案。

    【讨论】:

      【解决方案3】:

      如果容器已经排序(如暗示的那样),您应该能够使用std::upper_bound 和之前的项目来确定哪个最接近:

      // Untested.
      template <class Iter, class T>
      Iter closest_value(Iter begin, Iter end, T value)
      {
          Iter result = std::upper_bound(begin, end, value);
          if(result != begin)
          {
              Iter lower_result = result;
              --lower_result;
              if(result == end || ((value - *lower_result) < (*result - value)))
              {
                  result = lower_result;
              }
          }
      
          return result;
      }
      

      如果容器未排序,请使用min_element 和已建议的谓词。

      【讨论】:

      • 错字,应该是upper_bound(begin,end,value);
      • 如果upper_bound 返回end 怎么办?那么该函数是否应该返回end 之前的最后一个元素?
      【解决方案4】:

      如果您的数据未排序,请使用 std::min_element 和计算距离的比较函子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多