【问题标题】:matlab: efficient search a value within the arraymatlab:高效搜索数组中的值
【发布时间】:2014-06-10 01:30:33
【问题描述】:

我有一组已排序的值(例如 vec=[20, 54, 87, 233])。数组包含约 300 个元素。我有一个值,我需要在这个数组中搜索。搜索成功不仅是准确的值,而且是范围内的+/- 5位数字。例如,在这种情况下,像 17 或 55 这样的值也应该被视为已找到。最有效的方法是什么?我使用了像下面这样的循环,但我想它没有考虑到我的数组已经被订购。此外,在非空的情况下,我可以手动检查值的距离,因为 find 不返回位置。这不是什么大问题,因为我的“发现”只有 15%。

bRes  = find(vec >= Value-5 & vec <= Value+5);
if ~isempty(bRes)
    distGap = GetGapDetails(Value, vec);
    return;
end

谢谢! 瓦迪姆

【问题讨论】:

  • 只需使用histhistc
  • 但是它对我有什么帮助呢?固定范围(1-10,11-20 等)的 hist bin 值。我的查询值可能属于不同的 bin。
  • @user1597969 您可以使用 hist 定义自定义 bin 边缘。不均匀也没关系。

标签: arrays performance matlab search find


【解决方案1】:

这样会更有效率:

bRes  = vec >= Value-5 & vec <= Value+5;
if any(bRes) ...

您是对的,MATLAB 可能不会利用“vec”已经排序的事实。您可以在感兴趣的范围内将二进制搜索写入零(即,在 O(log(N)) 时间而不是 O(N) 时间内工作),但数组中只有 300 个元素,我怀疑您当前实施将保持良好。

【讨论】:

  • 谢谢!事实上,我的发现比你提出的要快 15% :)
【解决方案2】:

假设您的数组存储在 var 'A' 中,而您的值是 'v':

A(A>v+5 || A<v-5)=[];

【讨论】:

    【解决方案3】:

    在已排序的列表中搜索值的最佳方法是binary search,它只需要O(log(n)) 时间。这比将值与列表中的每个项目进行比较要好,后者的成本为O(n)。据我所知,Matlab 没有功能可以做到这一点。正如 Natan 已经提到的,您可以(a)为此使用内置函数 histc,它是用 C 语言编写的,可能会进行二进制搜索。

    function good = is_within_range(value, vector, threshold)
    
    % check that vector is sorted, comment this out for speed
    assert(all(diff(vector) > 0))
    assert(threshold > 0)
    
    % pad vector with +- inf for histc
    vector = [-inf, vector, inf];
    
    % find index of value in vector, so that vector(ind) <= value < vector(ind+1)
    % abuse histc, ignore bincounts
    [~, ind] = histc(value, vector);
    
    % check if we are within +- threshold from a value in vector,
    % either below or above
    good = (value <= vector(ind) + threshold) | value >= (vector(ind+1) - threshold);
    

    一些快速测试:

    >> is_within_range(0, [10, 30, 80], 5)
    ans = 0
    >> is_within_range(4, [10, 30, 80], 5)
    ans = 0
    >> is_within_range(5, [10, 30, 80], 5)
    ans = 1
    >> is_within_range(10, [10, 30, 80], 5)
    ans = 1
    >> is_within_range(15, [10, 30, 80], 5)
    ans = 1
    >> is_within_range(16, [10, 30, 80], 5)
    ans = 0
    >> is_within_range(31, [10, 30, 80], 5)
    ans = 1
    >> is_within_range(36, [10, 30, 80], 5)
    ans = 0
    

    另外,这个函数是矢量化的,所以你可以同时测试多个值:

    >> is_within_range([0, 4, 5, 10, 15, 16, 31, 36], [10, 30, 80], 5)
    ans =
         0     0     1     1     1     0     1     0
    

    【讨论】:

      猜你喜欢
      • 2012-12-24
      • 2017-07-07
      • 2017-02-14
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      • 2013-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多