40

Let's say I have an Array of numbers: [2,3,3,4,2,2,5,6,7,2]

What is the best way to find the minimum or maximum value in that Array?

Right now, to get the maximum, I am looping through the Array, and resetting a variable to the value if it is greater than the existing value:

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;
}

This just doesn't seem like the best performing way to do this (I try to avoid loops whenever possible).

Iman
  • 17,932
  • 6
  • 80
  • 90
Eric Belair
  • 10,574
  • 13
  • 75
  • 116
  • 4
    Running a foreach on simple arrays like this is never a bottleneck. The only time loops get expensive is when you do something bad like execute SQL inside a loop or duplicate some kind of calculation that will always be the same everytime. Don't fear the loop my friend! – TravisO Jan 08 '09 at 16:11
  • 1
    What's wrong with loops? – Daniel Daranas Jan 08 '09 at 16:38
  • What you must try to avoid are deeply nested loops... – Alex. S. Jan 28 '09 at 21:45

17 Answers17

82

The theoretical answers from everyone else are all neat, but let's be pragmatic. ActionScript provides the tools you need so that you don't even have to write a loop in this case!

First, note that Math.min() and Math.max() can take any number of arguments. Also, it's important to understand the apply() method available to Function objects. It allows you to pass arguments to the function using an Array. Let's take advantage of both:

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);

Here's the best part: the "loop" is actually run using native code (inside Flash Player), so it's faster than searching for the minimum or maximum value using a pure ActionScript loop.

Josh Tynjala
  • 5,235
  • 3
  • 23
  • 25
  • Math operations are notoriously slow in Flash. I'm wondering if it's actually proven to be faster this way or just an assumption? – keyle Jun 20 '12 at 04:45
  • Yes maybe it's faster, then again maybe it's not. I think this answer would be much better with an actual comparison of the two methods. – laurent Nov 24 '12 at 08:43
  • Math.max is not native, it's running inside AVM2. It is indeed a lot slower (3x) than a for() loop on Vector.. You can have a look at my answer for more details. – jauboux Aug 27 '14 at 13:56
  • 1
    I just checked this and the JavaScript version appears to be almost an order of magnitude faster in Chrome, significantly faster in Firefox and 3 times slower in Safari, compared to native: http://jsperf.com/math-min-max-vs-js-min-max Calling a function via `apply` is known to perform poorly compared to a normal function call. – Vitaly Nov 08 '15 at 13:44
30

There isn't any reliable way to get the minimum/maximum without testing every value. You don't want to try a sort or anything like that, walking through the array is O(n), which is better than any sort algorithm can do in the general case.

Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
28

If

  1. The array is not sorted
  2. Finding the min and max is done simultaneously

Then there is an algorithm that finds the min and max in 3n/2 number of comparisons. What one needs to do is process the elements of the array in pairs. The larger of the pair should be compared with the current max and the smaller of the pair should be compared with the current min. Also, one needs take special care if the array contains odd number of elements.

In c++ code (borrowing some code from 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;
}

It's very easy to see that the number of comparisons it takes is 3n/2. The loop runs n/2 times and in each iteration 3 comparisons are performed. This is probably the optimum one can achieve. At this moment, I cannot point to a definite source of that. (But, I think I have seen a proof of that somewhere.)

The recursive solution given by Mehrdad above, probably also achieves this minimal number of comparisons (the last line needs to be changed). But with the same number of comparisons an iterative solution will always beat a recursive solution due to overhead in the function call as he mentioned. However, if one only cares about finding min and max of a few numbers (as Eric Belair does), no one will notice any difference in todays computer with any of the approaches above. For a large array, the difference could be significant.

Though this solution and the solution given by Matthew Brubaker has O(n) complexity, in practice one should carefully asses the hidden constants involved. The number of comparisons in his solution is 2n. The speedup gained with the solution with 3n/2 comparisons as opposed to 2n comparisons would be noticeable.

  • 1
    There's a bit of code missing: the "else" portion of the "if ( array[start] < array[start+1] )" block. – Brilliand Oct 16 '11 at 10:58
  • 1
    There's a subtle hidden cost with this approach which makes it much slower than the naive way. For random data, that first conditional inside the loop will be false 50% of the time, meaning that the CPU can't reliably predict which way that conditional will go. In the naive approach, both conditionals are usually false which leads to very few branch mispredictions. I tested out both algorithms using gcc, clang, and icc on both my machines and found that the 2*N algorithm is usually about three and a half times faster. – mansfield Mar 20 '17 at 17:29
20

