web-dev-qa-db-fra.com

Insertion dans une liste chaînée triée Java

J'ai ce code ci-dessous où je suis en train d'insérer un nouvel entier dans une LinkedList triée d'intes mais je ne pense pas que ce soit la manière "correcte" de faire les choses car je sais qu'il existe des listes isolées avec un pointeur sur la valeur suivante et des listes doublement liées pointeurs vers la valeur suivante et précédente. J'ai essayé d'utiliser des nœuds pour implémenter le cas ci-dessous mais Java importe cette importation org.w3c.dom.Node (modèle d'objet document), donc je suis resté bloqué.

Cas d'insertion

  1. Insérer dans un tableau vide
  2. Si la valeur à insérer est inférieure à tout, insérez au début.
  3. Si la valeur à insérer est supérieure à tout, insérez le dernier.
  4. Peut être compris entre si la valeur est inférieure à/supérieure à certaines valeurs dans LL.

    import Java.util.*;
    
    public class MainLinkedList {
    public static void main(String[] args) {
    LinkedList<Integer> llist = new LinkedList<Integer>();
    
    llist.add(10);
    llist.add(30);
    llist.add(50);
    llist.add(60);
    llist.add(90);
    llist.add(1000);
    System.out.println("Old LinkedList " + llist);
    
    //WHat if you want to insert 70 in a sorted LinkedList
    LinkedList<Integer> newllist = insertSortedLL(llist, 70);
    System.out.println("New LinkedList " + newllist);
    }
    
    public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
    
        llist.add(value);
        Collections.sort(llist);
        return llist;
    
    }
    

    }

7
cloudviz

Cela pourrait parfaitement servir votre objectif:

Utilisez ce code:

import Java.util.*;

public class MainLinkedList {
    private static LinkedList<Integer> llist;

    public static void main(String[] args) {
        llist = new LinkedList<Integer>();

        addValue(60);
        addValue(30);
        addValue(10);
        addValue(-5);
        addValue(1000);
        addValue(50);
        addValue(60);
        addValue(90);
        addValue(1000);
        addValue(0);
        addValue(100);
        addValue(-1000);
        System.out.println("Linked List is: " + llist);

    }

    private static void addValue(int val) {

        if (llist.size() == 0) {
            llist.add(val);
        } else if (llist.get(0) > val) {
            llist.add(0, val);
        } else if (llist.get(llist.size() - 1) < val) {
            llist.add(llist.size(), val);
        } else {
            int i = 0;
            while (llist.get(i) < val) {
                i++;
            }
            llist.add(i, val);
        }

    }

}

Cette méthode gérera l’insertion dans la liste de manière triée sans utiliser Collections.sort(list)

6
Master

Si nous utilisons listIterator, la complexité pour obtenir get sera O (1). 

public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {

    private static final long serialVersionUID = 1L;


    public boolean orderedAdd(T element) {      
        ListIterator<T> itr = listIterator();
        while(true) {
            if (itr.hasNext() == false) {
                itr.add(element);
                return(true);
            }

            T elementInList = itr.next();
            if (elementInList.compareTo(element) > 0) {
                itr.previous();
                itr.add(element);
                System.out.println("Adding");
                return(true);
            }
        }
    }
}
16
Amruth

@Atrakeur

"trier toute la liste à chaque fois que vous ajoutez un nouvel élément n'est pas efficace"

C'est vrai, mais si vous avez besoin que la liste soit toujours dans un état trié, c'est vraiment la seule option.

"Le meilleur moyen est d'insérer l'élément directement là où il doit être (à sa position correcte). Pour cela, vous pouvez mettre en boucle toutes les positions pour trouver où ce numéro appartient"

C'est exactement ce que fait l'exemple de code.

"ou utilisez Collections.binarySearch pour laisser cet algorithme de recherche hautement optimisé faire ce travail pour vous"

La recherche binaire est efficace, mais uniquement pour les listes à accès aléatoire. Vous pouvez donc utiliser une liste de tableaux au lieu d'une liste chaînée, mais vous devez ensuite gérer les copies en mémoire à mesure que la liste s'allonge. Vous allez également utiliser plus de mémoire que nécessaire si la capacité de la liste est supérieure au nombre d'éléments (ce qui est assez commun).

