web-dev-qa-db-fra.com

Quel est le meilleur moyen d’obtenir la valeur minimale ou maximale d’un tableau de nombres?

Disons que j'ai un tableau de nombres: [2,3,3,4,2,2,5,6,7,2]

Quel est le meilleur moyen de trouver la valeur minimale ou maximale dans ce tableau?

Actuellement, pour obtenir le maximum, je boucle en boucle dans le tableau et je réinitialise une variable à la valeur si elle est supérieure à la valeur existante:

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

Cela ne semble tout simplement pas être le moyen le plus performant de le faire (j'essaie d'éviter les boucles autant que possible).

33
Eric Belair

Les réponses théoriques de tous les autres sont toutes bien, mais soyons pragmatiques. ActionScript fournit les outils dont vous avez besoin pour ne pas avoir à écrire de boucle dans ce cas!

Tout d’abord, notez que Math.min() et Math.max() peuvent prendre n’importe quel nombre d’arguments. En outre, il est important de comprendre la méthode apply() disponible pour les objets Function. Cela vous permet de passer des arguments à la fonction en utilisant une Array. Profitons des deux:

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

Voici la meilleure partie: la "boucle" est en fait exécutée à l'aide de code natif (dans Flash Player). Il est donc plus rapide que de rechercher la valeur minimale ou maximale à l'aide d'une boucle ActionScript pure.

81
joshtynjala

Il n’existe aucun moyen fiable d’obtenir le minimum/maximum sans tester chaque valeur. Vous ne voulez pas essayer une sorte ou quelque chose comme ça, parcourir le tableau est O (n), ce qui est mieux que tout algorithme de tri ne peut le faire dans le cas général.

30
Adam Bellaire

Si

  1. Le tableau n'est pas trié
  2. Trouver le min et le max est fait simultanément

Ensuite, il existe un algorithme qui trouve le minimum et le maximum dans 3n/2 nombre de comparaisons. Ce qu'il faut faire, c'est traiter les éléments du tableau par paires. Le plus grand de la paire doit être comparé au max actuel et le plus petit de la paire au min actuel. En outre, il faut faire particulièrement attention si le tableau contient un nombre impair d'éléments.

En code c ++ (empruntant du code à 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;
}

Il est très facile de voir que le nombre de comparaisons nécessaires est de 3n/2. La boucle est exécutée n/2 fois et à chaque itération, 3 comparaisons sont effectuées. C'est probablement l'optimum que l'on peut atteindre. Pour le moment, je ne peux pas pointer vers une source précise de cela. (Mais, je pense avoir vu une preuve de cela quelque part.)

La solution récursive donnée par Mehrdad ci-dessus réalise probablement également ce nombre minimal de comparaisons (la dernière ligne doit être modifiée). Mais avec le même nombre de comparaisons, une solution itérative sera toujours préférable à une solution récursive en raison de la surcharge de l'appel de fonction, comme il l'a mentionné. Cependant, si l’on se soucie seulement de trouver le minimum et le maximum de quelques nombres (comme le fait Eric Belair), personne ne remarquera la moindre différence entre l’ordinateur actuel et l’une des approches ci-dessus. Pour un large éventail, la différence pourrait être significative.

Bien que cette solution et la solution proposée par Matthew Brubaker aient une complexité O(n), dans la pratique, il convient d’évaluer soigneusement les constantes cachées impliquées. Le nombre de comparaisons dans sa solution est 2n. L'accélération obtenue avec la solution avec les comparaisons 3n/2 par opposition aux comparaisons 2n serait perceptible.

27
Rayhan

À moins que le tableau ne soit trié, c'est ce que vous obtiendrez de mieux. S'il est trié, prenez simplement le premier et le dernier élément.

Bien sûr, s’il n’est pas trié, il est garanti que le tri en premier et le premier et le dernier seront moins efficaces qu’une simple boucle. Même les meilleurs algorithmes de tri doivent examiner chaque élément plus d'une fois (une moyenne de 0 fois (log N) pour chaque élément. C'est le total de O (N * Log N).

Si vous souhaitez accéder rapidement au plus grand élément d'une structure de données, examinez les tas pour vous permettre de conserver efficacement les objets dans un ordre quelconque.

19
Eclipse

Vous devez parcourir le tableau, pas d'autre moyen de vérifier tous les éléments. Juste une correction pour le code - si tous les éléments sont négatifs, maxValue sera 0 à la fin. Vous devez l'initialiser avec la valeur minimale possible pour un entier. 
Et si vous allez parcourir le tableau plusieurs fois, il est judicieux de le trier en premier, car la recherche est plus rapide (recherche binaire) et les éléments minimum et maximum ne sont que le premier et le dernier.

12
Rumen Georgiev

Cela dépend de ce que vous appelez "le mieux". D'un point de vue théorique, vous ne pouvez pas résoudre le problème en moins de O(n) dans une machine de Turing déterministe.

L'algorithme naïf est trop en boucle et met à jour min, max. Cependant, une solution récursive nécessitera moins de comparaisons que l'algorithme naïf, si vous voulez obtenir simultanément min, max (ce n'est pas nécessairement plus rapide en raison de la surcharge des appels de fonctions).

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

La solution la plus simple serait de trier et d’obtenir le premier et le dernier élément, bien que ce ne soit évidemment pas le plus rapide;)

La meilleure solution, en termes de performances, pour trouver le minimum ou maximum est l'algorithme naïf que vous avez écrit (avec une seule boucle). 

4
Mehrdad Afshari

Math.max () est en réalité un code as3 compilé en opcodes AVM2 et, en tant que tel, n’est pas plus "natif" que tout autre code as3. En conséquence, ce n'est pas nécessairement la mise en œuvre la plus rapide.

