快速意味着优于O(N),这与find()能够一样好。我知道有ismembc
和ismembc2
,但我不认为它们中的任何一个都是我想要的。我阅读了文档,似乎他们在x中搜索等于的成员,但我希望的索引第一个值大于而不是x。
现在,如果其中任何一个 能够做到这一点,那么有人可以举个例子,因为我无法理解。
理想行为:
first_greater_than([0, 3, 3, 4, 7], 1)
返回2,第一个值的索引大于1,但显然输入数组会大得多。
当然,二进制搜索并不太难实现,但如果MATLAB已经完成,我宁愿使用他们的方法。
答案 0 :(得分:3)
由于输入已经排序,自定义二进制搜索应该有效(您可能需要对边缘情况进行一些更新,即请求的值小于数组的所有元素):
function [result, res2] = binarySearchExample(val)
%// Generate example data and sort it
N = 100000000;
a = rand(N, 1);
a = sort(a);
%// Run the algorithm
tic % start timing of the binary search algorithm
div = 1;
idx = floor(N/div);
while(1)
div = div * 2;
%// Check if less than val check if the next is greater
if a(idx) <= val,
if a(idx + 1) > val,
result = a(idx + 1);
break
else %// Get bigger
idx = idx + max([floor(N / div), 1]);
end
end
if a(idx) > val, % get smaller
idx = idx - floor(N / div);
end
end % end the while loop
toc % end timing of the binary search algorithm
%% ------------------------
%% compare to MATLAB find
tic % start timing of a matlab find
j = find(a > val, 1);
res2 = a(j);
toc % end timing of a matlab find
%// Benchmark
>> [res1, res2] = binarySearchExample(0.556)
Elapsed time is 0.000093 seconds.
Elapsed time is 0.327183 seconds.
res1 =
0.5560
res2 =
0.5560
答案 1 :(得分:1)
这是我的实施。这不是我想要的答案,但是现在,我将不得不假设我在MATLAB中没有实现我的目标。
所有MATLAB索引都做错了,因为它们从1开始而不是0
尽管如此,仍然从0开始指数。所以你会看到
索引看起来像这样:array(1+i)
访问元素i,我在哪里
在[0,N)。此外,所有MATLAB范围都做错了。他们的惯例是
[a,b],而不是[a,b)。所以你会看到看起来像这样的范围
贯穿:0:N-1是数字的范围(通常是数字的指数)
N维数组)从0到N.当数组用范围索引时,
两次更正都必须同时进行。 1添加到顶部
底部边界和1从顶部减去。这是结果:
array(1 + a:b)访问[a,b)中的元素,其中a和b在[0,N]中
和b>一个。我应该真的只是使用python和scipy,但是为时已晚。下一个项目......
binary_search.m:在我看来,它比@ ljk07的实施更加整洁,但当然它们仍然可以接受。谢谢,@ ljk07。
function i = binary_search(v, x)
%binary_search finds the first element in v greater than x
% v is a vector and x is a double. Returns the index of the desired element
% as an int64 or -1 if it doesn't exist.
% We'll call the first element of v greater than x v_f.
% Is v_f the zeroth element? This is technically covered by the algorithm,
% but is such a common case that it should be addressed immediately. It
% would otherwise take the same amount of time as the rest of them. This
% will add a check to each of the others, though, so it's a toss-up to an
% extent.
if v(1+0) > x
i = 0;
return;
end
% MATLAB foolishly returns the number of elements as a floating point
% constant. Thank you very much, MATLAB.
b = int64(numel(v));
% If v_f doesn't exist, return -1. This is also needed to ensure the
% algorithm later on terminates, which makes sense.
if v(1+b-1) <= x
i = -1;
return;
end
a = int64(0);
% There is now guaranteed to be more than one element, since if there
% wasn't, one of the above would have matched. So we split the [a, b) range
% at the top of the loop.
% The number of elements in the interval. Calculated once per loop. It is
% recalculated at the bottom of the loop, so it needs to be calculated just
% once before the loop can begin.
n = b;
while true
% MATLAB's / operator foolishly rounds to nearest instead of flooring
% when both inputs are integers. Thank you very much, MATLAB.
p = a + idivide(n, int64(2));
% Is v_f in [a, p) or [p, b)?
if v(1+p-1) > x
% v_f is in [a, p).
b = p;
else
% v_f is in [p, b).
a = p;
end
n = b - a;
if n == 1
i = a;
return;
end
end
end
<强> binary_search_test.m:强>
% Some simple tests. These had better pass...
assert(binary_search([0], 0) == -1);
assert(binary_search([0], -1) == 0);
assert(binary_search([0 1], 0.5) == 1);
assert(binary_search([0 1 1], 0.5) == 1);
assert(binary_search([0 1 2], 0.5) == 1);
assert(binary_search([0 1 2], 1.5) == 2);
% Compare the algorithm to internal find.
for n = [1 1:8]
n
v = sort(rand(10^n, 1));
x = 0.5;
%%
tic;
ifind = find(v > x, 1,'first') - 1;
toc;
% repeat. The second time is faster usually. Some kind of JIT
% optimisation...
tic;
ifind = find(v > x, 1,'first') - 1;
toc;
tic;
ibs = binary_search(v, x);
toc;
tic;
ibs = binary_search(v, x);
toc;
assert(ifind == ibs);
end
binary_search_test.m的输出(在我的计算机上):
n =
1
Elapsed time is 0.000054 seconds.
Elapsed time is 0.000021 seconds.
Elapsed time is 0.001273 seconds.
Elapsed time is 0.001135 seconds.
n =
2
Elapsed time is 0.000050 seconds.
Elapsed time is 0.000018 seconds.
Elapsed time is 0.001571 seconds.
Elapsed time is 0.001494 seconds.
n =
3
Elapsed time is 0.000034 seconds.
Elapsed time is 0.000025 seconds.
Elapsed time is 0.002344 seconds.
Elapsed time is 0.002193 seconds.
n =
4
Elapsed time is 0.000057 seconds.
Elapsed time is 0.000044 seconds.
Elapsed time is 0.003131 seconds.
Elapsed time is 0.003031 seconds.
n =
5
Elapsed time is 0.000473 seconds.
Elapsed time is 0.000333 seconds.
Elapsed time is 0.003620 seconds.
Elapsed time is 0.003161 seconds.
n =
6
Elapsed time is 0.003984 seconds.
Elapsed time is 0.003635 seconds.
Elapsed time is 0.004209 seconds.
Elapsed time is 0.003825 seconds.
n =
7
Elapsed time is 0.034811 seconds.
Elapsed time is 0.039106 seconds.
Elapsed time is 0.005089 seconds.
Elapsed time is 0.004867 seconds.
n =
8
Elapsed time is 0.322853 seconds.
Elapsed time is 0.323777 seconds.
Elapsed time is 0.005969 seconds.
Elapsed time is 0.005487 seconds.
绝对有加速。在我的计算机上,您可以看到在百万元素标记附近达到加速。因此,除非在C中实现binary_search或者你有一个包含大约百万个元素的向量,否则即使它使用的是愚蠢的算法,查找仍然更快。我期待门槛低于那个。我的猜测是因为查找主要是在C内部实现的。不公平:(但是,对于我的特定应用程序,我的矢量大小只有大约一千,所以毕竟,发现对我来说真的更快。至少直到那天我用C语言实现了带有mex文件的二进制搜索或切换到scipy,无论哪个先发生。我有点厌倦了MATLAB的一些不方便的切换。你可以通过阅读我的代码中的注释来判断。