Risposte:
Questo arriva molto tardi, ma c'è una classe nel JDK solo allo scopo di avere un elenco ordinato. È chiamato (un po 'fuori servizio con le altre Sorted*
interfacce) " java.util.PriorityQueue
". Può ordinare sia Comparable<?>
s che usando a Comparator
.
La differenza con un List
uso ordinato Collections.sort(...)
è che ciò manterrà sempre un ordine parziale, con prestazioni di inserimento O (log (n)), utilizzando una struttura di dati heap, mentre l'inserimento in un ordine ArrayList
sarà O (n) (cioè, usando la ricerca e lo spostamento binari).
Tuttavia, a differenza di a List
, PriorityQueue
non supporta l'accesso indicizzato ( get(5)
), l'unico modo per accedere agli elementi in un heap è di eliminarli, uno alla volta (da cui il nome PriorityQueue
).
TreeMap e TreeSet ti daranno un'iterazione sul contenuto in ordine ordinato. Oppure potresti usare un ArrayList e usare Collections.sort () per ordinarlo. Tutte quelle classi sono in java.util
Se desideri mantenere un elenco ordinato che modificherai frequentemente (ad esempio una struttura che, oltre a essere ordinata, consente i duplicati e i cui elementi possono essere referenziati in modo efficiente dall'indice), usa un ArrayList ma quando devi inserire un elemento , utilizza sempre Collections.binarySearch () per determinare l'indice a cui aggiungi un determinato elemento. Quest'ultimo metodo indica l'indice che è necessario inserire per mantenere l'elenco in ordine.
Utilizza la classe TreeMultiset di Google Guava . Guava ha una spettacolare API per le raccolte.
Un problema nel fornire un'implementazione dell'elenco che mantiene l'ordine ordinato è la promessa fatta nei metodi JavaDocs del add()
metodo.
List
aggiunge sempre alla fine.
Ci sono alcune opzioni Suggerirei TreeSet se non vuoi duplicati e gli oggetti che stai inserendo sono comparabili.
A tale scopo, puoi anche utilizzare i metodi statici della classe Collections.
Vedi Collezioni # sort (java.util.List) e TreeSet per maggiori informazioni.
Se vuoi solo ordinare un elenco, usa qualsiasi tipo di Elenco e usa Collections.sort () . Se vuoi assicurarti che gli elementi nell'elenco siano unici e sempre ordinati, usa un SortedSet .
Quello che ho fatto è implementare List con un'istanza interna con tutti i metodi delegati.
public class ContactList implements List<Contact>, Serializable {
private static final long serialVersionUID = -1862666454644475565L;
private final List<Contact> list;
public ContactList() {
super();
this.list = new ArrayList<Contact>();
}
public ContactList(List<Contact> list) {
super();
//copy and order list
List<Contact>aux= new ArrayList(list);
Collections.sort(aux);
this.list = aux;
}
public void clear() {
list.clear();
}
public boolean contains(Object object) {
return list.contains(object);
}
Dopo, ho implementato un nuovo metodo "putOrdered" che si inserisce nella posizione corretta se l'elemento non esiste o lo sostituisce nel caso esistesse.
public void putOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
list.add(index, contact);
}else{
list.set(index, contact);
}
}
Se si desidera consentire elementi ripetuti, implementare invece addOrdered (o entrambi).
public void addOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
}
list.add(index, contact);
}
Se si desidera evitare inserimenti, è anche possibile generare un'eccezione di operazione non supportata sui metodi "aggiungi" e "imposta".
public boolean add(Contact object) {
throw new UnsupportedOperationException("Use putOrdered instead");
}
... e devi anche stare attento con i metodi ListIterator perché potrebbero modificare il tuo elenco interno. In questo caso è possibile restituire una copia dell'elenco interno o nuovamente generare un'eccezione.
public ListIterator<Contact> listIterator() {
return (new ArrayList<Contact>(list)).listIterator();
}
List
contratto. Forse sarebbe meglio solo implementare Collection
. E se ContactList
è ordinato, allora contains()
può essere implementato usando binarySearch
anche per essere più efficiente.
Il modo più efficace per implementare un elenco ordinato come desiderato sarebbe quello di implementare uno skiplist indicizzabile come qui: Wikipedia: skiplist indicizzabile . Consentirebbe di avere inserimenti / rimozioni in O (log (n)) e consentirebbe di avere accesso indicizzato allo stesso tempo. E consentirebbe anche duplicati.
Skiplist è una struttura dati piuttosto interessante e, direi, sottovalutata. Purtroppo non esiste un'implementazione skiplist indicizzata nella libreria di base Java, ma è possibile utilizzare una delle implementazioni open source o implementarla da soli. Esistono implementazioni regolari di Skiplist come ConcurrentSkipListSet e ConcurrentSkipListMap
TreeSet non funzionerebbe perché non consente duplicati e non fornisce il metodo per recuperare l'elemento in una posizione specifica. PriorityQueue non funzionerebbe perché non consente il recupero di elementi in una posizione specifica, che è un requisito di base per un elenco. Penso che sia necessario implementare il proprio algoritmo per mantenere un elenco ordinato in Java con tempo di inserimento O (logn), a meno che non siano necessari duplicati. Forse una soluzione potrebbe essere l'utilizzo di una TreeMap in cui la chiave è una sottoclasse dell'elemento che sovrascrive il metodo equals in modo da consentire i duplicati.
Puoi provare a risolvere queste attività con LambdaJ se stai utilizzando versioni precedenti a java 8. Puoi trovarlo qui: http://code.google.com/p/lambdaj/
Ecco un esempio:
Ordina Iterativo
List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});
Ordina con LambdaJ
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());
Certo, avere questo tipo di bellezza influisce sulla performance (in media 2 volte), ma riesci a trovare un codice più leggibile?
Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
//or
persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
-(p1.getAge().compareTo(p2.getAge()))
Il problema con PriorityQueue è che viene eseguito il backup da un semplice array e la logica che ottiene gli elementi in ordine viene eseguita dalla cosa "coda [2 * n + 1] e coda [2 * (n + 1)]". Funziona alla grande se si estrae semplicemente dalla testa, ma lo rende inutile se si sta cercando di richiamare il .toArray su di esso ad un certo punto.
Risolvo questo problema utilizzando com.google.common.collect.TreeMultimap, ma fornisco un comparatore personalizzato per i valori, racchiuso in un ordinamento, che non restituisce mai 0.
ex. per doppio:
private static final Ordering<Double> NoEqualOrder = Ordering.from(new Comparator<Double>() {
@Override
public int compare(Double d1, Double d2)
{
if (d1 < d2) {
return -1;
}
else {
return 1;
}
}
});
In questo modo ottengo i valori in ordine quando chiamo .toArray () e ho anche dei duplicati.
Quello che vuoi è un albero di ricerca binario. Mantiene l'ordine ordinato offrendo al contempo l'accesso logaritmico per ricerche, rimozioni e inserimenti (a meno che tu non abbia un albero degenerato - quindi è lineare). È abbastanza facile da implementare e puoi persino farlo implementare l'interfaccia Elenco, ma l'accesso all'indice diventa complicato.
Il secondo approccio consiste nell'avere un ArrayList e quindi un'implementazione di ordinamento a bolle. Poiché si sta inserendo o rimuovendo un elemento alla volta, i tempi di accesso per inserimenti e rimozioni sono lineari. Le ricerche sono logaritmiche e costanti di accesso all'indice (i tempi possono essere diversi per LinkedList). L'unico codice che ti serve è 5, forse 6 righe di ordinamento a bolle.
Puoi usare Arraylist e Treemap, poiché hai detto che vuoi anche valori ripetuti, quindi non puoi usare TreeSet, anche se è ordinato, ma devi definire un comparatore.
Per Set puoi usare TreeSet. TreeSet ordina i suoi elementi sulla base di un ordinamento naturale o di qualsiasi ordinamento passato al Comparabile per quel particolare oggetto. Per la mappa usa TreeMap. TreeMap fornisce l'ordinamento tramite chiavi. Per aggiungere un oggetto come chiave alla TreeMap quella classe dovrebbe implementare un'interfaccia comparabile che a sua volta impone di implementare il metodo compare to () che contiene la definizione del criterio di ordinamento. http://techmastertutorial.in/java-collection-impl.html
Utilizzare il metodo sort () per ordinare l'elenco come di seguito:
List list = new ArrayList();
//add elements to the list
Comparator comparator = new SomeComparator();
Collections.sort(list, comparator);
Per riferimento consultare il link: http://tutorials.jenkov.com/java-collections/sorting.html
Utilizzare ciò TreeSet
che fornisce elementi in ordine ordinato. O utilizzare Collection.sort()
per l'ordinamento esterno con Comparator()
.
import java.util.TreeSet;
public class Ass3 {
TreeSet<String>str=new TreeSet<String>();
str.add("dog");
str.add("doonkey");
str.add("rat");
str.add("rabbit");
str.add("elephant");
System.out.println(str);
}
con Java 8 Comparator, se vogliamo ordinare l'elenco allora Ecco le 10 città più popolate al mondo e vogliamo ordinarlo per nome, come riportato da Time. Osaka, Giappone. ... Città del Messico, Messico. ... Pechino, Cina. ... San Paolo, Brasile. ... Mumbai, India. ... Shanghai, Cina. ... Delhi, India. ... Tokyo, Giappone.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortCityList {
/*
* Here are the 10 most populated cities in the world and we want to sort it by
* name, as reported by Time. Osaka, Japan. ... Mexico City, Mexico. ...
* Beijing, China. ... São Paulo, Brazil. ... Mumbai, India. ... Shanghai,
* China. ... Delhi, India. ... Tokyo, Japan.
*/
public static void main(String[] args) {
List<String> cities = Arrays.asList("Osaka", "Mexico City", "São Paulo", "Mumbai", "Shanghai", "Delhi",
"Tokyo");
System.out.println("Before Sorting List is:-");
System.out.println(cities);
System.out.println("--------------------------------");
System.out.println("After Use of List sort(String.CASE_INSENSITIVE_ORDER) & Sorting List is:-");
cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
System.out.println("--------------------------------");
System.out.println("After Use of List sort(Comparator.naturalOrder()) & Sorting List is:-");
cities.sort(Comparator.naturalOrder());
System.out.println(cities);
}
}
Ordinamento di un ArrayList in base a criteri definiti dall'utente.
Classe del modello
class Student
{
int rollno;
String name, address;
public Student(int rollno, String name, String address)
{
this.rollno = rollno;
this.name = name;
this.address = address;
}
public String toString()
{
return this.rollno + " " + this.name + " " + this.address;
}
}
Classe di classificazione
class Sortbyroll implements Comparator<Student>
{
public int compare(Student a, Student b)
{
return a.rollno - b.rollno;
}
}
Classe principale
class Main
{
public static void main (String[] args)
{
ArrayList<Student> ar = new ArrayList<Student>();
ar.add(new Student(111, "bbbb", "london"));
ar.add(new Student(131, "aaaa", "nyc"));
ar.add(new Student(121, "cccc", "jaipur"));
System.out.println("Unsorted");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
Collections.sort(ar, new Sortbyroll());
System.out.println("\nSorted by rollno");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
}
}
Produzione
Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
Sorted by rollno
111 bbbb london
121 cccc jaipur
131 aaaa nyc