计算第二个最小值的有效方法

时间:2017-02-27 10:58:07

标签: matlab max min

给定矩阵,可以很容易地计算最小值的值和索引:

A = rand(10);
[value, index] = min(A(:));

但是我还想恢复第二个最小值(同上最大值)。

我当然可以采取以下两种方法中的任何一种:

  1. 将A转换为矢量并对其进行排序。

    PROS:我可以恢复第二,第三...... n最小值

    缺点:如果A很大,排序很昂贵

  2. 一旦找到A的最小位置,我可以用一个大的值替换这个值(例如:Inf),然后再次运行min

    PROS:比排序便宜

    缺点:我必须修改我的矩阵(并将修改后的值保存在aux变量中)。在大型矩阵上重新运行min也很昂贵。

  3. 我想知道是否有更好的解决方案:

    当计算min时,算法必须跟踪到目前为止找到的最小值,直到新值具有较低的值(然后我们更新该值)。 相反,我们会跟踪到目前为止发现的最后n分钟值,以便恢复最低n值。

    我可以实现这一点,但我想知道它是否是最佳方法,或者它是否已经实施。

4 个答案:

答案 0 :(得分:3)

我不知道在哪种情况下它会比排序更便宜,但是使用以下代码是一种简单但不那么快的方法。我可能错了,但如果您只想要第一分钟和第二分钟,我认为您不能使用内置函数更快。

A = rand(10);
[firstMin, firstMinIndex] = min(A(:));
secondMin = min(A(A~=firstMin));
secondMinIndex = find(A==secondMin); % slow, but use only if you need the index

在这里,你要经过矩阵两次,一次用于布尔操作,另一次用于第二次。

在对2000x2000和4000x4000随机矩阵进行一些测试之后,似乎这个代码片段比在同一矩阵上应用的sort函数快3.5倍。

如果你真的需要更高的效率,你必须编写自己的mex例程,理论上你可以在n + log n-2比较中获得这两个值,如@luismendotomas提供的链接中所述。< / p>

希望这有帮助!

答案 1 :(得分:0)

一次通过:

a = [53 53 49 49 97 75 4 22 4 37];

first = Inf;
second = Inf;

for i = 1:1:numel(a)
    if (a(i) < first)
        second = first;
        first = a(i);
    elseif (a(i) < second && a(i) ~= first)
        second = a(i);
    end
end

fprintf('First smallest %d\n', first);
fprintf('Second smallest %d\n', second);

如果您希望将a(i) ~= first作为输出而不是4, 4

,则可以删除4, 23条件

另请参阅此SO question

答案 2 :(得分:0)

如前所述,我认为最好的(读取:&#34;最有效的#34;)方法是从@luismendotomas链接实现方法。

但是,如果你想避免自己做太多编程,那么你可以应用一些k近邻算法,因为你的数据有一个下限,例如:如果你的所有数据点都是正数,你可以找到2个最近的邻居为0.虽然我不确定这是否比你最初的建议更快。

对于一个k最近邻算法,请参见例如this

答案 3 :(得分:0)

beesleep已经指出方法2(通过计算最小值两次)比方法1(通过排序)更有效。然而,如上所述,在计算第二个最小值find的索引的答案中提供的实现非常低效。

事实上,要获得第二个最小值的索引,它是ca. 快10倍将第一个最小值设置为inf(如问题中所示),然后从min函数获取第二个最小值的索引(与使用相反) find

[firstMin, firstMinIndex] = min(A(:));
A(firstMinIndex) = inf;
[secondMin, secondMinIndex] = min(A(:));

以下是我用来将此实现与beesleep建议的实现进行比较的代码:

for i = 1:10

    A = rand(10000);

    tic
    [firstMin, firstMinIndex] = min(A(:));
    secondMin = min(A(A~=firstMin));
    secondMinIndex = find(A==secondMin); % slow, but use only if you need the index
    t1(i) = toc;

    tic
    [firstMin, firstMinIndex] = min(A(:));
    A(firstMinIndex) = inf;
    [secondMin, secondMinIndex] = min(A(:));
    t2(i) = toc;

end

disp(mean(t1) / mean(t2))