web-dev-qa-db-fra.com

Triez les tableaux de types primitifs dans l'ordre décroissant

J'ai un grand tableau de types primitifs (double) . Comment trier les éléments dans ordre décroissant ?

Malheureusement, l'API Java ne prend pas en charge le tri des types primitifs avec un comparateur.

Une solution de contournement serait de trier et puis inverser:

double[] array = new double[1048576];
...
Arrays.sort(array);
// reverse the array
for (int i = 0; i < array.length / 2; i++) {
     // swap the elements
     double temp = array[i];
     array[i] = array[array.length - (i + 1)];
     array[array.length - (i + 1)] = temp;
}

C'est lent - particulièrement si le tableau est déjà assez bien trié.

Quelle est la meilleure alternative?

44
Benedikt Waldvogel

Java Primitive inclut une fonctionnalité permettant de trier des tableaux de primitives basés sur un comparateur personnalisé. En l’utilisant, et en Java 8, votre exemple pourrait s’écrire comme suit:

double[] array = new double[1048576];
...
Primitive.sort(array, (d1, d2) -> Double.compare(d2, d1), false);

Si vous utilisez Maven, vous pouvez l'inclure avec:

<dependency>
    <groupId>net.mintern</groupId>
    <artifactId>primitive</artifactId>
    <version>1.2.1</version>
</dependency>

Lorsque vous transmettez false en tant que troisième argument à sort, il utilise un tri instable, une simple modification du fichier quicksort intégré dual-pivot de Java . Cela signifie que la vitesse doit être proche de celle du tri intégré.

Divulgation complète: j'ai écrit la bibliothèque Java Primitive.

16
Brandon Mintern

Je pense qu'il serait préférable de ne pas réinventer la roue et d'utiliser Arrays.sort ().

Oui, j'ai vu la partie "descendant". Le tri est la partie la plus difficile et vous souhaitez bénéficier de la simplicité et de la rapidité du code de bibliothèque Java. Une fois que cela est fait, vous inversez simplement le tableau, qui est une opération O(n) relativement bon marché. Voici du code J'ai trouvé que je pouvais le faire en aussi peu que 4 lignes:

for (int left=0, right=b.length-1; left<right; left++, right--) {
    // exchange the first and last
    int temp = b[left]; b[left]  = b[right]; b[right] = temp;
}
14
user29480

Guava a des méthodes pour convertir les tableaux primitifs en listes de types wrapper. La partie Nice est que ces listes sont des vues en direct, donc leurs opérations fonctionnent également sur les tableaux sous-jacents (similaire à Arrays.asList(), mais pour les primitives).

Quoi qu’il en soit, chacune de ces listes peut être passée à Collections.reverse():

int[] intArr = { 1, 2, 3, 4, 5 };
float[] floatArr = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
double[] doubleArr = { 1.0d, 2.0d, 3.0d, 4.0d, 5.0d };
byte[] byteArr = { 1, 2, 3, 4, 5 };
short[] shortArr = { 1, 2, 3, 4, 5 };
Collections.reverse(Ints.asList(intArr));
Collections.reverse(Floats.asList(floatArr));
Collections.reverse(Doubles.asList(doubleArr));
Collections.reverse(Bytes.asList(byteArr));
Collections.reverse(Shorts.asList(shortArr));
System.out.println(Arrays.toString(intArr));
System.out.println(Arrays.toString(floatArr));
System.out.println(Arrays.toString(doubleArr));
System.out.println(Arrays.toString(byteArr));
System.out.println(Arrays.toString(shortArr));

Sortie:

[5, 4, 3, 2, 1]
[5.0, 4.0, 3.0, 2.0, 1.0]
[5.0, 4.0, 3.0, 2.0, 1.0]
[5, 4, 3, 2, 1]
[5, 4, 3, 2, 1] 

8
Sean Patrick Floyd
double[] array = new double[1048576];

...

Par défaut, l'ordre est croissant 

Inverser l'ordre 

Arrays.sort(array,Collections.reverseOrder());
4
Piyush Doifode

Je pense que la solution la plus simple est toujours:

  1. Obtenir l'ordre naturel du tableau 
  2. Trouver le maximum dans ce tableau trié qui est alors le dernier élément 
  3. Utilisation d'un opérateur de boucle for avec décrément

