views:

4245

answers:

12

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

+19  A: 

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
+5  A: 

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
better yet - presume the first element is *both* the max and min, until proven otherwise
warren
+1 for finding the edge case
Amarghosh
+1  A: 

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
Sort may be simple but definitely not the most efficient.
TravisO
Of course, I didn't say so! Best is not the most efficient, however!
Mehrdad Afshari
I would think a sort would be more efficient than a loop?
Eric Belair
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
@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
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
@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
@warren: vector's end is: v[v.size()-1]
Mehrdad Afshari
@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
+14  A: 

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
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
You do realize that sorting takes way more time than simply scanning the list once.
Eclipse
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
If that's the case, then it may be more efficient.
Eclipse
Even if your insertion is O(log n), you're still doing more work by keeping it sorted.
Nick Johnson
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
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
@Zach: Which sorting algorithm is O(n)?
Adam Bellaire
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
See http://en.wikipedia.org/wiki/Radix_sort for an example.
Eclipse
+1  A: 

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
+1  A: 

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
+1  A: 

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
+20  A: 

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.

joshtynjala
A: 

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
+1  A: 

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

+4  A: 

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

       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.

A: 

Hi,Sorry this is the closest subject i could find to post this. I'm a bit new to flex and cannot get my head around this problem. can someone help. thanks in advance.

I have a string list path. path 1 - "one/two/three" path 2 - "one/two/four" path 3 - "five/six"

i need an advanced datagrid to show a tree structure like so one/ ...two/ ........three/ ............four five/ .......six but i want to achieve this dynamicall with arrays, objects, or arraycollection (as applicable) I need to loop through each string path using string methods which isnt a problem but how do i create "DYNAMIC" (depth) children? please help as i'm about to pull my hair out.

mitch
Better just post your problem as a new question ("Ask question" in the top right of the page), more people will see it that way. Also it's not really an *answer* to the question covered here.
sth