Lorsque vous avez un fichier très volumineux et de nombreux éléments, mais l'élément le plus courant est très courant - se produit fraction du temps - vous pouvez le trouver en temps linéaire avec des mots d'espace (le constante dans la notation est très petite, essentiellement 2 si vous ne comptez pas le stockage pour des choses auxiliaires comme le hachage). De plus, cela fonctionne très bien avec le stockage externe, car le fichier est traité en séquence un élément à la fois, et l'algorithme ne "regarde en arrière" jamais. Une façon de le faire est via un algorithme classique de Misra et Gries, voir ces notes de cours . Le problème est maintenant connu comme le problème des frappeurs lourds (les éléments fréquents étant les frappeurs lourds).O ( k ) O ( )>1/kO(k)O()
L'hypothèse selon laquelle l'élément le plus fréquent apparaît fraction du temps pour un petit nombre peut sembler forte mais elle est en quelque sorte nécessaire! Autrement dit, si vous aurez un accès séquentiel à votre fichier (et si le fichier est énorme, l'accès aléatoire sera trop cher), tout algorithme qui trouve toujours l'élément le plus fréquent dans un nombre constant de passages utilisera un espace linéaire dans le nombre d'éléments . Donc, si vous ne supposez rien sur l'entrée, vous ne pouvez pas battre une table de hachage. L'hypothèse selon laquelle l'élément le plus fréquent est très fréquent est peut-être le moyen le plus naturel de contourner les résultats négatifs.k>1/kk
Voici un croquis pour , c'est-à-dire lorsqu'il y a un seul élément qui se produit plus de la moitié du temps. Ce cas particulier est connu sous le nom d'algorithme de vote majoritaire et est dû à Boyer et Moore. Nous garderons un seul élément et un seul décompte. Initialisez le nombre à 1 et stockez le premier élément du fichier. Ensuite, traitez le fichier en séquence:k=2
- si l'élément actuel du fichier est le même que l'élément stocké, augmentez le nombre d'un
- si l'élément actuel du fichier est différent de l'élément stocké, diminuez le nombre d'un
- si le nombre mis à jour est de 0, "supprimer" l'élément stocké et stocker l'élément actuel du fichier; augmenter le nombre à 1
- passer à l'élément suivant du fichier
Un peu de réflexion sur cette procédure vous convaincra que s'il existe un élément "majoritaire", c'est-à-dire un élément qui se produit plus de la moitié du temps, alors cet élément sera l'élément stocké après le traitement de tout le fichier.
Pour général , vous gardez éléments et compte, et vous initialisez les éléments au premier éléments distincts du fichier et les comptes au nombre de fois chacun de ces éléments apparaît avant de voir le -ème élément distinct. Ensuite, vous exécutez essentiellement la même procédure: le nombre d'un élément est augmenté chaque fois qu'il est rencontré, tous les nombres d'éléments sont diminués si un élément qui n'est pas stocké est rencontré, et lorsqu'un certain nombre est nul, cet élément est expulsé en faveur de la élément courant du fichier. Il s'agit de l'algorithme Misra-Gries.k - 1 k - 1 k kkk−1k−1kk
Vous pouvez bien sûr utiliser une table de hachage pour indexer les éléments stockés. À la fin, cet algorithme est garanti pour retourner tout élément qui se produit plus de fraction du temps. C'est essentiellement le mieux que vous puissiez faire avec un algorithme qui effectue un nombre constant de passages sur le fichier et ne stocke que des mots .1 / k O ( k )k−11/kO(k)
Une dernière chose: après avoir trouvé candidats "frappeurs lourds" (c'est-à-dire des éléments fréquents), vous pouvez effectuer un autre passage sur le fichier pour compter la fréquence de chaque élément. De cette façon, vous pouvez classer les éléments entre eux et vérifier s'ils se produisent tous plus de fraction du temps (s'il y a moins de tels éléments, certains des éléments renvoyés par l'algorithme peuvent être des faux positifs ).kk - 11/kk−1