2012-01-02 11 views
6

È necessario recuperare una raccolta di stringhe in cui gli elementi inseriti devono essere ordinati e anche non duplicati, tramite indice.Come creare un set ordinato con un accesso casuale O (1) per indice

  • posso usare TreeSet che elimina i duplicati e ordina tutto in ordine ma non in grado di recuperare attraverso indice. per il recupero tramite l'indice , posso creare gli elementi ArrayList e addAll, ma questo addAll richiede molto tempo.

o

  • posso usare un ArrayList, inserto necessario quindi rimuovere duplicati da un altro metodo, quindi utilizzando Collections.sort metodo per ordinare gli elementi.

Ma la cosa è, tutti questi richiedono tempo, non v'è alcun diritto-modo per raggiungere questo obiettivo, una collezione -sorted, non duplicate, con O (1) accesso casuale in base all'indice.

+2

Perché non si utilizza semplicemente un TreeSet e quindi si costruisce il SortedList con il costruttore SortedList (Collection <>)? SortedSet <> implementa Collection <> – fge

+1

Qualsiasi cosa tu faccia su un computer "prendi [s] tempo". Hai misurato questa particolare parte del tuo programma e hai scoperto che ci vuole un * periodo di tempo * inaccettabile? E se sì, cosa è "irragionevole" nel tuo caso? Ore, secondi o millisecondi? – kdgregory

+1

33082 record hanno preso 710 ms per il metodo addAll, dove i record possono estendersi fino a lakh, che richiede molto tempo giusto? Anche costruire il Treeset ha richiesto lo stesso 704ms, ma questo è permissibile, ma questo addAll prende tutto il tempo necessario per costruire, quindi ho pensato di poter tagliare questo costo e far funzionare il mio programma più velocemente. – cypronmaya

risposta

0

Non sono sicuro, testate la mappa? Voglio dire usare la stringa come chiave in una TreeMap.

In una mappa, è un O (1) per una chiave per trovare la sua posizione (un valore hash). E KeySet di TreeMap restituirà un insieme ordinato di chiavi in ​​TreeMap.

Questo soddisfa le vostre esigenze?

+2

Solo HashMap ha la semantica * O (1) *; TreeMap è * O (logN) * ​​per il recupero. – kdgregory

2

È possibile utilizzare la seconda idea:

posso usare ArrayList, inserto richiesto e poi rimuovere i duplicati da qualche altro metodo, quindi utilizzando il metodo Collections.sort per ordinare gli elementi.

ma invece di rimuovere i duplicati prima del genere, è possibile ordinare il ArrayList prima, poi tutti i duplicati sono in posizioni consecutive e possono essere rimossi in una sola passata successivamente.

A questo punto, entrambi i metodi hanno la stessa complessità complessiva: O (N * logN) e vale la pena notare che non è possibile ottenere una sequenza ordinata più veloce di questa comunque (senza ulteriore sfruttamento di una certa conoscenza dei valori).

+0

Puoi quantificare come potrebbe essere più veloce della prima opzione? Perché se lo decidi per algoritmo, scoprirai che stai eseguendo una copia * O (logN) * ​​e una copia * O (N) * in entrambi i casi. – kdgregory

+0

@kdgregory: Nella versione TreeSet si eseguono inserimenti N * O (logN) (o controlli duplicati) quindi O (N * logN) totale. Nella seconda versione stai facendo un O (N * logN) sort + O (N) traversal che è ancora O (N * logN). La seconda versione ha tuttavia il vantaggio aggiuntivo di accedere per indice, che è anche ciò che l'OP desiderava. – Tudor

+0

Scusa, ma quello che intendevo è che entrambe le opzioni prima e seconda richiedono tempo, non sto quantificando entrambe qui ... – cypronmaya

0

Se si sono tenuti alla List all'inizio e alla fine dell'operazione, convertirlo in un Set con il costruttore "copia" (o addAll) dopo gli elementi sono popolati, questo elimina i duplicati. Se lo converti in un TreeSet con uno Comparator appropriato, lo risolve persino. Di conseguenza, è possibile convertirlo nuovamente in List.

+0

Ciò richiede molto tempo ... – cypronmaya

+0

Prima di aver creato un set di alberi in O (nlogn) (albero rosso-nero) piuttosto che convertirlo in un elenco in O (n), la prima conversione è necessaria solo se devo iniziare con una lista. – zeller

1

Le prestazioni dipendono dalla frequenza con cui gli elementi vengono aggiunti e dalla frequenza con cui saranno accessibili per indice.

Posso usare TreeSet che rimuove i duplicati e ordina tutto in ordine ma non può recuperare tramite indice. per il recupero tramite indice, posso creare arraylist e aggiungere elementi ad esso, ma questo addAll richiede molto tempo.

