Je veux filtrer efficacement une liste d'entiers pour les doublons d'une manière que seul l'ensemble résultant doit être stocké.
Cela peut être vu d'une manière:
- nous avons une gamme d'entiers avec grand (disons )
- nous avons une fonction avec, supposément, de nombreuses collisions (les images sont uniformément réparties dans )
- il faut alors stocker , c'est-à-dire
J'ai une estimation (probabiliste) assez précise de ce qui est, et peut donc allouer des structures de données à l'avance (disons ).
J'ai eu quelques idées, mais je ne sais pas quelle serait la meilleure approche:
- un jeu de bits est hors de question car l'ensemble d'entrée ne tient pas en mémoire.
- une table de hachage, mais (1) cela nécessite une surcharge de mémoire, disons 150% de et (2) la table doit être explorée lors de sa construction, ce qui nécessite du temps supplémentaire en raison de la surcharge de la mémoire.
- un tri "à la volée", de préférence avec une complexité (tri sans comparaison). À ce sujet, je ne sais pas quelle est la principale différence entre le tri par compartiment et le tri flash .
- un tableau simple avec un arbre de recherche binaire, mais cela nécessite temps.
- peut-être que l'utilisation de filtres Bloom ou d'une structure de données similaire pourrait être utile pour détendre (avec des faux positifs) le problème.
Certaines questions sur stackoverflow semblent s'attaquer à ce genre de choses ( /programming/12240997/sorting-array-in-on-run-time , /programming/3951547/java -array-find-duplicates ), mais aucun ne semble correspondre à mes exigences.
Réponses:
Pourquoi pas un bac et une chaîne?
L'idée est de stocker des entiers positifs représentables par bits dans un tableau A de 2 k entrées représentant des plages de valeurs: l'entrée A [ y ] , y ≥ 0 , représente la plage [ 2 m y , 2 m ( y + 1 ) - 1 ] . Pour tout 1 ≤ x < 2 n, nous pouvons écrire x = 2 m yn=k+m A 2k A[y] y≥0 [2my,2m(y+1)−1] 1≤x<2n où y a k bits et z a m bits. Essayez de stocker z (pas x !) À l'emplacement y :x=2my+z y k z m z x y
Lorsque déjà, ne faites rien: x est un doublon.A[y]=z x
Lorsque n'est pas initialisé, stockez z à A [ y ] .A[y] z A[y]
Sinon, stockez un index dans un tableau séparé utilisé pour enchaîner les (qui sont entrés en collision en y ) dans des listes chaînées. Vous devrez effectuer une recherche linéaire dans la liste dirigée par A [ y ] et, selon ce que la recherche révèle, insérer potentiellement z dans la liste.z y A[y] z
À la fin, est facile à récupérer en parcourant les entrées initialisées de A et - en concaténant simplement deux chaînes de bits - en réassemblant chaque z trouvé à l'emplacement y (soit directement soit dans une chaîne référencée ici) dans l'original valeur x = 2 m y + z .f(S) A z y x=2my+z
Lorsque la distribution est proche de l'uniforme et que dépasse N , il n'y aura pas beaucoup de chaînage (cela peut être évalué de la manière habituelle) et les chaînes auront tendance à être courtes. Lorsque la distribution n'est pas uniforme, l'algorithme fonctionne toujours, mais peut atteindre un timing quadratique. Si c'est une possibilité, utilisez quelque chose de plus efficace que les chaînes (et payez un peu de frais généraux pour le stockage).2k N
Le stockage nécessaire est au maximum de bits pour A et de 2 2 k bits pour les chaînes (en supposant que m ≤ k ). C'est exactement l'espace nécessaire pour stocker 2 k valeurs de n bits chacune. Si vous êtes confiant dans l'uniformité, vous pouvez sous-allouer le stockage pour les chaînes. Si la non-uniformité est une possibilité, vous voudrez peut-être augmenter k et préconiser pleinement le stockage en chaîne.2n A 22k m≤k 2k n k
Une autre façon de penser à cette solution est qu'il s'agit d' une table de hachage avec une fonction de hachage particulièrement agréable (prenez les bits les plus significatifs) et, à cause de cela, nous n'avons besoin que de stocker les m = n - k bits les moins significatifs dans la table.k m=n−k
Il existe des moyens de superposer le stockage pour les chaînes avec le stockage pour mais cela ne semble pas valoir la peine, car cela n'économiserait pas beaucoup (en supposant que m est beaucoup plus petit que k ) de l'espace et rendrait le code plus difficile à développer, déboguer et maintenir.A m k
la source