Quale elenco < Object > l'implementazione sarà la più veloce per un passaggio scrivere, leggere, quindi distruggere?

StackOverflow https://stackoverflow.com/questions/135314

  •  02-07-2019
  •  | 
  •  

Domanda

Qual è l'implementazione dell'elenco più veloce (in Java) in uno scenario in cui l'elenco verrà creato un elemento alla volta e in un secondo momento verrà letto un elemento alla volta? Le letture verranno eseguite con un iteratore e quindi l'elenco verrà distrutto.
So che la notazione Big O per get è O (1) e add è O (1) per un ArrayList, mentre LinkedList è O (n) per get e O (1) per add. L'iteratore si comporta con la stessa notazione Big O?

È stato utile?

Soluzione

Dipende in gran parte dal fatto che tu conosca la dimensione massima di ciascun elenco in anticipo.

Se lo fai, usa ArrayList ; sarà sicuramente più veloce.

Altrimenti, probabilmente dovrai creare un profilo. Mentre l'accesso a ArrayList è O (1), crearlo non è così semplice, a causa del ridimensionamento dinamico.

Un altro punto da considerare è che il compromesso spazio-temporale non è ben definito. Ogni oggetto Java ha un certo sovraccarico. Mentre un ArrayList può sprecare spazio sugli slot in eccesso, ogni slot ha solo 4 byte (o 8 su una JVM a 64 bit). Ogni elemento di un LinkedList è probabilmente di circa 50 byte (forse 100 in una JVM a 64 bit). Quindi è necessario disporre di alcuni slot sprecati in un ArrayList prima che un LinkedList vinca effettivamente il presunto vantaggio di spazio. Anche la località di riferimento è un fattore, e ArrayList è preferibile anche lì.

In pratica, uso quasi sempre ArrayList .

Altri suggerimenti

Primi pensieri:

  • Rifattorizza il tuo codice per non aver bisogno dell'elenco.
  • Semplifica i dati fino a un tipo di dati scalare, quindi usa: int[[
  • O semplicemente usa una matrice di qualunque oggetto tu abbia: Oggetto [] - John Gardner
  • Inizializza l'elenco a dimensione intera: new ArrayList (123);

Ovviamente, come menzionano tutti gli altri, eseguono test delle prestazioni, dimostrano che la tua nuova soluzione è un miglioramento.

L'iterazione attraverso un elenco collegato è O (1) per elemento.

Il tempo di esecuzione di Big O per ciascuna opzione è lo stesso. Probabilmente ArrayList sarà più veloce a causa della migliore localizzazione della memoria, ma dovresti misurarlo per sapere con certezza. Scegli quello che rende il codice più chiaro.

Nota che iterare attraverso un'istanza di LinkedList può essere O (n ^ 2) se fatto in modo ingenuo. In particolare:

List<Object> list = new LinkedList<Object>();
for (int i = 0; i < list.size(); i++) {
    list.get(i);
}

Questo è assolutamente orribile in termini di efficienza a causa del fatto che l'elenco deve essere attraversato fino a i due volte per ogni iterazione. Se usi LinkedList , assicurati di usare un Iterator o il migliorato di Java 5 per -loop:

for (Object o : list) {
    // ...
}

Il codice sopra è O (n), poiché l'elenco viene attraversato in modo statico sul posto.

Per evitare tutte le seccature di cui sopra, basta usare ArrayList . Non è sempre la scelta migliore (in particolare per quanto riguarda l'efficienza dello spazio), ma di solito è una scommessa sicura.

Suggerisco di confrontarlo. Una cosa è leggere l'API, ma fino a quando non la provi da solo, sarebbe accademico.

Dovrebbe essere abbastanza facile da testare, assicurati solo di fare operazioni significative, o che l'hotspot ti renderà super intelligente e ottimizzerà tutto su un NO-OP :)

Quasi sicuramente vuoi un ArrayList . Sia l'aggiunta che la lettura sono "tempo costante ammortizzato" (ovvero O (1)) come specificato nella documentazione (nota che questo è vero anche se l'elenco deve aumentare le sue dimensioni - è progettato in questo modo vedi http://java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html ). Se si conosce approssimativamente il numero di oggetti che verranno memorizzati, viene eliminato anche l'incremento delle dimensioni di ArrayList.

L'aggiunta alla fine di un elenco collegato è O (1), ma il moltiplicatore costante è più grande di ArrayList (poiché di solito si crea un oggetto nodo ogni volta). La lettura è praticamente identica a ArrayList se si utilizza un iteratore.

È una buona regola usare sempre la struttura più semplice che puoi, a meno che non ci sia una buona ragione per non farlo. Qui non esiste tale motivo.

La citazione esatta dalla documentazione per ArrayList è: " L'operazione di aggiunta viene eseguita in un tempo costante ammortizzato, cioè l'aggiunta di n elementi richiede O (n) tempo. Tutte le altre operazioni vengono eseguite in un tempo lineare (approssimativamente parlando). Il fattore costante è basso rispetto a quello per l'implementazione di LinkedList. & Quot;

Esiste una nuova implementazione dell'elenco chiamata GlueList che è più veloce di tutte le implementazioni dell'elenco classico.

Ho effettivamente iniziato a pensare che qualsiasi uso di strutture di dati con comportamento non deterministico, come ArrayList o HashMap, dovrebbe essere evitato, quindi direi di usare ArrayList solo se puoi limitarne le dimensioni; qualsiasi elenco illimitato usa LinkedList. Questo perché codifico principalmente sistemi con requisiti quasi in tempo reale.

Il problema principale è che qualsiasi allocazione di memoria (che potrebbe avvenire in modo casuale con qualsiasi operazione di aggiunta) potrebbe anche causare una garbage collection e qualsiasi garbage collection può farti perdere un target. Maggiore è l'allocazione, maggiore è la probabilità che si verifichi e ciò si complica anche se si utilizza il collector CMS. Il CMS non è compatto, quindi trovare spazio per un nuovo nodo elenco collegato sarà generalmente più semplice che trovare spazio per un nuovo array di 10.000 elementi.

Più rigoroso è il tuo approccio alla programmazione, più puoi avvicinarti al tempo reale con una JVM di serie. Ma la scelta di sole strutture di dati con comportamento deterministico è uno dei primi passi che dovresti fare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top