Elaborando un po 'la risposta di Snowman, penso che andrei per una gerarchia di valori hash su (in modo esponenziale) aumentando sottoinsiemi del file, calcolati su richiesta ogni volta che si verificano collisioni e memorizzati in una struttura dati adatta (tabella hash, ma anche un semplice albero di prefisso farebbe) per un rapido accesso futuro. Ciò dovrebbe garantire un fallimento rapido in caso di "quasi identità" e mantenere la complessità del caso peggiore (fino a un fattore log) e ottenere una buona complessità della media.
Sarebbe come segue in pseudo-Python , prendendo come input un file f
, un insieme di file D
e un dizionario H
(di nuovo, si potrebbe fare meglio qui , ma non dovrebbe importare troppo) agendo come una cache per i valori hash precedentemente calcolati:
collisions = [fc for fc in D if size(fc)==size(f)]
size_hash = 4*1024
while (len(collisions) > 0) and (size_hash<=size(f)):
H[(f,size_hash)] = md5(f,size_hash)
for fc in collisions:
if (fc,size_hash) not in H:
H[(fc,size_hash)] = md5(fc,size_hash)
collisions = [fc for fc in collisions if H[(fc,size_hash)]==H[(f,size_hash)]]
size_hash *= 2
for fc in collisions:
# Painstakingly read and compare content to that of f...
Complessità peggiore: Nel peggiore dei casi, tutti i file hanno uguale lunghezza n
, e hanno contenuti MD5 identici (sfortunati!) diversi, quindi uno finisce per calcolare gli hash MD5 per pezzi di dimensioni 4k, 8k, 16k ... n
in ciascuno dei file, solo per leggerli completamente dopo.
In termini di tempo, i primi 4k di ciascun file vengono letti per calcolare il primo hash, quindi il primo 8k per il secondo, 16k per il terzo ... quindi l'intera dimensione n. Il calcolo di un MD5 può essere eseguito in tempo lineare, quindi il consumo totale di tempo è (fino a una costante) 4k + 8k + 16k + ... + n < 2n operazioni, cioè rimane nell'ordine di grandezza del confronto finale (inevitabile) dei file.
In termini di memoria, log (n) valori hash MD5 (uno per 4k, uno per 8k ...), ciascuno di dimensioni costanti sarà memorizzato, quindi l'overhead dovrebbe essere ragionevole.
Complessità nella media dei casi: non specificherò l'analisi (le matematiche non sono comunque consentite dal sistema di markdown :)), ma anche assumendo un numero elevato di file di uguali dimensioni, il il numero previsto di valori hash calcolati dovrebbe essere costante in media, quindi questo algoritmo non leggerà parti significative dei file, né coagulerà la memoria.