web-dev-qa-db-fra.com

Comment trier certains éléments et en laisser d'autres en Java?

Je cherche à trier certains éléments dans un tableau mais à en exclure d'autres.

Pour un exemple simple, un tableau contenant des entiers, je voudrais trier les nombres impairs mais laisser le même où ils se trouvent.

Jusqu'à présent, j'ai les éléments suivants:

public class MyClass {
    public static void main(String args[]) {
        int temp;
        int array[] = {5, 3, 2, 8, 1, 4};

        int[] sortedArray = new int[array.length];
        for (int j = 0; j < array.length - 1; j++) {
            for (int x = 0; x < array.length - 1; x++) {
                if (array[x] > array[x + 1] && array[x] % 2 != 0 && array[x + 1] % 2 !=0) {
                    temp = array[x];
                    array[x] = array[x + 1];
                    array[x + 1] = temp;
                    sortedArray = array;
                }
            }
        }
        for (int i: sortedArray) {
            System.out.println(i);
        }

    }
}

Tableau entier donné: 5, 3, 2, 8, 1, 4

Sortie du code: 3, 5, 2, 8, 1, 4

Résultats attendus: 1, 3, 2, 8, 5, 4

Impossible de comprendre la logique nécessaire pour le scénario dans lequel un nombre impair inférieur vient avant un nombre pair dans le tableau d'origine.

19
BIGJOHN

Une solution simple de force brute:

  • itérer le tableau d'entrée et récupérer tous les nombres impairs
  • collecter les nombres impairs dans un nouveau tableau plus petit
  • trier ce tableau
  • parcourez maintenant le tableau initial à nouveau: chaque fois que vous trouvez un nombre impair, vous sélectionnez l'entrée "next" dans le tableau impair

Ce qui précède n’est probablement pas la solution optimale (à cause du gaspillage de mémoire sur un second tableau, et du temps passé à copier les valeurs), mais cela devrait être super facile écrire et tester. 

Théoriquement, vous pouvez aussi le faire "en place". Signification: vous pouvez créer une classe qui entoure un tableau d'int - mais qui fournit un view à ses utilisateurs qui ne montre qu'un tableau des impairs impairs.

Exemple d'implémentation (merci à Daniel Foerster ):

public static int[] sortFiltered(int[] src, IntPredicate predicate) {
  int[] filtered = IntStream.of(src).filter(predicate).sorted().toArray();
  int[] dst = new int[src.length];
  for (int i = 0, j = 0; i < src.length; i++) {
    dst[i] = predicate.test(src[i]) ? filtered[j++] : src[i];
  }
  return dst;
}

Invocation avec un filtre pour les nombres impairs:

sortFiltered(array, (n) -> n % 2 != 0);

Comme vous pouvez le constater, cet algorithme ne dépend pas d’un type particulier de prédicat, ni de tableau/liste. Mais comme il utilise IntStream et Lambda Expressions , il nécessite Java 8 ou plus récent.

20
GhostCat

Vous avez mis en place une sorte de type de bulle (pas très efficace). Le problème avec votre code est qu'il exclut les deux éléments du tri, même si un seul est pair. En vous appuyant sur votre solution, vous pouvez ajuster votre code comme suit:

public class MyClass {
    public static void main(String args[]) {
        int temp;
        //odd numbers are sorted, even number stay where they are
        //Expected output: 1, 3, 2, 8, 5, 4
        int array[] = {5, 3, 2, 8, 1, 4};
        int[] sortedArray = new int[array.length];
        for (int j = 0; j < array.length - 1; j++) {
            for (int x = 0; x < array.length - 1; x++) {

                while(array[x] % 2 == 0 && x < array.length-1){
                    x++;
                }

                int y = x+1;

                if(y < array.length) {
                    while (array[y] % 2 == 0 && y < array.length - 1) {
                        y++;
                    }

                    if (array[x] > array[y] && array[y] % 2 == 1 && array[x] % 2 == 1) {
                        temp = array[x];
                        array[x] = array[y];
                        array[y] = temp;
                        sortedArray = array;
                    }
                }
            }
        }
        for (int i: sortedArray) {
            System.out.println(i);
        }
    }
}