Unless the array is sorted, that's the best you're going to get. If it is sorted, just take the first and last elements.

Of course, if it's not sorted, then sorting first and grabbing the first and last is guaranteed to be less efficient than just looping through once. Even the best sorting algorithms have to look at each element more than once (an average of O(log N) times for each element. That's O(N*Log N) total. A simple scan once through is only O(N).

If you are wanting quick access to the largest element in a data structure, take a look at heaps for an efficient way to keep objects in some sort of order.

Eclipse
  • 44,851
  • 20
  • 112
  • 171
  • This is exactly what I decided to do - sort the Array (descending for MAX, ascending for MIN), and then grab the first element. – Eric Belair Jan 08 '09 at 16:25
  • 4
    You do realize that sorting takes way more time than simply scanning the list once. – Eclipse Jan 08 '09 at 16:30
  • there's no need to resort the array every time if you do sorting at insertion. Then you only need to take the first/last element for min/max values. – Matthew Brubaker Jan 08 '09 at 16:32
  • If that's the case, then it may be more efficient. – Eclipse Jan 08 '09 at 16:40
  • Even if your insertion is O(log n), you're still doing more work by keeping it sorted. – Nick Johnson Jan 08 '09 at 18:36
  • 1
    Addendum: That is, assuming you don't need to regularly ask for the largest element - in which case keeping it sorted or using a heap _is_ a better approach. – Nick Johnson Jan 08 '09 at 18:37
  • Your answer suggests that all sorting algorithms at their best are O(nlogn), however, that is only true for *comparison* sorts. You can sort an array of integral types in O(n). Regardless, for retrieving the min or max, one loop over the array is fastest. – Zach Langley Jan 08 '09 at 21:49
  • @Zach: Which sorting algorithm is O(n)? – Adam Bellaire Jan 09 '09 at 12:23
  • With a limited domain, you can do counting sorts that essentially boil down to preassigning slots in a large aray, going through the list once and putting each item in its pre-ordained slot, then going through the slots and putting things back in the array in order. Or a variant of that idea. – Eclipse Jan 09 '09 at 16:01
12

You have to loop through the array, no other way to check all elements. Just one correction for the code - if all elements are negative, maxValue will be 0 at the end. You should initialize it with the minimum possible value for integer.
And if you are going to search the array many times it's a good idea to sort it first, than searching is faster (binary search) and minimum and maximum elements are just the first and the last.

Rumen Georgiev
  • 702
  • 4
  • 23
4

Depends on what you call "best." From a theoretical point of view, you cannot solve the problem in less than O(n) in a deterministic Turing machine.

The naive algorithm is too loop and update min, max. However, a recursive solution will require less comparisons than naive algorithm, if you want to get min, max simultaneously (it isn't necessarily faster due to function call overhead).

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) } ;
}

The simplest solution would be to sort and get the first and last item, though it's obviously not the fastest ;)

The best solution, performance-wise, to find the minimum or maximum is the naive algorithm you written (with a single loop).

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • Sort may be simple but definitely not the most efficient. – TravisO Jan 08 '09 at 16:12
  • Of course, I didn't say so! Best is not the most efficient, however! – Mehrdad Afshari Jan 08 '09 at 16:17
  • I would think a sort would be more efficient than a loop? – Eric Belair Jan 08 '09 at 16:24
  • I have to disagree that this has fewer comparisons than a "naive" iteration. You are comparing every element anyway, why complicate it further? – Matthew Brubaker Jan 08 '09 at 16:25
  • @Eric a sort will require you to spend however long the sort algorithm takes (greater than O(n)) whereas an intelligent loop will be O(n) in length – Matthew Brubaker Jan 08 '09 at 16:26
  • how do you know what the "last" item is? Unless you have a fixed-length array, and not some funky vector class or something, you may not know where it ends – warren Jan 08 '09 at 16:44
  • @Matthew: if you need to compute both minimum and maximum, you have to make 2n-2 comparisons in naive iteration (n-1 comparisons for each one). With this algorithm you do 3n/2 comparisons. – Mehrdad Afshari Jan 08 '09 at 18:50
  • @warren: vector's end is: v[v.size()-1] – Mehrdad Afshari Jan 08 '09 at 18:50
  • 2
    @Eric: I didn't mean sort is more efficient. I said he wants the best method. I meant the best method is not always the fastest. Of course a sort would take more time. But it's one line of code. So it might be the best in that regard ;) – Mehrdad Afshari Jan 08 '09 at 18:52
3

Math.max() is actually as3 code compiled to AVM2 opcodes, and as such is not more "native" than any other as3 code. As a consequence, it is not necessarily the fastest implementation.