List.addAll (yourSortedSet) avrà atleast O (n) tempo e spazio ogni volta che si desidera accedere al SortedSet come elenco (cioè dall'indice di elemento).

Posso usare ArrayList, inserire richiesto e quindi rimuovere i duplicati con un altro metodo, quindi utilizzando il metodo Collections.sort per ordinare gli elementi.

l'ordinamento richiederà sicuramente più di O (n) ogni volta che si desidera una visualizzazione ordinata dell'elenco.

Un'altra soluzione

Se non si recuperano con l'indice molto spesso, allora è più efficiente di farlo nel modo seguente:

Basta memorizzare String s in un SortedSet può essere estendere TreeSet e fornire/implementare il proprio metodo get(int i) in cui si itera fino all'elemento ith e si restituisce quell'elemento. Nel peggiore dei casi, questo sarà O (n) altrimenti molto meno. In questo modo sei non eseguendo alcun confronto o conversione o copia di stringhe. Non è necessario spazio extra.

+0

La memorizzazione delle stringhe in un TreeSet richiede O (N * logN) perché si hanno N stringhe e O (logN) per trovare la sua posizione mediante confronti successivi. – Tudor

0

Utilizzare un Hashmap per risolvere il problema con valori univoci e ordinarlo con alcuni metodi di ordinamento. Se è possibile utilizzare quicksort.

+0

Si noti che (1) 'HashMap' non conserva alcun ordine; (2) Non è possibile ordinare un 'HashMap'. Quicksort può essere di una certa rilevanza qui, ma è piuttosto limitato: non appena inizi ad aggiornare una collezione, quasi tutti gli altri algoritmi funzioneranno meglio. – alf

+0

Okay, puoi usare un LinkedMap questo estensioni di Map può essere utilizzato per la determinazione di valori univoci e può essere ordinato mediante puntatori di ciascun elemento della mappa – pesoklp13

+0

Non c'è 'LinkedMap' in' java.util'.'LinkedHashMap' non è adatto per qualsiasi algoritmo di ordinamento. Potresti controllare prima i tuoi consigli? – alf

0

Forse usando LinkedList (che richiede meno memoria dell'array) con il metodo booleano che determina se quell'elemento è già presente nell'elenco e un algoritmo QuickSort. Tutte le strutture di java devono essere in qualche modo ordinate e protette dai duplicati, quindi tutto richiede tempo ...

+2

1) LinkedList richiede * più * memoria di ArrayList. 2) Determinare se un elemento è già in una lista è un'operazione * O (N) * su una lista collegata; è un'operazione * O (N) * su una ArrayList ordinata, ma l'ordinamento di ArrayList sarà * O (NlogN) * ​​al meglio; 3) Java fornisce metodi di ordinamento incorporati nel JDK e utilizza MergeSort per gli elenchi; 4) Non riesco nemmeno a capire la frase che inizia con "Tutte le strutture in Java". – kdgregory

2

Il vero problema qui è che il PO non ci ha detto il vero problema. Quindi molte persone indovinano le strutture dati e postano le risposte senza pensarci veramente.

Il vero sintomo, come l'OP ha dichiarato in un commento, è che ci vuole 700ms a mettere le corde in un TreeSet, e un altro 700 ms per copiare che TreeSet in un ArrayList. Ovviamente, il programma non sta facendo quello che l'OP pensa che sia, dato che la copia dovrebbe richiedere al massimo qualche microsecondo. In effetti, il programma seguente, eseguito sul mio vecchio Thinkpad, impiega solo 360 ms per creare 100.000 stringhe casuali, metterle in un TreeSet e copiare TreeSet in una ArrayList.

Detto questo, l'OP ha selezionato una risposta (due volte). Forse se/quando l'OP decide di pensare al vero problema, questo esempio di SSCCE sarà utile. È CW, quindi sentitevi liberi di modificarlo.


import java.lang.management.ManagementFactory; 
import java.lang.management.ThreadMXBean; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import java.util.TreeSet; 


public class Microbench 
{ 
    public static void main(String[] argv) 
    throws Exception 
    {   
     ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); 
     long start = threadBean.getCurrentThreadCpuTime(); 
     executeTest(); 
     long finish = threadBean.getCurrentThreadCpuTime(); 
     double elapsed = (finish - start)/1000000.0; 
     System.out.println(String.format("elapsed time = %7.3f ms", elapsed)); 
    } 


    private static List<String> executeTest() 
    { 
     String[] data = generateRandomStrings(100000); 

     TreeSet<String> set = new TreeSet<String>(); 
     for (String s : data) 
      set.add(s); 

     return new ArrayList<String>(set); 
    } 


    private static String[] generateRandomStrings(int size) 
    { 
     Random rnd = new Random(); 
     String[] result = new String[size]; 
     for (int ii = 0 ; ii < size ; ii++) 
      result[ii] = String.valueOf(rnd.nextLong()); 
     return result; 
    } 
} 
0

ci sono due modi per farlo LinkedMap uso dove ogni elemento nella mappa è unico o rendere la propria estensione della lista e metodo di sostituzione aggiungere

import java.util.ArrayList; 

public class MyList<V> extends ArrayList<V>{ 

    private static final long serialVersionUID = 5847609794342633994L; 

    public boolean add(V object) { 
     //make each object unique 
     if(contains(object)){ 
      return false; 
     } 

     //you can make here ordering and after save it at position 

     //your ordering here 

     //using extended method add 
     super.add(yourposition,object); 
    } 
} 
0

ho anche affrontato il problema della trovare elementi in una determinata posizione in una TreeMap. Ho migliorato l'albero con pesi che consentono di accedere agli elementi per indice e trovare elementi negli indici. Il progetto si chiama indexed-tree-map http://code.google.com/p/indexed-tree-map/. L'implementazione per trovare l'indice di un elemento o elemento in un indice in una mappa ordinata non è basata su iterazione lineare ma su una ricerca binaria ad albero. L'aggiornamento dei pesi dell'albero si basa anche sulla salita verticale dell'albero. Quindi nessuna iterazione lineare.

Problemi correlati