5

Sto provando a costruire una struttura dati generica che deve contenere chiavi e valori e, allo stesso tempo, tenere traccia dell'indice in cui le chiavi e i valori sono stati inseriti come un arraylist proprio in una complessità di O (log n) o Di meno.È possibile creare una mappa con proprietà ArrayList con log (n) complessità?

Ho provato a risolvere una soluzione a questo problema e ho creato varie TreeMaps con Integer - index e valuse e vise-versa, e lo stesso con le chiavi.

Giusto per rendere più chiaro, l'indice simboleggia l'ordine di inserimento da parte dell'utente. quindi se avessi 3 elementi allora il loro indice è 0 1 2 e se l'elemento 0 è stato cancellato allora ho bisogno di premere 1 a 0 e 2 a 1 e un nuovo elemento sarebbe aggiunto con l'indice 2.

Il mio problema è quando Rimuovo una chiave e il suo valore, se voglio inserire la chiave successiva e il valore nell'indice corretto devo assicurarmi che tutti i vecchi siano stati ripristinati di 1. Non so come farlo e non cadere in O (n) complessità.

Il mio obiettivo è utilizzare le strutture dati esistenti e mescolarle per ottenere questo risultato, per favore date un'occhiata ai metodi che ho implementato come ho bisogno di quelli.

Aggiungo il mio codice per riferimento, qualsiasi aiuto sarebbe molto apprezzato.

Grazie

Tom

import java.util.Collection; 
import java.util.HashMap; 
import java.util.TreeMap; 
import java.util.Map; 

public class SuperStruct<K,V> 
{ 
    private Map<K,V> mInternalKeyToValueMap;//all the keys and their values 
    private Map<Integer,V> mIndexToValueMap;//index's for values according to the entrance order to 
    private Map<V,Integer> mValueToIndexMap;//values and their index's 
    private Map<Integer,K> mIndexToKeyMap;//index's and their keys according to entrance order 
    private Map<K,Integer> mKeyToIndexMap;//keys and their index's 
    private int mNextIndex;//index for the data structure according to the order data was received by user 

    public SuperStruct(){ 
     mInternalKeyToValueMap = new TreeMap<K,V>(); 
     mIndexToValueMap = new TreeMap<Integer,V>(); 
     mValueToIndexMap = new TreeMap <V,Integer>(); 
     mIndexToKeyMap = new TreeMap <Integer, K>(); 
     mKeyToIndexMap = new TreeMap <K,Integer>();  
    } 
    public boolean containsKey(Object key) { 
     boolean containable = mInternalKeyToValueMap.containsKey(key); 
     return containable; 
    } 

    public boolean containsValue(Object value) { 
     boolean containable = mValueToIndexMap.containsKey(value); 
     return containable; 
    } 

    public V get(Object key) { 
     if(mInternalKeyToValueMap.containsKey(key)){ 
      V value = mInternalKeyToValueMap.get(key); 
      return value; 
     } 
     return null; 
    } 



    public Collection<K> keySet() { 

     return mInternalKeyToValueMap.keySet(); 
    } 
    /** 
    * This method is putting the key and the value in the main TreeMap "mInternalKeyToValueMap", while on the mean time updating 4 other TreeMaps 
    * with data regarding to the index in which data was received from the user. 
    * all in all this method runs in complexity of 6*(O(log n)) that sums down to O(log n) cause constants don't calculate over the whole 
    * Complexity calculation 
    * In case that a key already had a mapping to it and we overwrite the value we will run in complexity of 11*(O(log n)) which still sums down to O(log n) 
    * cause constants don't calculate over the whole 
    */ 

    public V put(K key, V value) { 
     if(mValueToIndexMap.containsKey(value))//preventing duplications of value 
      return value; 
      if(mInternalKeyToValueMap.containsKey(key)){//when a key already exist in system and we want to overwrite its value 
       int indexToDelete = mKeyToIndexMap.get(key);//we get the index of the value we over-write 
       V value1 = mIndexToValueMap.get(indexToDelete);//using this index we get the value 
       mValueToIndexMap.remove(value1);//we remove the value and its index 
       mIndexToValueMap.remove(indexToDelete);//we remove the index and its value 
      } 
      mInternalKeyToValueMap.put(key, value);//putting the new value for the key in the main TreeMap 
      mValueToIndexMap.put(value, mNextIndex);//populating the TreeMap of values and their index's - the order we received them from the user 
      mIndexToValueMap.put(mNextIndex, value);//This TreeMap holds the index's for each value according to the order of insertion by user 
      mIndexToKeyMap.put(mNextIndex, key);//This TreeMap holds the index's for each key according to the order of insertion by user 
      mKeyToIndexMap.put(key,mNextIndex);//populating the TreeMap of keys and their index's - the order we received them from the user 
      ++mNextIndex;//advancing the index which mark the insertion order of arguments to structure 
      return null; 

    } 


    public V remove(Object key) { 
     if(mInternalKeyToValueMap.containsKey(key)==true && (mInternalKeyToValueMap.get(key)!=null)) 
     { 
      V value = mInternalKeyToValueMap.get(key); 
      mInternalKeyToValueMap.remove(key);//removing map for the value 
      int mIndexToRemoveValue = mValueToIndexMap.get(value);//getting the right index to remove the value 
      mIndexToValueMap.remove(mIndexToRemoveValue);//vacating the value for this index 
      mIndexToKeyMap.remove(mIndexToRemoveValue);//vacating the key for this index 
      mKeyToIndexMap.remove(key);//removing a key and index in the keyToIndex Map 
      mValueToIndexMap.remove(value);//removing a key and index in the ValueToIndex Map 
      return value; 

     } 
     return null; 
    } 