Actually, given that it works on Array type, it is slower than carefully written code usign Vector:

I did a quick benchmark comparison of several naive Vector and Array implementations of Math.max, using gskinner's PerformanceTest (Vector and Array being filled with identical random Numbers). The fastest Vector implementation appeared to be more than 3x faster than Math.max with recent AIR SDK/release player (flash player WIN 14,0,0,122 RELEASE, compiled with AIR SDK 14):

average 3.5 ms for 1,000,000 values, compared to Math.max() average of 11ms :

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;
}

Conclusion is that if you are concerned by performance, you should use Vector over Array anywhere you can in the first place, and not always rely on default implementations, especially when they force the use of Array

PS:same implementation with a for each() loop is 12x slower ...!

jauboux
  • 888
  • 6
  • 12
2

If you are building the array once and want to find the maximum just once, iterating is the best you can do.

When you want to modify the array and occasionally want to know the maximum element, you should use a Priority Queue. One of the best data structures for that is a Fibonacci Heap, if this is too complicated use a Binary Heap which is slower but still good.

To find minimum and maximum, just build two heaps and change the sign of the numbers in one of them.

martinus
  • 17,736
  • 15
  • 72
  • 92
2

This depends on real world application requirements.

If your question is merely hypothetical, then the basics have already been explained. It is a typical search vs. sort problem. It has already been mentioned that algorithmically you are not going to achieve better than O(n) for that case.

However, if you are looking at practical use, things get more interesting. You would then need to consider how large the array is, and the processes involved in adding and removing from the data set. In these cases, it can be best to take the computational 'hit' at insertion / removal time by sorting on the fly. Insertions into a pre-sorted array are not that expensive.

The quickest query response to the Min Max request will always be from a sorted array, because as others have mentioned, you simply take the first or last element - giving you an O(1) cost.

For a bit more of a technical explanation on the computational costs involved, and Big O notation, check out the Wikipedia article here.

Nick.

Nick
  • 2,285
  • 2
  • 14
  • 26
1

Please take into account that sorting the array will only be faster that looping up to certain size of the array. If your array is small (and it will be like that any time) then your solution is perfectly fine. But if it might get too large you should use a conditional to use the sort approach when the array is small, and the normal iteration when it is too large

0

Shortest way :

Math.min.apply(null,array); //this will return min value from array
Math.max.apply(null,array); //this will return max value from array

otherway of getting min & max value from array

 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;
    }

As you can see, the code in both of these functions is very similar. The function sets a variable - max (or min) and then runs through the array with a loop, checking each next element. If the next element is higher than the current, set it to max (or min). In the end, return the number.

sajan
  • 1,355
  • 1
  • 14
  • 19
0

There are a number of ways this can be done.

  1. Brute force. Linear search for both min and max separately. (2N comparisons and 2N steps)
  2. Iterate linearly and check each number for both min and max. (2N comparisons)
  3. Use Divide and conquer. (Between 2N and 3N/2 comparisons)
  4. Compare by pairs explained below (3N/2 Comparisons)

How to find max. and min. in array using minimum comparisons?


If you are really paranoid about speed, runtime & number of comparisons, also refer to http://www.geeksforgeeks.org/maximum-and-minimum-in-an-array/

Community
  • 1
  • 1
0

Below is Solution with 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);
}
Ajay Kumar
  • 4,864
  • 1
  • 41
  • 44
0

If you want to find both the min and max at the same time, the loop can be modified as follows:

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

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

This should get achieve O(n) timing.

Matthew Brubaker
  • 3,097
  • 1
  • 21
  • 18
0

Amazed no-one mentioned parallelism here.

If you got really a huge array, you can use parallel-for, on sub ranges. In the end compare all sub-ranges. But parallelism comes width some penalty too, so this would not optimize on small arrays. However if you got huge datasets it starts to make sense, and you get a time division reduction nearing the amount of threads performing the test.

Peter
  • 2,043
  • 1
  • 21
  • 45
-1

Find max values from a array Let's see how to obtain min, max values by using a single funtion

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; 
}

same thing can do for find min value

-5

After reading everyone's comments (thank you for your interest), I found that the "best" way (least amount of code, best performing) to do this was to simply sort the Array, and then grab the first value in the Array:

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

myArray.sort(Array.NUMERIC);

var minValue:int = myArray[0];

This also works for an Array of Objects - you simply use the Array.sortOn() function and specify a property:

// 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;

I hope this helps someone else someday!

Eric Belair
  • 10,574
  • 13
  • 75
  • 116