Je cherche une bonne liste triée pour Java. Googling autour de me donner quelques conseils sur l'utilisation de TreeSet/TreeMap. Mais ces composants sont le manque d'une chose: l'accès aléatoire à un élément de l'ensemble. Par exemple, je veux accéder au nième élément du jeu trié, mais avec TreeSet, je dois parcourir d'autres n-1 avant de pouvoir y arriver. Ce serait un gaspillage puisque j'aurais plusieurs milliers d'éléments dans mon set.
Fondamentalement, je recherche quelque chose de similaire à une liste triée dans .NET, avec la possibilité d’ajouter rapidement un élément, de supprimer rapidement un élément et d’avoir un accès aléatoire à n’importe quel élément de la liste.
Ce type de liste triée est-il implémenté quelque part? Merci.
édité
Mon intérêt pour SortedList découle de ces problèmes: je dois maintenir une liste de plusieurs milliers d'objets (et peut atteindre plusieurs centaines de milliers). Ces objets seront persistés dans la base de données. Je veux sélectionner au hasard quelques dizaines d'éléments dans la liste. J'ai donc essayé de conserver une liste séparée en mémoire contenant les clés primaires (numéros longs) de tous les objets. J'ai besoin d'ajouter/supprimer des clés de la liste lorsque l'objet est ajouté/supprimé de la base de données. J'utilise actuellement ArrayList mais je crains que ArrayList ne lui convienne pas si le nombre d'enregistrements augmente. (Imaginez que vous deviez parcourir plusieurs centaines de milliers d'éléments chaque fois qu'un objet est supprimé de la base de données). De retour à l'époque où je faisais de la programmation .NET, j'utilisais une liste triée (List est une classe .NET qui, une fois la propriété Sorted définie sur true, maintiendra l'ordre de son élément et fournira une recherche binaire qui aidera à supprimer/insérer des éléments. très rapide). J'espère que je pourrai trouver quelque chose de similaire chez Java BCL, mais malheureusement, je n'ai pas trouvé de correspondance parfaite.
Il semble que vous souhaitiez une structure de liste avec une suppression très rapide et un accès aléatoire par index (et non par clé). Un ArrayList
vous donne le dernier et un HashMap
ou TreeMap
vous donne le premier.
Il existe une structure dans Apache Commons Collections qui peut être ce que vous recherchez, la TreeList . JavaDoc spécifie qu'il est optimisé pour une insertion et une suppression rapides à tout index de la liste. Si vous avez également besoin de génériques, cela ne vous aidera pas.
C'est l'implémentation SortedList que j'utilise. Peut-être que cela aide avec votre problème:
import Java.util.Collection;
import Java.util.Collections;
import Java.util.Comparator;
import Java.util.LinkedList;
/**
* This class is a List implementation which sorts the elements using the
* comparator specified when constructing a new instance.
*
* @param <T>
*/
public class SortedList<T> extends ArrayList<T> {
/**
* Needed for serialization.
*/
private static final long serialVersionUID = 1L;
/**
* Comparator used to sort the list.
*/
private Comparator<? super T> comparator = null;
/**
* Construct a new instance with the list elements sorted in their
* {@link Java.lang.Comparable} natural ordering.
*/
public SortedList() {
}
/**
* Construct a new instance using the given comparator.
*
* @param comparator
*/
public SortedList(Comparator<? super T> comparator) {
this.comparator = comparator;
}
/**
* Construct a new instance containing the elements of the specified
* collection with the list elements sorted in their
* {@link Java.lang.Comparable} natural ordering.
*
* @param collection
*/
public SortedList(Collection<? extends T> collection) {
addAll(collection);
}
/**
* Construct a new instance containing the elements of the specified
* collection with the list elements sorted using the given comparator.
*
* @param collection
* @param comparator
*/
public SortedList(Collection<? extends T> collection, Comparator<? super T> comparator) {
this(comparator);
addAll(collection);
}
/**
* Add a new entry to the list. The insertion point is calculated using the
* comparator.
*
* @param paramT
* @return <code>true</code> if this collection changed as a result of the call.
*/
@Override
public boolean add(T paramT) {
int initialSize = this.size();
// Retrieves the position of an existing, equal element or the
// insertion position for new elements (negative).
int insertionPoint = Collections.binarySearch(this, paramT, comparator);
super.add((insertionPoint > -1) ? insertionPoint : (-insertionPoint) - 1, paramT);
return (this.size() != initialSize);
}
/**
* Adds all elements in the specified collection to the list. Each element
* will be inserted at the correct position to keep the list sorted.
*
* @param paramCollection
* @return <code>true</code> if this collection changed as a result of the call.
*/
@Override
public boolean addAll(Collection<? extends T> paramCollection) {
boolean result = false;
if (paramCollection.size() > 4) {
result = super.addAll(paramCollection);
Collections.sort(this, comparator);
}
else {
for (T paramT:paramCollection) {
result |= add(paramT);
}
}
return result;
}
/**
* Check, if this list contains the given Element. This is faster than the
* {@link #contains(Object)} method, since it is based on binary search.
*
* @param paramT
* @return <code>true</code>, if the element is contained in this list;
* <code>false</code>, otherwise.
*/
public boolean containsElement(T paramT) {
return (Collections.binarySearch(this, paramT, comparator) > -1);
}
/**
* @return The comparator used for sorting this list.
*/
public Comparator<? super T> getComparator() {
return comparator;
}
/**
* Assign a new comparator and sort the list using this new comparator.
*
* @param comparator
*/
public void setComparator(Comparator<? super T> comparator) {
this.comparator = comparator;
Collections.sort(this, comparator);
}
}
Cette solution est très flexible et utilise les fonctions Java existantes:
Quelques notes:
Java.util.ArrayList
. Utilisation Collections.synchronizedList
si vous en avez besoin (reportez-vous à la documentation de Java pour Java.util.ArrayList
pour plus de détails).Java.util.LinkedList
. Pour de meilleures performances, en particulier pour trouver le point d'insertion (commentaire de Logan) et pour obtenir plus rapidement des opérations ( https://dzone.com/articles/arraylist-vs-linkedlist-vs ), cela a été changé en Java.util.ArrayList
.Phuong:
import Java.util.ArrayList;
import Java.util.Collections;
import Java.util.List;
import Java.util.Random;
public class test
{
public static void main(String[] args)
{
List<Integer> nums = new ArrayList<Integer>();
Random Rand = new Random();
for( int i = 0; i < 40000; i++ )
{
nums.add( Rand.nextInt(Integer.MAX_VALUE) );
}
long start = System.nanoTime();
Collections.sort(nums);
long end = System.nanoTime();
System.out.println((end-start)/1e9);
}
}
Puisque vous avez rarement besoin de trier, selon votre énoncé du problème, ceci est probablement plus efficace que nécessaire.
SortedList décorator from Java Les bibliothèques Happy peuvent être utilisées pour décorer TreeList à partir de Collections Apache. Cela produirait une nouvelle liste dont les performances sont comparables à TreeSet. https://sourceforge.net/ p/happy-guy/wiki/Trié% 20Liste /
Selon la façon dont vous utilisez la liste, il peut être intéressant d’utiliser un TreeSet, puis d’utiliser la méthode toArray () à la fin. J'avais un cas où j'avais besoin d'une liste triée, et j'ai trouvé que TreeSet + toArray () était beaucoup plus rapide que d'ajouter à un tableau et de fusionner le tri à la fin.
En règle générale, vous ne pouvez pas avoir une recherche constante dans le temps et enregistrer les suppressions/insertions dans le temps, mais si vous êtes satisfait de la recherche dans le journal, vous pouvez utiliser une liste SortedList.
Je ne sais pas si vous allez faire confiance à mon codage, mais j'ai récemment écrit une implémentation SortedList en Java, que vous pouvez télécharger à partir de http://www.scottlogic.co.uk/2010/12/sorted_lists_in_Java/ . Cette implémentation vous permet de rechercher le ième élément de la liste en temps de journalisation.
Pour tester l'efficacité de Konrad Holl, nous avons fait une rapide comparaison avec ce que je pensais être la façon la plus lente de le faire:
package util.collections;
import Java.util.ArrayList;
import Java.util.Collection;
import Java.util.Collections;
import Java.util.Iterator;
import Java.util.List;
import Java.util.ListIterator;
/**
*
* @author Earl Bosch
* @param <E> Comparable Element
*
*/
public class SortedList<E extends Comparable> implements List<E> {
/**
* The list of elements
*/
private final List<E> list = new ArrayList();
public E first() {
return list.get(0);
}
public E last() {
return list.get(list.size() - 1);
}
public E mid() {
return list.get(list.size() >>> 1);
}
@Override
public void clear() {
list.clear();
}
@Override
public boolean add(E e) {
list.add(e);
Collections.sort(list);
return true;
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object obj) {
return list.contains((E) obj);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] arg0) {
return list.toArray(arg0);
}
@Override
public boolean remove(Object obj) {
return list.remove((E) obj);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
list.addAll(c);
Collections.sort(list);
return true;
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void add(int index, E element) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public E remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object obj) {
return list.indexOf((E) obj);
}
@Override
public int lastIndexOf(Object obj) {
return list.lastIndexOf((E) obj);
}
@Override
public ListIterator<E> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("Not supported.");
}
}
Il s'avère que c'est environ deux fois plus vite! Je pense que c'est à cause de SortedLinkList slow get - ce qui en fait un bon choix pour une liste.
Temps comparés pour une même liste aléatoire:
SembleList est très rapide ...
GlazedLists a une très, très bonne implémentation de liste triée
Qu'en est-il d'utiliser un HashMap
? L’insertion, la suppression et la récupération sont toutes des opérations O(1). Si vous souhaitez tout trier, vous pouvez extraire une liste des valeurs de la carte et les exécuter dans un journal O (n n) algorithme de tri.
modifier
Une recherche rapide a trouvé LinkedHashMap , qui maintient l'ordre d'insertion de vos clés. Ce n'est pas une solution exacte, mais c'est assez proche.