Ainsi, la structure/approche de données à adopter dépendra beaucoup de vos besoins en matière de stockage et d’accès.

[edit] En fait, l'exemple de code pose un problème: il entraîne plusieurs analyses de la liste lors de la mise en boucle. 

int i = 0;
while (llist.get(i) < val) {
    i++;
}
llist.add(i, val);

L'appel à obtenir (i) va parcourir la liste une fois pour arriver à la ième position. Ensuite, l'appel à ajouter (i, val) le traverse à nouveau. Donc, ce sera très lent.

Une meilleure approche consisterait à utiliser un ListIterator pour parcourir la liste et effectuer une insertion. Cette interface définit une méthode add () qui peut être utilisée pour insérer l’élément à la position actuelle.

1
Greg Brown

Consultez com.google.common.collect.TreeMultiset .

Il s’agit bien d’un ensemble trié qui autorise plusieurs instances de la même valeur.

C'est un bon compromis pour ce que vous essayez de faire. L'insertion est moins chère que ArrayList, mais vous obtenez tout de même les avantages de la recherche par binaire/arborescence.

1
DanJ

Vous pouvez le faire simplement en complexité log (N) time. Pas besoin de parcourir toutes les valeurs. vous pouvez utiliser la recherche binaire pour ajouter de la valeur à la liste chaînée triée. Ajoutez simplement la valeur à la position de la limite supérieure de cette fonction. Vérifiez le code ... vous comprendrez peut-être mieux.

    public static int ubound(LinkedList<Integer> ln, int x) {
        int l = 0;
        int h = ln.size();
        while (l < h) {
            int mid = (l + h) / 2;
            if (ln.get(mid) <= x) l = mid + 1;
            else h = mid;
        }
        return l;
    }

    public void solve() 
    {
        LinkedList<Integer> ln = new LinkedList<>();
        ln.add(4);
        ln.add(6);
        ln.add(ubound(ln, 5), 5);
        out.println(ln);

    }

Sortie: [4, 5, 6]

pour en savoir plus sur la recherche binaire, rendez-vous sur: https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/

0
NIKUNJ KHOKHAR

Vous devez trouver où insérer les données en connaissant les critères de commande.

La méthode simple consiste à rechercher par force brute la position d'insertion (parcourir la liste, recherche binaire ...).

Une autre méthode, si vous connaissez la nature de vos données, consiste à estimer une position d’insertion afin de réduire le nombre de vérifications. Par exemple, si vous insérez «Zorro» et que la liste est ordonnée par ordre alphabétique, vous devez commencer au dos de la liste ... ou estimer l'emplacement de votre lettre (probablement vers la fin). Ceci peut également fonctionner pour chiffres si vous savez d'où ils viennent et comment ils sont distribués. C'est ce qu'on appelle la recherche par interpolation: http://en.wikipedia.org/wiki/Interpolation_search

Pensez également à l'insertion par lot: Si vous insérez rapidement un grand nombre de données, vous pouvez envisager d'effectuer plusieurs insertions en une seule fois et de ne les trier qu'une fois par la suite.

0
Christophe Roussy

La liste chaînée n'est pas la meilleure implémentation pour SortedList

De plus, trier toute la liste à chaque fois que vous ajoutez un nouvel élément n'est pas efficace. La meilleure méthode consiste à insérer l'élément directement là où il doit être (à sa position correcte). Pour Cela vous permet de mettre en boucle toutes les positions pour trouver où ce numéro appartient, puis de l'insérer ou d'utiliser Collections.binarySearch pour laisser cet algorithme de recherche hautement optimisé effectuer ce travail à votre place.

BinarySearch renvoie l'index de l'objet si celui-ci est trouvé dans la liste (vous pouvez rechercher les doublons ici si nécessaire) ou (- (point d'insertion) - 1) si l'objet ne figure pas déjà dans la liste (et le point d'insertion est l'index où l'objet doit être placé pour maintenir l'ordre)

0
Atrakeur