算法入门:最少比较次数求最大/最小/第二大元素

本文将解决三个问题:
input:A[1……n] 包含n个数字

output:
- A的最大值max
- A的最大值max和最小值min
- A的最大值max和第二大值

要求:比较的次数尽可能少


1.最大元素

如果使用排序的话,常见排序中比较快的有快速排序O(nlogn)。但是显然做一个线性遍历更加快。linear scan的时间复杂度为O(n) 。

max = A[1];
for i=2 to n
    if max < A[i]
    max = A[i];
return max


2.最大元素和最小元素

值得注意的是这里要求的是比较次数尽可能少,如果做两次linear scan的话是需要2n次比较的,如果使用下面这种方法的话可以将比较次数降低至3/2n。

min = A[1];
max = A[2];
for i = 1 to n
     if A[i] < A[i+1]
         if max < A[i+1]
             max = A[i+1];
         if min > A[i]
             min = A[i];

对于每一对A[i]和A[i+1],要比较3次,总共有n/2对,所以比较次数是3/2n。

3.求最大元素和第二大元素

如果使用线性扫描的话还是要比较2n次,第一次找最大值,再在剩下的元素中找最大值作为整体的第二大值。这里有一种方法是:在2中假设最大元素为max,将所有与max进行过比较的数字拿出来找最大值,也就是整体的第二大值。


建立一个vector B来存储被击败的数字。它是一个链表,每个元素是一个数组,用来存储当前索引位置的元素击败过的数字,注意是把loser放到B中winner对应的坐标的位置。比如4,2,45,9四个数字,第一次比较2是loser所以把2放进B[1]的位置,1是winner 4的坐标。


这个图会比较清楚:
算法入门:最少比较次数求最大/最小/第二大元素_第1张图片

max(A,i,j)
{
    if i = j
        return i;
    else
        mid = ⌊(i+j)/2; // 向下取整
        a = max(A,i,mid);// 递归
        b = max(A,mid+1,j);
    if A[a]>A[b]
        insert A[b] into B[a];
        return a;
    if A[a]<A[b]
        insert A[a] into B[b];
        return b;
}

最后在主函数中:

main()
{
    i = max(A,1,n);
    traverse B[i] to find the secondMax;
    return A[i],secondMax
}

你可能感兴趣的:(算法)