Se ogni set mantiene un registro di quali altri set esistono e hai un totale di s>0 set, puoi facilmente trasformare qualsiasi struttura di dati per una raccolta ( ad es . Alberi di ricerca binari, ecc. ) In uno in cui puoi recuperare un elemento dell'intersezione di due insiemi nel tempo O(logs) .
Ogni set dovrebbe avere un identificatore univoco rispetto a un set totalmente ordinato. Se assegni esplicitamente i tuoi insiemi S1,S2,… l'identificatore potrebbe essere solo l'indice.
È necessario implementare un "registro" degli insiemi; una struttura di dati che mantiene una raccolta di tutti i set che sono stati definiti. Il registro deve essere implementato come una struttura di dati dell'albero di ricerca, per consentire un facile recupero ( ad esempio se si desidera eliminare il set) e l'attraversamento lineare dei set.
Ogni set Sj mantiene anche un "indice" di ciascuno degli altri set - non una copia di essi, ma piuttosto una struttura di dati che viene indicizzata dalle etichette degli altri set. Questo indice verrà utilizzato per mantenere, per ogni set Sk , un albero di ricerca binario di tutti gli elementi di Sj∩Sk . (I due set Sj e Sk condividono una copia di quell'albero di ricerca.)
Inizializzazione
L'inizializzazione di un set consiste in operazioni per inizializzare l'albero dei suoi elementi, operazioni mentre si inizializza (copiando dal registro) l'indice per l'insieme e operazioni mentre attraversi il registro per aggiungere negli indici di ciascuno degli altri insiemi . Nell'indice di , creiamo alberi di ricerca che rappresentano per gli altri insiemi ; copiamo lo stesso puntatore per l'indice di .O ( 1 ) O ( s ) T O ( s log s ) T S j T T ∩ S j = ∅T=∅O(1)O(s)TO(slogs)TSjTT∩Sj=∅S jSjSj
Aggiunta di un elemento a un setT
L'aggiunta di alcuni all'insieme richiede , dove. Testiamo anche l'appartenenza di in ciascuno degli altri set , che richiede tempo doveè la dimensione dell'universo (o del set più grande ) e è il numero di set nel registro. Per ogni insieme tale che , anche inserto nell'indice per il set . Per ciascuno di questi setT O ( log n T ) n T = | T | x S 1 , S 2 , ... O ( log n S 1 + log n S 2 + ⋯ ) ⊆ O ( s log n ) , n = | V | S j s S j x ∈ S jx∈VTO(lognT)nT=|T|xS1,S2,…
O(lognS1+lognS2+⋯)⊆O(slogn),
n=|V|SjsSjx∈SjS j ∩ T S j O ( log s + log n T ) S j T x S j ∩ T S 1 , S 2 , … O ( s log s + s log n T ) S j V s ≪ n O ( s log n )xSj∩TSj, ciò richiede tempo, per cercare nell'indice di e per inserire in ; in tutti i set questo richiede tempo . Se supponiamo che il numero di insiemi sia molto inferiore alla dimensione dell'universo (ovvero, se supponiamo ), il tempo totale per l'inserimento dell'elemento è quindi .
O(logs+lognT)SjTxSj∩TS1,S2,…O(slogs+slognT)SjVs≪nO(slogn)
Se non si consente duplicati in serie, siamo in grado di risparmiare tempo nel caso in cui già rinunciando alla prova di appartenenza e inserimenti per le altre serie . "Inserimento" nel caso in cui sia già presente, richiede solo tempo .T x O ( log n T )x∈STxO(lognT)
Test di intersezione
L'indice di ciascun set viene mantenuto precisamente per consentire una rapida valutazione dell'intersezione tra due set e . Per un set , semplicemente controllando il suo indice per il set , non possiamo solo determinare in tempo se interseca o meno , ma possiamo anche recuperare un albero binario contenente l'intero set .S k S j S k O ( log s ) S j S k S j ∩ S kSjSkSjSkO(logs)SjSkSj∩Sk
Rimozione dell'elemento
Per eliminare un elemento da un set , lo rimuoviamo non solo dall'albero di ricerca per stesso, ma da ciascuna delle intersezioni per gli insiemi nel suo indice. Questo richiede tempo , dove.T T S j ∩ T S j O ( s log n T ) n T = | T |xTTSj∩TSjO(slognT)nT=|T|
Imposta cancellazione
A causa del sovraccarico di ricerca nel registro, se si hanno molti set, potrebbe essere preferibile eliminare i set quando non sono più necessari. Attraversando l'intero registro, possiamo eliminare dall'indice di tutti gli altri insiemi nel tempo , dominato dal costo di eliminazione dell'albero di ricerca che rappresenta per ciascuno degli altri insiemi , dove.S j O ( s n T ) S j ∩ T S j n T = | T |SSjO(snT)Sj∩TSjnT=|T|
Osservazioni
Se si prevede di implementare solo un numero costante di insiemi, i tempi di esecuzione sopra indicati si riducono a:
inizializzazione:O(1)
inserimento elemento:O(logn)
test di intersezione (e recupero dell'intersezione):O(1)
rimozione elemento:O(lognT)
imposta la cancellazione:O(nS)
dove è la dimensione del set più grande nel registro eper il set cui si sta operando.nnT=|T|T
Se prevedete di avere set , dove è il vostro universo, potreste aver bisogno di una struttura dati diversa se volete che queste operazioni operino in un tempo sub-lineare. Tuttavia, se si hanno coppie di insiemi di cui si sa che non si proveranno mai intersezioni, è possibile ridurre le dimensioni dell'indice per gli insiemi (non includendo insiemi di cui si verificherà l'intersezione) o utilizzare più di un registro ( uno per ogni raccolta di insiemi di cui potresti verificare l'intersezione). In effetti, un registro è utile solo se si desidera un controllo centralizzato per garantire che ogni coppia di insiemi abbia una registrazione reciproca nell'indice: può essere pratico in alcuni casi, all'inizializzazione di una serie , semplicemente registrare l' annuncio hocO(|V|)VSogni nuovo set negli indici degli altri set cui sei interessato all'intersezione conTS