Cela se traduit par:

1 3 2 8 5 4

1
Ueli Hofstetter

Votre code est une sorte de bulle mais avec cela vous ne faites que comparer chaque voisin direct. Voici un code de travail qui utilise 2 pour les boucles et fonctionne à la place. Il ne compare pas nécessairement les voisins directs, mais il recherche plutôt le prochain nombre impair à comparer avec le nombre impair actuel.

De plus, il y a eu une petite erreur avec la copie de votre array à sortedArray parce que vous faites ceci: sortedArray = array; dans votre boucle qui copie simplement la référence du tableau. Dans le code de travail ci-dessous, j'ai pris votre solution et l'ai modifiée. Je viens également de copier le tableau avant le début du tri afin que le tableau source ne soit pas modifié.

La boucle for interne commence par l'index de la boucle for externe plus 1. De plus, la boucle interne boucle jusqu'à un élément avant la fin. Dans le pire des cas, il aura besoin des opérations n-1 * n/2 = n^2/2 - n/2 qui mènent àO(n^2)comme le type de bulle normal.

Code et exemple de travail sur ideone :

public class MyClass
{
   public static void main(String args[])
   {
      int array[] = {5, 3, 2, 8, 1, 4};

      int[] sortedArray = new int[array.length];
      System.arraycopy(array, 0, sortedArray, 0, array.length);

      for (int i = 0; i < sortedArray.length - 1; i++)
      {
         /* is current odd, if so search next odd */
         if (sortedArray[i] % 2 != 0)
         {
            /* search for next odd and compare */
            for (int j = i + 1; j < sortedArray.length; j++)
            {
               if ((sortedArray[j] % 2 != 0) && (sortedArray[i] > sortedArray[j]))
               {
                  int temp = sortedArray[i];
                  sortedArray[i] = sortedArray[j];
                  sortedArray[j] = temp;
               }
            }
         }
      }
      for (int i: sortedArray)
      {
         System.out.println(i);
      }
   }
}

Sortie:

1
3
2
8
5
4

1
Andre Kampling

Étant donné le tableau non trié A: Créez 2 occurrences vectorielles O et E contenant les éléments pairs et impairs du tableau, dans l'ordre. (Tous les exemples de code sont pseudocode. "Jusqu'à" dans une boucle signifie que le côté droit de la limite n'est pas incluse, selon la numérotation liée à un tableau standard)

for i in 0 up to A.length: if A[i] is odd, append it to O, else append it to E

Créez un tableau séparé de booléens B comme suit:

for i in 0 up to A.length: if A[i] is odd, B[i] = true, else B[i] = false

Triez O dans un nouveau vecteur S (par ordre croissant). Je recommande d'utiliser le tri intégré de Java car il sera beaucoup plus efficace que le tri à bulle des autres réponses que vous utilisez.

S = ascendingSort(O)

Définit une opération pop qui renvoie le premier élément d'un vecteur, puis le supprime du vecteur.

Créez un nouveau vecteur R vide, puis implémentez le pseudocode suivant:

for i in 0 up to B.length: if B[i] is true, then append pop(S) to R, else append pop(E) to R.

Renvoie R comme résultat.


Pourquoi ça marche:

Commencez par séparer les chances du nombre d'événements afin de masquer ceux-ci du type, en maintenant leur ordre d'origine (vecteurs O et E). Conservez les positions (vecteur B) des éléments impairs/pairs du tableau d'origine.

Triez les chances (vecteur S).

Après le tri, assemblez les notes et triez les cotes dans l'ordre, en conservant l'ordre initial des notes. Lire le vecteur B en prenant les éléments dans l'ordre des vecteurs E et S. Ceci maintient l'ordre des événements car ils ont été placés dans le vecteur E dans l'ordre, puis ils sont remis dans l'ordre.

1
user1258361