Dans Java, il existe les interfaces SortedSet
et SortedMap
. Les deux font partie du framework standard de collections Java et fournissent un moyen trié d'accéder aux éléments.
Cependant, à ma connaissance, il n’existe pas de SortedList
en Java. Vous pouvez utiliser Java.util.Collections.sort()
pour trier une liste.
Une idée pourquoi c'est conçu comme ça?
Les itérateurs de liste garantissent avant tout que vous obteniez les éléments de la liste dans l'ordre interne de la liste (aka. ordre d'insertion ). Plus précisément, c'est dans l'ordre dans lequel vous avez inséré les éléments ou sur la façon dont vous avez manipulé la liste. Le tri peut être vu comme une manipulation de la structure de données et il existe plusieurs façons de trier la liste.
Je vais classer les chemins dans l'ordre de utilité comme je le vois personnellement:
Set
ou Bag
NOTE: J'ai mis cette option en haut car c'est ce que vous voulez normalement faire de toute façon.
Un ensemble trié trie automatiquement la collection lors de l'insertion , ce qui signifie qu'il effectue le tri pendant que vous ajoutez des éléments à la collection. Cela signifie également que vous n'avez pas besoin de le trier manuellement.
De plus, si vous êtes certain de ne pas avoir à vous soucier des éléments en double, vous pouvez utiliser plutôt TreeSet<T>
. Il implémente les interfaces SortedSet
et NavigableSet
et fonctionne comme vous le souhaiteriez probablement d'une liste:
_TreeSet<String> set = new TreeSet<String>();
set.add("lol");
set.add("cat");
// automatically sorts natural order when adding
for (String s : set) {
System.out.println(s);
}
// Prints out "cat" and "lol"
_
Si vous ne voulez pas l’ordre naturel, vous pouvez utiliser le paramètre constructeur qui prend un Comparator<T>
.
Alternativement, vous pouvez utiliser Multisets (également appelé Sacs ) , c'est un Set
qui autorise les éléments en double à la place et il existe une implémentation tierce de ceux-ci. Notamment dans les bibliothèques de Guava , il existe un TreeMultiset
, qui fonctionne beaucoup comme le TreeSet
.
Collections.sort()
Comme mentionné ci-dessus, le tri de List
s est une manipulation de la structure de données. Donc, pour les situations où vous avez besoin d'une "source de vérité" qui sera triée de différentes manières, le tri manuel est la voie à suivre.
Vous pouvez trier votre liste avec la méthode Java.util.Collections.sort()
. Voici un exemple de code sur la façon dont:
_List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");
Collections.sort(strings);
for (String s : strings) {
System.out.println(s);
}
// Prints out "cat" and "lol"
_
Un avantage évident est que vous pouvez utiliser Comparator
dans la méthode sort
. Java fournit également certaines implémentations pour Comparator
, telles que Collator
, ce qui est utile pour les chaînes de tri sensibles à la localisation. Voici un exemple:
_Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
_
Notez cependant que l’utilisation de la méthode sort
n’est pas conviviale dans les environnements concurrents, car l’instance de collection sera manipulée et vous devriez envisager plutôt d’utiliser des collections immuables. C’est quelque chose que Guava fournit dans la classe Ordering
et est simple:
_List<string> sorted = Ordering.natural().sortedCopy(strings);
_
Java.util.PriorityQueue
_Bien qu'il n'y ait pas de liste triée dans Java, il existe cependant une file d'attente triée qui fonctionnerait probablement aussi bien pour vous. C'est la classe Java.util.PriorityQueue
.
Nico Haase a lié dans les commentaires un question connexe qui répond également à cela.
Dans une collection triée , vous ne souhaitez probablement pas manipuler la structure de données interne. C'est pourquoi PriorityQueue n'implémente pas l'interface List (car cela vous donne un accès direct à ses éléments).
PriorityQueue
La classe PriorityQueue
implémente les interfaces _Iterable<E>
_ et _Collection<E>
_ afin qu’elle puisse être itérée comme d’habitude. Toutefois, il n'est pas garanti que l'itérateur renvoie les éléments dans l'ordre de tri. Au lieu de cela (comme Alderath le souligne dans les commentaires), vous devez poll()
la file d'attente jusqu'à ce qu'elle soit vide.
Notez que vous pouvez convertir une liste en file d'attente prioritaire via le constructeur prenant toute collection :
_List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");
PriorityQueue<String> sortedStrings = new PriorityQueue(strings);
while(!sortedStrings.isEmpty()) {
System.out.println(sortedStrings.poll());
}
// Prints out "cat" and "lol"
_
SortedList
REMARQUE: Vous ne devriez pas avoir à faire cela.
Vous pouvez écrire votre propre classe List qui trie chaque fois que vous ajoutez un nouvel élément. Cela peut être assez lourd en calcul en fonction de votre implémentation et est inutile , à moins que vous ne vouliez le faire en tant qu’exercice, pour deux raisons principales:
List<E>
_ car les méthodes add
doivent garantir que l'élément réside dans l'index spécifié par l'utilisateur.Cependant, si vous voulez le faire comme exercice, voici un exemple de code pour vous aider à démarrer, il utilise la classe abstraite AbstractList
:
_public class SortedList<E> extends AbstractList<E> {
private ArrayList<E> internalList = new ArrayList<E>();
// Note that add(E e) in AbstractList is calling this one
@Override
public void add(int position, E e) {
internalList.add(e);
Collections.sort(internalList, null);
}
@Override
public E get(int i) {
return internalList.get(i);
}
@Override
public int size() {
return internalList.size();
}
}
_
Notez que si vous n'avez pas remplacé les méthodes dont vous avez besoin, les implémentations par défaut de AbstractList
renverront UnsupportedOperationException
s.
Parce que le concept de liste est incompatible avec le concept de collection triée automatiquement. Le point essentiel d’une liste est qu’après avoir appelé list.add(7, elem)
, un appel à list.get(7)
renverra elem
. Avec une liste triée automatiquement, l'élément pourrait se retrouver dans une position arbitraire.
Étant donné que toutes les listes sont déjà "triées" en fonction de l'ordre auquel les éléments ont été ajoutés (ordre FIFO), vous pouvez les "ordonner" avec un autre ordre, y compris l'ordre naturel des éléments, en utilisant Java.util.Collections.sort()
.
MODIFIER:
Les listes en tant que structures de données sont basées sur ce qui est intéressant, c'est l'ordre dans lequel les éléments ont été insérés.
Les ensembles n'ont pas cette information.
Si vous souhaitez commander en ajoutant du temps, utilisez List
. Si vous souhaitez commander selon d'autres critères, utilisez SortedSet
.
Set et Map sont des structures de données non linéaires. La liste est une structure de données linéaire.
La structure de données arborescente SortedSet
et SortedMap
interfaces implémente TreeSet
et TreeMap
respectivement à l'aide de l'algorithme d'implémentation arbre rouge-noir utilisé. Donc, il s’assure qu’il n’ya pas d’éléments en double (ou de clés dans le cas de Map
).
List
maintient déjà une collection ordonnée et une structure de données basée sur un index, les arbres ne sont pas des structures de données basées sur un index.Tree
par définition, ne peut pas contenir de doublons.List
nous pouvons avoir des doublons, il n’ya donc pas de TreeList
(c’est-à-dire non SortedList
).Java.util.Collections.sort()
. Il trie la liste spécifiée en ordre croissant, en fonction de l'ordre naturel de ses éléments.SortedList
Bien que cela ait pris un certain temps, Java 8 a un List
trié. http://docs.Oracle.com/javase/8/javafx/api/javafx/collections/transformation/SortedList.html
Comme vous pouvez le constater dans les javadocs, il fait partie des collections JavaFX , destiné à fournir une vue triée sur une liste observable.
Mise à jour: notez qu'avec Java 11, le toolkit JavaFX s'est déplacé en dehors du JDK et constitue désormais une bibliothèque distincte. JavaFX 11 est disponible sous forme de SDK téléchargeable ou de MavenCentral. Voir https://openjfx.io
À compter d'avril 2015, pour tous les nouveaux arrivants, Android dispose désormais d'une classe SortedList dans la bibliothèque de support, conçue spécifiquement pour fonctionner avec RecyclerView
. Voici le blog post à ce sujet.
Un autre point concerne la complexité temporelle des opérations d’insertion. Pour une insertion de liste, on s’attend à une complexité de O (1). Mais cela ne pourrait pas être garanti avec une liste triée.
Et le point le plus important est que les listes ne supposent rien sur leurs éléments. Par exemple, vous pouvez créer des listes d'éléments qui n'implémentent pas equals
ou compare
.
Pensez-y comme ceci: l'interface List
dispose de méthodes telles que add(int index, E element)
, set(int index, E element)
. Le contrat stipule qu’une fois que vous avez ajouté un élément à la position X, vous le trouverez à moins d’ajouter ou de supprimer des éléments auparavant.
Si une implémentation de liste stockait des éléments dans un ordre autre que celui basé sur l'index, les méthodes de la liste ci-dessus n'auraient aucun sens.
La première ligne de l'API List indique qu'il s'agit d'une collection ordonnée (également appelée séquence). Si vous triez la liste, vous ne pouvez pas maintenir l'ordre, il n'y a donc pas de TreeList en Java.
Comme le dit l'API Java La liste s'est inspirée de Séquence et affiche les propriétés de la séquence http://en.wikipedia.org/wiki/Sequence_ (mathématiques )
Cela ne signifie pas que vous ne pouvez pas trier la liste, mais Java est strict selon sa définition et ne fournit pas de version triée des listes par défaut.
Pensez à utiliser indexed-tree-map . TreeSet du JDK amélioré qui donne accès à chaque élément et permet de rechercher l'index d'un élément sans itération ni liste cachée sous-jacente sauvegardant l'arborescence. L'algorithme est basé sur la mise à jour des poids des nœuds changeants chaque fois qu'il y a un changement.
Si vous recherchez un moyen de trier les éléments, mais pouvez également y accéder par index de manière efficace, vous pouvez procéder comme suit:
ArrayList
)Ensuite, pour ajouter ou supprimer un élément, vous pouvez utiliser Collections.binarySearch
pour obtenir l'index d'insertion/suppression. Étant donné que votre liste implémente un accès aléatoire, vous pouvez modifier efficacement la liste avec l'index déterminé.
Exemple:
_/**
* @deprecated
* Only for demonstration purposes. Implementation is incomplete and does not
* handle invalid arguments.
*/
@Deprecated
public class SortingList<E extends Comparable<E>> {
private ArrayList<E> delegate;
public SortingList() {
delegate = new ArrayList<>();
}
public void add(E e) {
int insertionIndex = Collections.binarySearch(delegate, e);
// < 0 if element is not in the list, see Collections.binarySearch
if (insertionIndex < 0) {
insertionIndex = -(insertionIndex + 1);
}
else {
// Insertion index is index of existing element, to add new element
// behind it increase index
insertionIndex++;
}
delegate.add(insertionIndex, e);
}
public void remove(E e) {
int index = Collections.binarySearch(delegate, e);
delegate.remove(index);
}
public E get(int index) {
return delegate.get(index);
}
}
_