Credo che la soluzione di Airza si sta dirigendo verso una buona direzione, ma dal momento che l'ordinamento non è ciò che si vuole, ed è più costoso è possibile effettuare le seguenti operazioni da combinare con l'approccio di angelatlarge:
prendere un pezzo C che si adatta nella memoria della taglia M/2.
Prendi il pezzo C i
Scorrere i e patate ogni elemento in un hash-table. Se l'elemento esiste già, sai che è un duplicato e puoi contrassegnarlo come duplicato. (aggiungi il suo indice in una matrice o qualcosa del genere).
Ottieni il blocco successivo C i + 1 e verifica se esiste già una chiave nella tabella hash. Se esiste un elemento, contrassegnarlo per la cancellazione.
Ripetere con tutti i pezzi fino a quando si sa che non contengono duplicati dal pezzo C i
Ripetere i passaggi 1,2 con pezzo C i + 1
eliminati tutti gli elementi contrassegnato per la cancellazione (potrebbe essere fatto durante, qualunque sia più appropriato, potrebbe essere più costoso eliminarne uno alla volta se devi spostare tutto il resto).
Viene eseguito in O ((N/M) * | C |), dove | C | è la dimensione del blocco. Nota che se M> 2N, allora abbiamo solo un pezzo, e questo viene eseguito in O (N), che è ottimale per l'eliminazione dei duplicati. Semplicemente li cancelliamo e ci assicuriamo che tutte le collisioni siano cancellate.
Modifica: Per richiesto, sto fornendo dettagli: * N è il numero di telefono.
La dimensione del blocco dipenderà dalla memoria, dovrebbe essere della dimensione M/2. Questa è la dimensione della memoria che caricherà un blocco del file, poiché l'intero file è troppo grande per essere caricato in memoria.
Questo lascia un altro M/2 byte per mantenere la tabella di hash , e/o un elenco duplicato .
Quindi, devono essere presenti blocchi N/(M/2), ciascuno della dimensione | C | = M/2
Il tempo di esecuzione sarà il numero di blocchi (N/(M/2)), moltiplicato per le dimensioni di ogni blocco | C | (o M/2). Nel complesso, questo dovrebbe essere lineare (più o meno l'overhead di cambiare da un pezzo all'altro, che è il motivo per cui il modo migliore per descriverlo è O ((N/M) * | C |)
. una Caricamento di un pezzo C iO. (| C |).
b iterare ogni elemento, prova e impostare se non ci O (1) saranno hashing in cui inserimento e ricerca dovrebbero prendere.
c. Se l'elemento è già presente, è possibile eliminarlo.
d. Ottenere il prossimo ch Lo Zio, sciacquare e ripetere (pezzi 2N/M, quindi O (N/M))
Rimozione di un elemento potrebbe costare O (N), a meno che non teniamo una lista e rimuoverli tutti in una volta , evitando di spostare tutti gli elementi rimanenti ogni volta che viene rimosso un elemento.
Se i numeri di telefono possono essere rappresentati come un intero -1, possiamo evitare di avere un hash-table pieno e basta usare una mappa di bandiera, risparmiando mucchi di memoria (ce la faremo solo bisogno di N-bit di memoria)
Ecco un pseudo-codice in qualche modo dettagliato:
void DeleteDuplicate(File file, int numberOfPhones, int maxMemory)
{
//Assume each 1'000'000 number of phones that fit in 32-bits.
//Assume 2MB of memory
//Assume that arrays of bool are coalesced into 8 bools per byte instead of 1 bool per byte
int chunkSize = maxMemory/2; // 2MB/2/4-byes per int = 1MB or 256K integers
//numberOfPhones-bits. C++ vector<bool> for example would be space efficient
// Coalesced-size ~= 122KB | Non-Coalesced-size (worst-case) ~= 977KB
bool[] exists = new bool[numberOfPhones];
byte[] numberData = new byte[chunkSize];
int fileIndex = 0;
int bytesLoaded;
do //O(chunkNumber)
{
bytesLoaded = file.GetNextByes(chunkSize, /*out*/ numberData);
List<int> toRemove = new List<int>(); //we still got some 30KB-odd to spare, enough for some 6 thousand-odd duplicates that could be found
for (int ii = 0; ii < bytesLoaded; ii += 4)//O(chunkSize)
{
int phone = BytesToInt(numberData, ii);
if (exists[phone])
toRemove.push(ii);
else
exists[phone] = true;
}
for (int ii = toRemove.Length - 1; ii >= 0; --ii)
numberData.removeAt(toRemove[ii], 4);
File.Write(fileIndex, numberData);
fileIndex += bytesLoaded;
} while (bytesLoaded > 0); // while still stuff to load
}
Cosa vuoi fare con i duplicati? Vuoi solo sapere se ci sono dei duplicati? Vuoi rimuovere i duplicati? Vuoi sapere se il numero di duplicati supera qualche soglia? –
Il duplicato verrebbe rimosso, non appena è stato trovato o alla fine. –
Due megabyte sono sufficienti per un [filtro Bloom] (http://en.wikipedia.org/wiki/Bloom_filter) contenente un milione di elementi. –