Comme d'autres l'ont déjà dit: l'utilisation de toList est un effort supplémentaire, Arrays.sort (tableau, Collections.reverseOrder ()) ne fonctionne pas avec les primitives et l'utilisation d'un cadre supplémentaire semble trop compliquée lorsque tout ce dont vous avez besoin est déjà inbuild et par conséquent bien...

Exemple de code:

import Java.util.Arrays;

public class SimpleDescending {

    public static void main(String[] args) {

        // unsorted array
        int[] integerList = {55, 44, 33, 88, 99};

        // Getting the natural (ascending) order of the array
        Arrays.sort(integerList);

        // Getting the last item of the now sorted array (which represents the maximum, in other words: highest number)
        int max = integerList.length-1;

        // reversing the order with a simple for-loop
        System.out.println("Array in descending order:");
        for(int i=max; i>=0; i--) {
            System.out.println(integerList[i]);
        }

        // You could make the code even shorter skipping the variable max and use
        // "int i=integerList.length-1" instead of int "i=max" in the parentheses of the for-loop
    }
}
2
madfree

Vous ne pouvez pas utiliser les comparateurs pour trier les tableaux primitifs.

Votre meilleur choix est d'implémenter (ou d'emprunter une implémentation) un algorithme de tri qui soit approprié pour votre cas d'utilisation afin de trier le tableau (dans l'ordre inverse de votre cas).

1
Krystian Cybulski

Avec les types numériques, la négation des éléments avant et après le tri semble être une option. La vitesse relative à une seule inversion après tri dépend du cache, et si l'inverse n'est pas plus rapide, toute différence peut très bien être perdue dans le bruit.

1
greybeard
Before sorting the given array multiply each element by -1 

puis utilisez Arrays.sort (arr) puis multipliez à nouveau chaque élément par -1

for(int i=0;i<arr.length;i++)
    arr[i]=-arr[i];
Arrays.sort(arr);
for(int i=0;i<arr.length;i++)
    arr[i]=-arr[i];
1
Shravan Kumar

Votre implémentation (celle de la question) est plus rapide que, par exemple. envelopper avec toList() et en utilisant une méthode basée sur un comparateur. La mise en boîte automatique et l'utilisation de méthodes de comparaison ou d'objets Collections encapsulés sont beaucoup plus lentes que la simple inversion.

