从数组中获取最小值或最大值的最佳方法是什么?

时间:2009-01-08 15:57:20

标签: algorithm actionscript-3 flex actionscript complexity-theory

假设我有一组数字:[2,3,3,4,2,2,5,6,7,2]

在该数组中找到最小值或最大值的最佳方法是什么?

现在,为了获得最大值,我循环遍历数组,并将变量重置为该值,如果它大于现有值:

var myArray:Array /* of Number */ = [2,3,3,4,2,2,5,6,7,2];

var maxValue:Number = 0;

for each (var num:Number in myArray)
{
    if (num > maxValue)
        maxValue = num;
}

这似乎不是执行此操作的最佳方式(我尽可能避免循环)。

18 个答案:

答案 0 :(得分:81)

其他人的理论答案都很整洁,但让我们务实。 ActionScript提供了您需要的工具,因此在这种情况下甚至不必编写循环!

首先,请注意Math.min()Math.max()可以使用任意数量的参数。此外,了解apply()对象可用的Function方法非常重要。它允许您使用Array将参数传递给函数。让我们利用两者:

var myArray:Array = [2,3,3,4,2,2,5,6,7,2];
var maxValue:Number = Math.max.apply(null, myArray);
var minValue:Number = Math.min.apply(null, myArray);

这是最好的部分:“循环”实际上是使用本机代码(在Flash Player内部)运行的,因此它比使用纯ActionScript循环搜索最小值或最大值更快。

答案 1 :(得分:30)

没有任何可靠的方法可以在不测试每个值的情况下获得最小值/最大值。你不想尝试排序或类似的东西,遍历数组是O(n),这比一般情况下任何排序算法都要好。

答案 2 :(得分:27)

如果

  1. 数组未排序
  2. 同时完成最小值和最大值
  3. 然后有一个算法可以找到3n / 2个比较中的最小值和最大值。我们需要做的是成对处理数组的元素。应将该对中较大的一对与当前最大值进行比较,并将该对中较小的一对与当前最小值进行比较。此外,如果数组包含奇数个元素,则需要特别小心。

    在c ++代码中(借用Mehrdad的一些代码)。

    struct MinMax{
       int Min,Max;
    }
    
    MinMax FindMinMax(int[] array, int start, int end) {
       MinMax  min_max;
       int index;
       int n = end - start + 1;//n: the number of elements to be sorted, assuming n>0
       if ( n%2 != 0 ){// if n is odd
    
         min_max.Min = array[start];
         min_max.Max = array[start];
    
         index = start + 1;
       }
       else{// n is even
         if ( array[start] < array[start+1] ){
           min_max.Min = array[start];
           min_max.Max = array[start+1];
         }
         else{
           min_max.Min = array[start+1];
           min_max.Max = array[start];
         }
         index = start + 2;
       }
    
       int big, small;
       for ( int i = index; i < n-1; i = i+2 ){
          if ( array[i] < array[i+1] ){ //one comparison
            small = array[i];
            big = array[i+1];
          }
          else{
            small = array[i+1];
            big = array[i];
          }
          if ( min_max.Min > small ){ //one comparison
            min_max.Min = small;
          }
          if ( min_max.Max < big ){ //one comparison
            min_max.Max = big;
          }
       }
    
       return min_max;
    }
    

    很容易看出它所需的比较次数是3n / 2。循环运行n / 2次,并且在每次迭代中执行3次比较。这可能是最佳的。在这一刻,我无法指出这一点。 (但是,我想我已经在某处看到过这方面的证据。)

    上面Mehrdad给出的递归解决方案可能也实现了这种最小数量的比较(最后一行需要改变)。但是,通过相同数量的比较,迭代解决方案将始终击败递归解决方案,因为他提到了函数调用的开销。然而,如果只关心找到一些数字的最小值和最大值(正如Eric Belair所做的那样),没有人会注意到今天的计算机与上述任何方法有任何区别。对于大型阵列,差异可能很大。

    虽然这个解决方案和Matthew Brubaker给出的解决方案具有O(n)复杂性,但在实践中应该仔细评估所涉及的隐藏常数。他的解决方案中的比较次数是2n。与2n比较相比,使用3n / 2比较的解决方案获得的加速将是显而易见的。

答案 3 :(得分:19)

除非对数组进行排序,否则这将是您获得的最佳选择。如果它已排序,只需取第一个和最后一个元素。