En fait, étant donné que cela fonctionne sur le type Array, il est plus lent que le code soigneusement écrit usign Vector:

J'ai fait une comparaison rapide de plusieurs implémentations naïves de Math.max dans Vector et Array, en utilisant PerformanceTest de gskinner (Vector et Array étant remplis de nombres aléatoires identiques) . L'implémentation de Vector la plus rapide semblait être plus de 3 fois plus rapide que Math. max avec le lecteur AIR SDK/release récent (flash player WIN 14,0,0,122 RELEASE, compilé avec AIR SDK 14):

3,5 ms en moyenne pour 1 000 000 de valeurs, contre 11 ms en moyenne pour Math.max ():

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

La conclusion est que si vous êtes préoccupé par les performances, vous devez utiliser Vector over Array partout où vous le pouvez, et ne pas toujours vous fier aux implémentations par défaut, en particulier lorsqu'elles forcent l'utilisation de Array.

PS: la même implémentation avec une boucle pour chaque () est 12x plus lente ...!

3
jauboux

Si vous construisez le tableau une fois et que vous voulez trouver le maximum une seule fois, itérer est ce que vous pouvez faire de mieux.

Lorsque vous souhaitez modifier le tableau et que vous souhaitez parfois connaître le nombre maximal d'éléments, vous devez utiliser un Priority Queue . Une des meilleures structures de données pour cela est un tas de Fibonacci , si cela est trop compliqué, utilisez un tas binaire qui est plus lent mais toujours bon.

Pour trouver le minimum et le maximum, créez simplement deux tas et modifiez le signe des nombres dans l'un d'eux.

2
martinus

Cela dépend des exigences du monde réel.

Si votre question est simplement hypothétique, alors les bases ont déjà été expliquées. C'est un problème typique de recherche contre tri. Il a déjà été mentionné que, sur le plan de l’algorithme, vous ne réussirez pas mieux que O(n) dans ce cas.

Cependant, si vous envisagez une utilisation pratique, les choses deviennent plus intéressantes. Vous devrez ensuite examiner la taille du tableau et les processus impliqués dans l'ajout et la suppression de l'ensemble de données. Dans ces cas, il peut être préférable de procéder au tri à la volée au moment de l'insertion/du retrait. Les insertions dans un tableau pré-trié ne coûtent pas très cher.

La réponse de requête la plus rapide à la requête Min Max sera toujours celle d'un tableau trié, car, comme d'autres l'ont déjà mentionné, vous prenez simplement le premier ou le dernier élément, ce qui vous donne un coût de O(1).

Pour un peu plus d'explications techniques sur les coûts de calcul impliqués, et la notation Big O, consultez l'article Wikipedia ici .

Entaille.

2
Nick

Veuillez prendre en compte que trier le tableau ne sera plus rapide que de boucler jusqu'à une certaine taille du tableau. Si votre tableau est petit (et ce sera comme ça à tout moment), alors votre solution est parfaite. Mais si elle devient trop grande, vous devez utiliser une condition pour utiliser la méthode de tri lorsque le tableau est petit et l'itération normale lorsqu'il est trop grand.

1
Javier

Cela peut être fait de différentes manières.

  1. Force brute. Recherche linéaire pour min et max séparément. (2N Comparaisons et 2N pas) 
  2. Itérer linéairement et vérifier chaque nombre pour min et max. (Comparaisons 2N) 
  3. Utilisez Diviser et conquérir. (Entre 2N et 3N/2 comparaisons) 
  4. Comparez par paires comme expliqué ci-dessous (Comparaisons 3N/2)

Comment trouver max. et min. en tableau en utilisant des comparaisons minimum?


Si vous êtes vraiment paranoïaque à propos de la vitesse, du temps d’exécution et du nombre de comparaisons, reportez-vous également à http://www.geeksforgeeks.org/maximum-and-minimum-in-an-aran-ray/

0
Shogo Warrior

Algorithme MaxMin (premier, dernier, max, min)

// Cet algorithme stocke l'élément le plus haut et le plus bas

// Valeurs du tableau global A dans les variables globales max et min

// tmax et tmin sont des variables globales temporaires 

{
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;
  }
 }
}
0
Sharief Muzammil

Trouver les valeurs maximales d'un tableau .__ Voyons comment obtenir des valeurs min, max en utilisant une seule fonction

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

la même chose peut faire pour trouver la valeur min

0

Surpris, personne n’a mentionné le parallélisme ici.

Si vous avez vraiment un grand tableau, vous pouvez utiliser parallel-for, sur des sous-gammes . En fin de compte, comparer toutes les sous-gammes . Mais le parallélisme entraîne également une certaine pénalité, de sorte que cela ne serait pas optimal sur de petits tableaux . Cependant, si vous avez d'énormes ensembles de données, cela commence à avoir un sens et vous obtenez une réduction de la division temporelle proche du nombre de threads effectuant le test.

0
user3800527

Voici la solution avec 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);
}
0
Ajay

Chemin le plus court: 

Math.min.apply (null, array); // cela retournera la valeur min du tableau
Math.max.apply (null, array); // cela retournera la valeur maximale du tableau 

autrement obtenir la valeur min & max du tableau

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

Comme vous pouvez le constater, le code de ces deux fonctions est très similaire. La fonction définit une variable - max (ou min), puis parcourt le tableau avec une boucle en vérifiant chaque élément suivant. Si l'élément suivant est supérieur au courant, définissez-le sur max (ou min). En fin de compte, renvoyez le numéro.

0
sajankumar vijayan

Si vous souhaitez rechercher simultanément les valeurs min et max, la boucle peut être modifiée comme suit:

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

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

Ceci devrait permettre d’atteindre le timing O(n).

0
Matthew Brubaker