【问题标题】:Find index of nearest in sorted vector在已排序的向量中查找最近的索引
【发布时间】:2021-05-20 17:01:14
【问题描述】:

我编写了一个 C++ 例程来查找排序数组中最近的双精度元素。有没有加快速度的方法?

根据布尔值reversed的值有两个分支,如果reversed按降序排序。

 void findNearestNeighbourIndex_new(real_T value, real_T* x, int_T x_size, int_T& l_idx)
{
    l_idx = -1;

    bool reversed= (x[1] - x[0] < 0);

    if ((!reversed&& value <= x[0]) 
                  || (reversed&& value >= x[0])){ 
        // Value is before first position in x
        l_idx = 0;
    }
    else if ((!reversed&& value >= x[x_size - 1]) 
                    || (reversed&& value <= x[x_size - 1])){ 
        // Value is after last position in x
        l_idx = x_size - 2;
    }
    else // All other cases
    {
        if (reversed)
        {
            for (int i = 0; i < x_size - 1; ++i)
            {
                if (value <= x[i] && value > x[i + 1])
                {
                    l_idx = i;
                    break;
                }
            }
        }
        else{
            for (int i = 0; i < x_size - 1; ++i)  
            {
                if (value >= x[i] && value < x[i + 1])
                {
                    l_idx = i;
                    break;
                }
            }
        }   
    }
}

在这种对数组进行排序的情况下,我看不出有更好的方法。因此,通过分析,我发现if (value &lt;= x[i] &amp;&amp; value &gt; x[i + 1]) 中的比较很昂贵。

编辑

尝试使用 lower_bound()

std::vector<real_T> x_vec(x, x + x_size);

l_idx = std::upper_bound(x_vec.begin(), x_vec.end(), value) - x_vec.begin() - 1;

【问题讨论】:

标签: c++ algorithm performance optimization intel-vtune


【解决方案1】:

您可以使用std::lower_bound 查找等于或大于请求的元素,然后将迭代器向后移动并检查前面的值。这将使用二分查找,成本为 O(log n),这也启用了标准 STL 比较器等。

【讨论】:

  • 我实际上需要最近邻居的索引,而不是值
  • @octoback 你在哪里说的。当你真正想要 Y 时,却要求 X 是不礼貌的。
  • @octoback 因为您正在使用迭代器及其 std::vector - 您可以轻松地进行迭代器数学(减去向量开始迭代器以获取索引)。
  • 我正在将数组转换为向量,然后使用 lower_bound,这大大降低了性能
  • @octoback 再次,您的问题标题为“在排序向量中”。无论如何,您也可以在原始排序数组上使用 lower_bound。
【解决方案2】:

如果您实际上没有与upper_bound() 一起使用的向量,则不需要构造一个向量,因为这将是一个 O(n) 操作。 upper_bound() 将与您拥有的数组一起使用。您可以使用:

l_idx = std::upper_bound(x, x + size, value) - x - 1;

测试用例:

#include <iostream>
#include <functional>
#include <algorithm>

int main()
{
    const int size = 9;
    int x[9] = {1,2,3,4,5,6,7,8,9};

    auto pos = std::upper_bound(x, x + size, 5) - x;

    std::cout << "position: " << pos;

    return 0;
}

输出:

5

upper_bound() 的结果将我们指向 6(live example)。

【讨论】:

  • 这里的-x 正确吗?使用这个表达式,我的测试被破坏了,因此它们不能替代我编写的循环。我宁愿看到这种味道l_idx = std::upper_bound(x_vec.begin(), x_vec.end(), value) - x_vec.begin() - 1; 但这不是编译
  • @octoback 我编辑了我的答案,向您展示了一个带有数组的工作示例。为了以您想要的方式拥有它,您需要将数组转换为向量,这将花费您。
  • 如果目标值超过最高向量值,则该代码不起作用。我在回答中写的代码解决了这个问题
【解决方案3】:

方法是对大小减去 1(使工作超过最大值)和目标值减去 0.5 以使其准确:

#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;

int main()
{
    float x[10] = { 2,3,4,5,6,7,8,9,10,11 },y;
    int size = sizeof(x) / sizeof(x[0]),pos;


    y = 4.1; pos = std::upper_bound(x, x + size - 1, y - 0.5) - x;
    std::cout << "position: " << pos << " target value=" << y << " upper_bound=" << x[pos] << endl;
    y = 4.9; pos = std::upper_bound(x, x + size - 1, y - 0.5) - x;
    std::cout << "position: " << pos << " target value=" << y << " upper_bound=" << x[pos] << endl;
    y = -0.5; pos = std::upper_bound(x, x + size - 1, y - 0.5) - x;
    std::cout << "position: " << pos << " target value=" << y << " upper_bound=" << x[pos] << endl;
    y = 100; pos = std::upper_bound(x, x + size - 1, y - 0.5) - x;
    std::cout << "position: " << pos << " target value=" << y << " upper_bound=" << x[pos] << endl;
    getchar();
    return 0;
}

【讨论】:

    【解决方案4】:

    实现了这个辅助例程

    void findNearestNeighbourIndex_bin_search_new(real_T value, real_T* x,  
                  int_T start, int_T stop, int_T& l_idx)
    {
        int_T mid = ( stop - start ) / 2;
    
        if (value >= x[mid+1])
        {
            findNearestNeighbourIndex_bin_search_new(value, x, mid + 1, stop, l_idx);
        }
        else if (value < x[mid])
        {
            findNearestNeighbourIndex_bin_search_new(value, x, start, mid, l_idx);
        }
        else
        {
            l_idx = mid;
            return;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-01
      • 2018-06-05
      • 2016-07-19
      相关资源
      最近更新 更多