Wenn Sie nach einer Möglichkeit suchen, Elemente zu sortieren, aber auch effizient nach Index auf sie zugreifen zu können, können Sie Folgendes tun:
- Verwenden Sie eine Zufallszugriffsliste für die Speicherung (z. B.
ArrayList
)
- Sorgen Sie dafür, dass sie immer sortiert ist
Um dann ein Element hinzuzufügen oder zu entfernen, können Sie Collections.binarySearch
um den Einfüge-/Entfernungsindex zu erhalten. Da Ihre Liste einen zufälligen Zugriff implementiert, können Sie die Liste mit dem ermittelten Index effizient ändern.
例
/**
* @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);
}
}
(Eine ausführlichere Implementierung finden Sie in diese Antwort )
3 Stimmen
Hat stackoverflow.com/questions/416266/sorted-collection-in-java Ihnen helfen?
9 Stimmen
Welches Ergebnis erwarten Sie also, wenn Sie ein Element in der Mitte der Liste einfügen?
6 Stimmen
@bestsss Es wäre durchaus möglich, eine SortedList-Klasse zu haben, die nicht die java.util.List-Schnittstelle implementiert. Lesen Sie die Frage als eine Anfrage, warum es keine Datenstruktur gibt, die die gewünschte Funktionalität unterstützt. Lassen Sie sich nicht von unbedeutenden Details wie der Namensgebung ablenken.
0 Stimmen
@Alderath, die übliche Struktur dafür ist ein Baum (rot/schwarz, avl oder btree) mit zusätzlichen prev/next-Links zur Unterstützung der Ordnung. Ich verwende eine ähnliche Struktur rot/schwarz mit vorhergehenden/nächsten Links. Das ist allerdings eine ziemliche Nischenanwendung. Der Baum kann sowohl in geordneter als auch in eingefügter Reihenfolge durchlaufen werden, hat O(logn) find/contains aber get(int) ist O(n). Angesichts der Tatsache, dass es sich um eine Nischenanwendung handelt, würde ich annehmen, dass es den Entwicklern überlassen wurde, eine solche zu implementieren, wenn sie es brauchen.
6 Stimmen
Nicht die Beantwortung der Frage nach dem "Warum", sondern die einfachste Abhilfe für TreeSet ist es, einen Comparator zu verwenden, der niemals Null zurückgibt, z. B.
int diff = this.score - that.score;
return (diff == 0) ? 1 : diff;
Da es sich um einen stinkenden Hack handelt, würde ich dies als anonymes Konstruktorargument bereitstellen, anstatt Comparable zu implementieren.0 Stimmen
@earcam Wie soll man in so einem Set überhaupt etwas finden?
set.add(X); Y = set.get(X);
wird mit Sicherheit null zurückgeben.0 Stimmen
@user13784117, ich glaube, Sie haben das falsch verstanden und BTW
Set
implementiert nichtget
- Notiz; ich würde sagen, es ist ein Stinkmorchel - Der Punkt, auf den ich hinauswollte, ist, dass mein Vorschlag mehrere identische Werte in einerSet
und tut dies amadd
Vermeidung von Kosten fürCollections.sort(List)
. Dieser stinkende Hack versagt bei einer Reihe von Szenarien, wie zum Beispielcontains
- nicht für die Verwendung, sondern für die Konvertierung gedacht war; ich vermute stark, dass es schneller ist (in Bezug auf die Zeitkomplexität für riesig Sammlungen) zu verwenden und dann in eine Liste mit z.B. zu dumpen.ArrayList
Konstrukteur oderaddAll
(unwahrscheinlich, dass es besser für Big-O-Speicher ist)0 Stimmen
Mein Fehler bei
get
- aber ähnliche Argumente fürcontains
. Außerdem verstößt Ihr Komparator sicherlich gegen einen Vertrag, da compare(a,b) == 1 und compare(b,a) == 1, d.h. a > b und b > a. Ich würde zumindest für Konsistenz im Fall von a.equals(b) durch die Bestellung auf etwas anderes, vielleicht Vergleichen von System.identityHashCode-Werte.0 Stimmen
Ich habe diesen interessanten Hack ausprobiert, aber er hat auch den Nachteil, dass set.removeAll(set2) nichts entfernt, weil die removeAll-Methode irgendwie den Comparator verwendet.