Bien sûr, vous pouvez écrire votre propre genre. Ce n'est peut-être pas la réponse que vous cherchez, mais notez que si votre commentaire sur "si le tableau est déjà assez bien trié" se produit fréquemment, vous feriez bien de choisir un algorithme de tri qui gère bien ce cas (par exemple, insertion) plutôt que d'utiliser Arrays.sort() (qui est mergesort, ou une insertion si le nombre d'éléments est petit).

1
Jason Cohen

Il y a eu une certaine confusion à propos de Arrays.asList dans les autres réponses. Si tu le dis

double[] arr = new double[]{6.0, 5.0, 11.0, 7.0};
List xs = Arrays.asList(arr);
System.out.println(xs.size());  // prints 1

alors vous aurez une liste avec 1 élément. La liste résultante a le tableau double [] comme son propre élément. Ce que vous voulez, c'est avoir un List<Double> dont les éléments sont ceux du double[].

Malheureusement, aucune solution impliquant des comparateurs ne fonctionnera pour un tableau primitif. Arrays.sort accepte uniquement un comparateur lorsqu'il reçoit un Object[]. Et pour les raisons décrites ci-dessus, Arrays.asList ne vous laissera pas faire une liste à partir des éléments de votre tableau.

Donc, malgré ma réponse précédente, à laquelle les commentaires ci-dessous font référence, il n'y a pas de meilleur moyen que d'inverser manuellement le tableau après le tri. Toute autre approche (telle que copier les éléments dans un Double[] et les trier en sens inverse puis les recopier) serait plus codante et plus lente.

1
Eli Courtwright

Si les performances sont importantes et que la liste est généralement déjà bien triée.

Le tri à bulles devrait être l’un des moyens les plus lents de trier, mais j’ai vu des cas où la meilleure performance était un simple tri à bulles bidirectionnel.

Donc, cela peut être l’un des rares cas où vous pouvez tirer profit du codage vous-même. Mais vous devez vraiment le faire correctement (assurez-vous au moins que quelqu'un d'autre confirme votre code, faites une preuve que cela fonctionne, etc.)

Comme quelqu'un l'a fait remarquer, il peut même être préférable de commencer par un tableau trié et de le conserver pendant que vous modifiez le contenu. Cela peut fonctionner encore mieux.

0
myplacedk

Voici ma solution, vous pouvez l’adapter à vos besoins. 

Comment ça marche? Il faut un tableau d'entiers comme arguments. Après cela, il créera un nouveau tableau qui contiendra les mêmes valeurs que le tableau des arguments. La raison de cela est de laisser le tableau d'origine intact.

Une fois que le nouveau tableau contient les données copiées, nous le trions en échangeant les valeurs jusqu'à ce que la condition if (newArr [i] <newArr [i + 1]) soit évaluée à false. Cela signifie que le tableau est trié par ordre décroissant.

Pour une explication approfondie, consultez mon article de blog ici .

public static int[] sortDescending(int[] array)
{
    int[] newArr = new int[array.length];

    for(int i = 0; i < array.length; i++)
    {
        newArr[i] = array[i];
    }

    boolean flag = true;
    int tempValue;

    while(flag) 
    {
        flag = false;

        for(int i = 0; i < newArr.length - 1; i++) 
        {
            if(newArr[i] < newArr[i+1])
            {
                tempValue = newArr[i];
                newArr[i] = newArr[i+1];
                newArr[i+1] = tempValue;
                flag = true;
            }
        }
    }

    return newArr;
}
0
Catalin Pit
double s =-1;
   double[] n = {111.5, 111.2, 110.5, 101.3, 101.9, 102.1, 115.2, 112.1};
   for(int i = n.length-1;i>=0;--i){
      int k = i-1;
      while(k >= 0){
          if(n[i]>n[k]){
              s = n[k];
              n[k] = n[i];
              n[i] = s;
          }
          k --;
      }
   }
   System.out.println(Arrays.toString(n));
 it gives time complexity O(n^2) but i hope its work
0
Shubham Gaur

Si vous utilisez Java8, convertissez simplement tableau en flux, triez et reconvertissez . Toutes les tâches peuvent être effectuées en une seule ligne, ce qui ne me semble pas si grave.

double[] nums = Arrays.stream(nums).boxed().
        .sorted((i1, i2) -> Double.compare(i2, i1))
        .mapToDouble(Double::doubleValue)
        .toArray();
0
tanghao

Je ne connais aucune installation de tri primitif dans l'API principale Java.

D'après mes expériences avec le langage de programmation D (une sorte de C sur les stéroïdes), j'ai constaté que l'algorithme de tri par fusion est sans doute l'algorithme de tri polyvalent le plus rapide (c'est ce que le langage D utilise sa fonction de tri).

0
Leo

Votre algorithme est correct. Mais nous pouvons faire l’optimisation de la manière suivante: Lors de l’inversion, vous pouvez essayer de conserver une autre variable afin de réduire le compteur arrière, car le calcul de array.length- (i + 1) peut prendre du temps! de sorte que chaque fois qu'il ne doit pas être attribué 

double temp;

for(int i=0,j=array.length-1; i < (array.length/2); i++, j--) {

     // swap the elements
     temp = array[i];
     array[i] = array[j];
     array[j] = temp;
}
0
lakshmanaraj

cela peut marcher pour les petits tableaux.

int getOrder (double num, double[] array){
    double[] b = new double[array.length];
    for (int i = 0; i < array.length; i++){
        b[i] = array[i];
    }
    Arrays.sort(b);
    for (int i = 0; i < b.length; i++){
        if ( num < b[i]) return i;
    }
    return b.length;
}

J'ai été surpris que le chargement initial du tableau b était nécessaire

double[] b = array; // makes b point to array. so beware!
0
user462990

Comprenez que c’est un très vieux billet, mais j’ai trébuché sur un problème similaire en essayant de trier les tableaux int primitifs, alors je publie ma solution. Suggestions/commentaires bienvenus -

int[] arr = {3,2,1,3};
List<Integer> list = new ArrayList<>();
Arrays.stream(arr).forEach(i -> list.add(i));
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
0
MJA