当然,如果它没有排序,那么首先排序并抓住第一个和最后一个保证效率低于仅循环一次。即使是最好的排序算法也必须多次查看每个元素(每个元素的平均O(log N)次。这就是O(N * Log N)总数。一次扫描的简单只是O(N)。

如果您想快速访问数据结构中的最大元素,请查看堆,以便有效地保持对象的某种顺序。

答案 4 :(得分:12)

你必须遍历数组,没有其他方法来检查所有元素。只需对代码进行一次校正 - 如果所有元素都为负数,则maxValue最后为0。您应该使用整数的最小可能值对其进行初始化。
如果你要多次搜索数组,最好先对它进行排序,而不是搜索更快(二进制搜索),最小和最大元素只是第一个和最后一个。

答案 5 :(得分:4)

取决于你所谓的“最佳”。从理论的角度来看,在确定性的图灵机中,你不能在O(n)以内解决问题。

天真算法太循环并且更新min,max。但是,如果你想同时获得最小值,最大值(由于函数调用开销,它不一定更快),递归解决方案比朴素算法需要更少的比较。

struct MinMax{
   public int Min,Max;
}

MinMax FindMinMax(int[] array, int start, int end) {
   if (start == end)
      return new MinMax { Min = array[start], Max = array[start] };

   if (start == end - 1)
      return new MinMax { Min = Math.Min(array[start], array[end]), Max = Math.Max(array[start], array[end]) } ;

   MinMax res1 = FindMinMax(array, start, (start + end)/2);
   MinMax res2 = FindMinMax(array, (start+end)/2+1, end);
   return new MinMax { Min = Math.Min(res1.Min, res2.Min), Max = Math.Max(res1.Max, res2.Max) } ;
}

最简单的解决方案是排序并获取第一个和最后一个项目,尽管它显然不是最快的;)

在性能方面,找到最小最大值的最佳解决方案是您编写的简单算法(使用单个循环)。

答案 6 :(得分:3)

Math.max()实际上是as3代码编译成AVM2操作码,因此不是更多&#34; native&#34;比任何其他as3代码。因此,它不一定是最快的实施。

实际上,鉴于它适用于Array类型,它比精心编写的代码使用Vector:

我使用gskinner的PerformanceTest(Vector和Array填充相同的随机数)对Math.max的几个天真的Vector和Array实现进行了快速基准比较。 使用最新的AIR SDK /发布播放器(使用AIR SDK 14编译的Flash播放器WIN 14,0,0,122 RELEASE),最快的Vector实现似乎比Math.max快3倍以上:

对于1,000,000个值,

平均为3.5 ms,而Math.max()的平均值为11 ms:

function max(values:Vector.<Number>):Number
{
    var max:Number = Number.MIN_VALUE;
    var length:uint = values.length;
    for (var i:uint = 0; i < length ; ++i)
        if (values[i] > max)
            max = values[i];
    return max;
}

结论是,如果你担心性能,你应该首先在任何地方使用Vector over Array,而不是总是依赖于默认实现,特别是当它们强制使用Array时

PS:使用for each()循环的相同实现速度慢了12倍......!

答案 7 :(得分:2)

如果您正在构建一次,并希望只找到一次最大值,那么迭代是您可以做的最好的。

如果要修改数组并偶尔想知道最大元素,则应使用Priority Queue。其中一个最好的数据结构是Fibonacci Heap,如果这太复杂,请使用Binary Heap,但速度较慢但仍然很好。

要查找最小值和最大值,只需构建两个堆并更改其中一个数字的符号。

答案 8 :(得分:2)

这取决于实际应用要求。

如果您的问题仅仅是假设,那么基本原理已经解释过了。这是典型的搜索与排序问题。已经提到过,从算法上来说,在这种情况下你不会比O(n)更好。

但是,如果你正在寻找实际用途,事情会变得更有趣。然后,您需要考虑数组的大小,以及添加和删除数据集所涉及的过程。在这些情况下,最好在插入/移除时通过动态排序来计算“命中”。插入预先排序的数组并不昂贵。

对Min Max请求的最快查询响应将始终来自已排序的数组,因为正如其他人所提到的那样,您只需要使用第一个或最后一个元素 - 给您一个O(1)成本。

有关计算成本和Big O表示法的更多技术解释,请查看维基百科文章here

尼克。

答案 9 :(得分:1)

请注意,对数组进行排序只会比循环到某个大小的数组更快。如果你的阵列很小(并且它会像任何时候一样)那么你的解决方案就完全没问题了。但是如果它可能变得太大,你应该使用条件来在数组很小时使用排序方法,并在它太大时使用正常迭代

答案 10 :(得分:0)

最短路:

Math.min.apply(NULL,数组); //这将从数组中返回最小值   Math.max.apply(NULL,数组); //这将从数组返回最大值