    public Collection<V> values() {  
     return mInternalKeyToValueMap.values(); 
    } 

    public Collection<V> getStrcutureSorted(){ 
     return mValueToIndexMap.keySet(); 
    } 

    public V getValueByIndex(int index){//return the index in which the value sits in, if not present null 
     V value = mIndexToValueMap.get(index); 
      return value; 
    } 

    public Integer getIndexByKey(K key){ 
     Integer returnable = mKeyToIndexMap.get(key); 
     if(returnable == null) 
      return -1; 
     return returnable; 


    } 
    public K getKeyByIndex(int index){ 
     return mIndexToKeyMap.get(index); 
    } 
    } 
+0

https://stackoverflow.com/questions/44170832/access-tree-with-ordinal-index –

risposta

2

Questo è un enigma interessante. Sembra che dovrebbe essere possibile, ma i dettagli sono sfuggenti. Il problema è nell'operazione di aggiornamento dell'indice dopo un'eliminazione. Se gli indici sono memorizzati in un nodo ad albero, ad esempio, in media gli indici n/2 dovranno essere modificati dopo un'operazione di cancellazione, che rovina la proprietà O (log n) che si sta cercando.

Se si memorizzano oggetti contemporaneamente in un albero e in un oggetto ArrayList, si ha ancora il problema di localizzare un oggetto in ArrayList, che non riesco a far funzionare in modo diretto nel tempo inferiore a O (n) . Forse c'è qualche variazione su un ArrayList, forse una costruzione personalizzata, ma sembra molto lavoro.

Invece, suggerisco di considerare un albero rosso-nero o un albero bilanciato simile con la modifica annotata allo Red-black tree access by ordinal index: per ogni nodo dell'albero, memorizzare anche il conteggio dei nodi nella sottostruttura con il nodo dato come radice. Durante le operazioni di inserimento ed eliminazione, è necessario aggiornare il conteggio di tutti i nodi interessati da un'operazione di rotazione. Ciò può ancora essere fatto in tempo O (log n), ma è complicato.

Quindi le ricerche binarie per l'elemento kth più piccolo (o più grande) verranno eseguite anche nel tempo O (log n), come al solito, con il solito algoritmo ricorsivo.

Ecco alcuni altri riferimenti per la tecnica: http://www.cs.usfca.edu/~galles/cs673/lecture/lecture8.pdf, http://fdatamining.blogspot.ca/2011/09/functional-red-black-tree-with-dynamic.html, http://en.wikipedia.org/wiki/Order_statistic_tree. Questo dovrebbe iniziare.

Aggiornamento: dettagli di implementazione

Cosa dovrete fare è creare due alberi. Uno potrebbe essere un ordinario albero bilanciato (come un albero rosso-nero) per contenere riferimenti ai tuoi oggetti con coppie chiave/valore. Puoi cercare sulla chiave e ottenere il valore corrispondente in O (log n); inserimento e cancellazione sarebbero anche O (log n). Inoltre, i nodi in questo primo albero potrebbero contenere riferimenti a nodi nel secondo albero (sotto).

Il secondo albero manterrà anche i riferimenti ai nodi nel primo albero, ma sarebbe un albero di statistica degli ordini come nella discussione precedente. Gli inserimenti posizionerebbero sempre nuovi oggetti all'estremità destra dell'albero.

Un'operazione di inserimento in questa struttura dati sarebbe un normale inserto nel primo albero per chiave, un inserto nel lato destro dell'albero delle statistiche dell'ordine e i riferimenti in ciascun nodo inserito verrebbero aggiornati in modo da puntare all'appropriato posizione nell'altro albero.

Un'operazione di ricerca può essere eseguita sul primo albero per una data chiave in O (log n), che restituirebbe il valore appropriato e, seguendo un riferimento all'altro albero, potrebbe essere utilizzato per trovare la "statistica ordine" "del nodo nel secondo albero in O (log n) tempo attraversando l'albero alla radice ed eseguendo un semplice calcolo.

Un'operazione di ricerca può essere eseguita sul secondo albero in O (log n) tempo per la posizione k in coda, restituendo un riferimento al secondo albero, che può essere dereferenziato per ottenere la coppia chiave/valore associata.

La cancellazione in uno degli alberi sarebbe preceduta dal deferenziare il riferimento all'altro albero, quindi la cancellazione del nodo nel primo albero, seguita dalla cancellazione del nodo corrispondente nell'altro albero, entrambe le operazioni O (log n).

Penso sia così. Tutto può essere fatto in tempo O (log n). C'è un costo minore nello spazio per il secondo albero, ma contiene solo riferimenti; lo spazio è ancora O (n).

Funziona?

+0

Non sono sicuro che funzionerà nel caso dell'OP. Il suo concetto di "indice" si basa sulla chiave utilizzata per strutturare l'albero. OP vuole che "index" faccia riferimento all'ordine di inserimento, che non è correlato alla chiave. – ishnid

+1

Sì, hai ragione. Ma ho avuto l'intuizione che questo potrebbe aiutare. Penso che lo faccia, ma la risposta è più elaborata della mia risposta originale. Pubblicherò un aggiornamento tra qualche minuto. –

+0

Sì, penso che il tuo post aggiornato funzionerà. Ho postato la mia risposta poco prima di andare a letto, e stamattina ho giocato con un'implementazione. Ho trovato qualcosa di molto simile a quello che proponi. Penso che l'unica modifica sia che ho una singola classe Entry, che memorizza la chiave, il valore e i riferimenti ai nodi appropriati in ogni albero. – ishnid

Problemi correlati