在已排序的向量中查找最近的索引
Find index of nearest in sorted vector
我编写了一个 C++ 例程来查找排序数组中最近的双精度元素。有没有办法加快?
根据boolean的值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 <= x[i] && value > 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;
您可以使用 std::lower_bound 找到等于或大于请求的元素,然后向后移动迭代器并检查前面的值。这将使用二进制搜索并且将花费 O(log n),这也启用标准的 STL 比较器等等。
实现了这个辅助例程
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;
}
}
如果您实际上没有可与 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).
方法是将大小减 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;
}
我编写了一个 C++ 例程来查找排序数组中最近的双精度元素。有没有办法加快?
根据boolean的值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 <= x[i] && value > 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;
您可以使用 std::lower_bound 找到等于或大于请求的元素,然后向后移动迭代器并检查前面的值。这将使用二进制搜索并且将花费 O(log n),这也启用标准的 STL 比较器等等。
实现了这个辅助例程
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;
}
}
如果您实际上没有可与 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).
方法是将大小减 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;
}