获得分钟&amp; amp;数组的最大值

 function maxVal(givenArray):Number
    {
    var max = givenArray[0];
    for (var ma:int = 0; ma<givenArray.length; ma++)
    {
    if (givenArray[ma] > max)
    {
    max = givenArray[ma];
    }
    }
    return max;
    }

    function minVal(givenArray):Number
    {
    var min = givenArray[0];
    for (var mi:int = 0; mi<givenArray.length; mi++)
    {
    if (givenArray[mi] < min)
    {
    min = givenArray[mi];
    }
    }
    return min;
    }

如您所见,这两个函数中的代码非常相似。该函数设置一个变量--max(或min),然后通过循环遍历数组,检查每个下一个元素。如果下一个元素高于当前值,则将其设置为max(或min)。最后,返回号码。

答案 11 :(得分:0)

如果你想同时找到最小值和最大值,可以按如下方式修改循环:

int min = int.maxValue;
int max = int.minValue;

foreach num in someArray {
  if(num < min)
    min = num;
  if(num > max)
    max = num;
}

这应该达到O(n)时间。

答案 12 :(得分:0)

有很多方法可以做到。

  1. 蛮力。分别线性搜索最小值和最大值。的(2N 比较和2N步骤)
  2. 线性迭代并检查每个数字的最小值和最大值。 (2N比较)
  3. 使用分而治之。 (2N和3N / 2之间的比较)
  4. 通过下面解释的对比较(3N / 2比较)
  5. How to find max. and min. in array using minimum comparisons?


    如果你真的对速度,运行时间和比较次数,也可参考 http://www.geeksforgeeks.org/maximum-and-minimum-in-an-array/

答案 13 :(得分:0)

算法MaxMin(第一个,最后一个,最大值,最小值)

//此算法存储最高和最低元素

//全局变量max和min中全局数组A的值

// tmax和tmin是临时全局变量

{
if (first==last) //Sub-array contains single element
 {
    max=A[first];
    min=A[first];
 }
 else if(first+1==last) //Sub-array contains two elements
  {
     if(A[first]<A[Last])
      {
      max=a[last];  //Second element is largest
      min=a[first]; //First element is smallest
      }
   else
   {
     max=a[first]; //First element is Largest 
     min=a[last];  //Second element is smallest
   }
}
else
 //sub-array contains more than two elements
{
 //Hence partition the sub-array into smaller sub-array 
 mid=(first+last)/2;
 //Recursively solve the sub-array
 MaxMin(first,mid,max,min);
 MaxMin(mid+1,last,tmax,tmin);
 if(max<tmax)
  {
     max=tmax;
  }
    if(min>tmin)
  {
   min=tmin;
  }
 }
}

答案 14 :(得分:0)

以下是o(n)的解决方案: -

public static void findMaxAndMinValue(int A[]){
    int min =0, max = 0;
    if(A[0] > A[1] ){
        min = A[1];
        max = A[0];
    }else{
        max = A[1];
        min = A[0];
    }
    for(int i = 2;i<A.length ;i++){
        if(A[i] > max){
            max = A[i];
        }
        if(min > A[i]){
            min = A[i];
        }
    }
    System.out.println("Maxinum Value is  "+min+" & Minimum Value is  "+max);
}

答案 15 :(得分:0)

惊讶没有人提到这里的并行性。

如果你真的有一个巨大的数组,你可以在子范围上使用parallel-for。 最后比较所有子范围。 但并行性也会给宽度带来一些损失,所以这不会在小数组上进行优化。但是,如果您拥有庞大的数据集,它就会开始变得有意义,并且您可以将时间分割减少到接近执行测试的线程数量。

答案 16 :(得分:0)

从数组中查找最大值 让我们看看如何通过单个功能获得最小值,最大值

public void findMaxValue(){
   int[] my_array = {1,2,,6,5,8,3,9,0,23};
   int max = my_array[0];
   for(int i=1; i<my_array.length; i++)
   {
      if(my_array[i] > max)
         max = my_array[i];
   }
   return max; 
}

同样的事情可以找到最小值

答案 17 :(得分:-5)

在阅读了所有人的评论后(感谢您的兴趣),我发现执行此操作的“最佳”方式(代码量最少,性能最佳)只是对数组进行排序,然后获取第一个值。阵列:

var myArray:Array /* of Number */ = [2,3,3,4,2,2,5,6,7,2];

myArray.sort(Array.NUMERIC);

var minValue:int = myArray[0];

这也适用于对象数组 - 您只需使用Array.sortOn()函数并指定属性:

// Sample data
var myArray:Array /* of XML */ = 
    [
    <item level="2" name="a" />
    <item level="3" name="b" />
    <item level="3" name="c" />
    <item level="2" name="d" />
    <item level="5" name="e" />
    ]

// Perform a descending sort on the specified attribute in Array to get the maximum value
myArray.sortOn("@level", Array.DESCENDING | Array.NUMERIC);

var lowestLevel:int = myArray[0].@level;

我希望有一天能帮助别人!