J'ai récemment entendu parler de recherche ternaire dans laquelle nous divisons un tableau en 3 parties et comparons. Ici, il y aura deux comparaisons mais cela réduira le tableau à n/3. Pourquoi les gens ne l'utilisent-ils pas autant?
En fait, les gens utilisent des arbres k-ary pour k arbitraires.
C'est cependant un compromis.
Pour trouver un élément dans un arbre k-aire, vous avez besoin d'environ k * ln (N)/ln (k) opérations (rappelez-vous la formule de changement de base). Plus votre k est grand, plus vous avez besoin d'opérations globales.
L'extension logique de ce que vous dites est "pourquoi les gens n'utilisent-ils pas un arbre N-aire pour N éléments de données?". Ce qui, bien sûr, serait un tableau.
Une recherche ternaire vous donnera toujours la même complexité asymptotique O (log N) temps de recherche et ajoute de la complexité à la mise en œuvre.
Le même argument peut être dit pour pourquoi vous ne voudriez pas une recherche quad ou tout autre ordre supérieur.
Rechercher 1 milliard (1 milliard - 1 milliard de dollars) d'éléments triés prendrait en moyenne environ 15 comparés à la recherche binaire et environ 9 comparés à une recherche ternaire - ce qui n'est pas un avantage énorme. Et notez que chaque "comparaison ternaire" peut impliquer 2 comparaisons réelles.
Sensationnel. Les réponses les plus votées manquent le coche sur celui-ci, je pense.
Votre CPU ne supporte pas la logique ternaire en une seule opération; il divise la logique ternaire en plusieurs étapes de la logique binaire. Le code le plus optimal pour la CPU est la logique binaire. Si les puces étaient communes et prenaient en charge la logique ternaire en une seule opération, vous auriez raison.
Les arbres B peuvent avoir plusieurs branches sur chaque nœud; un arbre B d'ordre 3 est une logique ternaire. Chaque étape dans l'arborescence nécessite deux comparaisons au lieu d'une, ce qui ralentira probablement le temps de calcul.
Les arbres B, cependant, sont assez communs. Si vous supposez que chaque nœud de l'arborescence sera stocké séparément sur le disque, vous passerez le plus clair de votre temps à lire le disque ... et le processeur ne sera pas un goulot d'étranglement, mais le disque le sera. Donc, vous prenez un arbre B avec 100 000 enfants par nœud, ou tout ce que vous voudrez à peine entrer dans un bloc de mémoire. Les arbres B ayant ce type de facteur de ramification auraient rarement une hauteur supérieure à trois nœuds et vous n'auriez que trois lectures de disque - trois arrêts au goulet d'étranglement - pour rechercher un énorme ensemble de données.
Révision:
Une recherche ternaire peut être plus rapide qu'une recherche binaire si une détermination de partition à 3 voies peut être effectuée pour moins d'environ 1,55 fois le coût d'une comparaison à 2 voies. Si les éléments sont stockés dans un tableau trié, la détermination à 3 voies sera en moyenne 1,66 fois plus chère qu'une détermination à 2 voies. Toutefois, si les informations sont stockées dans une arborescence, le coût de la récupération des informations est élevé par rapport au coût de la comparaison réelle, et la localisation en cache signifie que le coût de la récupération aléatoire d'une paire de données liées n'est pas pire que le coût de la récupération d'une seule Un arbre de données ternaire ou à sens unique peut améliorer considérablement l’efficacité.
Qu'est-ce qui vous fait penser que la recherche ternaire devrait être plus rapide?
Nombre moyen de comparaisons:
in ternary search = ((1/3)*1 + (2/3)*2) * ln(n)/ln(3) ~ 1.517*ln(n)
in binary search = 1 * ln(n)/ln(2) ~ 1.443*ln(n).
Pire nombre de comparaisons:
in ternary search = 2 * ln(n)/ln(3) ~ 1.820*ln(n)
in binary search = 1 * ln(n)/ln(2) ~ 1.443*ln(n).
Il semble donc que la recherche ternaire est pire.
Notez également que cette séquence généralise la recherche linéaire si nous continuons
Binary search
Ternary search
...
...
n-ary search ≡ linear search
Ainsi, dans une recherche n-aire, nous aurons "un seul COMPARER" qui pourrait prendre jusqu'à n comparaisons réelles.
La recherche "terinary" (ternaire?) Est plus efficace dans le meilleur des cas, ce qui impliquerait de rechercher le premier élément (ou peut-être le dernier, en fonction de la comparaison que vous avez effectuée en premier). Pour les éléments plus éloignés de la fin que vous vérifiez en premier, alors que deux comparaisons réduiraient le tableau de 2/3 à chaque fois, les mêmes deux comparaisons avec la recherche binaire réduiraient l'espace de recherche de 3/4.
Ajoutez à cela, la recherche binaire est plus simple. Vous ne faites que comparer et obtenir une moitié ou une autre, plutôt que de comparer, si moins que d'obtenir le premier tiers, sinon comparer, si moins que d'obtenir le deuxième tiers, sinon obtenir le dernier tiers.
La recherche ternaire peut être utilisée efficacement sur des architectures parallèles - FPGA et ASIC. Par exemple, si la mémoire FPGA interne requise pour la recherche est inférieure à la moitié de la ressource FPGA, vous pouvez créer un bloc de mémoire en double. Cela permettrait d’accéder simultanément à deux adresses de mémoire différentes et d’effectuer toutes les comparaisons en un seul cycle d’horloge. C’est l’une des raisons pour lesquelles le FPGA 100 MHz peut parfois surpasser le processeur 4 GHz :)
Presque tous les manuels et les sites Web sur les arbres de recherche binaires ne parlent pas vraiment d'arbres binaires! Ils vous montrent des arbres de recherche ternaires! Les vrais arbres binaires stockent les données dans leurs feuilles, pas les nœuds internes (à l'exception des clés pour naviguer). Certains appellent ces arbres à feuilles et font la distinction entre les arbres de noeuds indiqués dans les manuels:
J. Nievergelt, C.-K. Wong: Limites supérieures de la longueur totale du chemin des arbres binaires, Journal ACM 20 (1973) 1–6.
Ce qui suit est extrait du livre de Peter Brass sur les structures de données.
2.1 Deux modèles d'arbres de recherche
Dans l’esquisse qui vient d’être donnée, nous avons supprimé un point important qui, au premier abord, semble Trivial, mais nous aboutissons en fait à deux modèles différents d’arbres de recherche, soit de , Qui peuvent être combinés à la plupart des éléments suivants. matériel, mais un de ceux-ci est fortement préférable.
Si nous comparons dans chaque nœud la clé de requête avec la clé contenue dans le nœud Et suivons la branche de gauche si la clé de requête est plus petite et la branche de droite Si la clé de requête est plus grande, alors que se passe-t-il s'ils sont égaux? Les deux modèles D’arbres de recherche sont les suivants:
Prenez la branche de gauche si la clé de requête est plus petite que la clé de nœud; sinon, prenez la branche droite, jusqu’à atteindre une feuille de l’arbre. Les clés du nœud intérieur De l’arbre servent uniquement à des fins de comparaison; tous les objets sont dans les feuilles.
Prenez la branche de gauche si la clé de requête est plus petite que la clé de nœud; prenez la branche de droite si la clé de requête est plus grande que la clé de noeud; et prenez l’objet contenu dans le nœud s’ils sont égaux.
Ce point mineur a un certain nombre de conséquences:
{Dans le modèle 1, l’arbre sous-jacent est un arbre binaire, alors que dans le modèle 2, chaque nœud Est en réalité un nœud ternaire avec un voisin central spécial.
{Dans le modèle 1, chaque nœud intérieur a un sous-arbre gauche et un sous-arbre droit (chacun pouvant être un nœud feuille De l’arbre), alors que dans le modèle 2, nous devons autoriser des nœuds incomplets , Où gauche ou un sous-arbre de droite peut être manquant et seuls l’objet de comparaison et la clé sont garantis.
La structure d’un arbre de recherche du modèle 1 est donc plus régulière que celle d’un arbre Du modèle 2; c'est, du moins pour la mise en œuvre, un avantage certain.
{Dans le modèle 1, traverser un nœud intérieur ne nécessite qu'une seule comparaison, , Tandis que dans le modèle 2, nous avons besoin de deux comparaisons pour vérifier les trois possibilités .
En effet, les arbres de même hauteur dans les modèles 1 et 2 contiennent au plus approximativement Le même nombre d'objets, mais il faut multiplier par deux le nombre de comparaisons dans le modèle 2 pour atteindre les objets les plus profonds de l'arbre. . Bien sûr, dans le modèle 2, il y a aussi Certains objets qui ont été atteints beaucoup plus tôt; l'objet dans la racine se trouve avec seulement deux comparaisons, mais presque tous les objets se trouvent au niveau le plus profond ou à proximité.
Théorème. Un arbre de hauteur h et de modèle 1 contient au plus 2 ^ h objets. Un arbre de hauteur h et de modèle 2 contient au plus 2 ^ h + 1 - 1 objets.
Cela se voit facilement car l’arbre de hauteur h a pour sous-arbres gauche et droit un arbre de D’au plus h - 1, et dans le modèle 2, un objet supplémentaire entre .
{Dans le modèle 1, les clés dans les nœuds intérieurs servent uniquement à des fins de comparaison et Peut réapparaître dans les feuilles pour l'identification des objets. Dans le modèle 2, chaque touche N'apparaît qu'une seule fois, avec son objet.
Dans le modèle 1, il est même possible que des clés utilisées pour la comparaison ne puissent pas appartenir à , Par exemple si cet objet a été supprimé. En séparant conceptuellement ces fonctions de comparaison et d’identification, ce N’est pas surprenant, et dans les structures ultérieures, il pourrait même être nécessaire de définir des tests artificiels Ne correspondant à aucun objet, uniquement pour: obtenir une bonne division de l'espace de recherche . Toutes les clés utilisées à des fins de comparaison sont nécessairement distinctes, car dans un modèle 1, chaque nœud intérieur a des sous-arbres gauche et droit non vides. Ainsi, chaque touche Apparaît au maximum deux fois, une fois comme clé de comparaison et une fois comme clé d'identification dans La feuille.
Le modèle 2 est devenu la version de manuel préférée car dans la plupart des manuels , La distinction entre objet et clé n'est pas faite: la clé est l'objet. Il devient alors peu naturel de dupliquer la clé dans l'arborescence. . Mais dans Toutes les applications réelles, la distinction entre clé et objet est très importante. On ne souhaite presque jamais garder trace d'un ensemble de nombres; les chiffres sont normalement associés à des informations supplémentaires, qui sont souvent plus volumineuses que la clé elle-même.
Voici certaines preuves expérimentales aléatoires que je n’ai pas vérifiées montrant que la recherche est plus lente que la recherche binaire.
Vous avez peut-être entendu parler de la recherche ternaire dans ces énigmes qui impliquent de peser des objets sur des balances. Ces échelles peuvent donner 3 réponses: gauche est plus claire, les deux sont identiques ou gauche est plus lourde. Donc, dans une recherche ternaire, il ne faut qu'une comparaison. Cependant, les ordinateurs utilisent la logique booléenne, qui n'a que 2 réponses. Pour effectuer la recherche ternaire, vous devez en fait effectuer 2 comparaisons au lieu de 1. Je suppose qu'il existe des cas où cela est encore plus rapide que les affiches précédentes, mais vous pouvez voir que la recherche ternaire n'est pas toujours mieux, et il est plus déroutant et moins naturel de mettre en œuvre sur un ordinateur.
Je viens de poster un blog à propos de la recherche ternaire et j'ai montré quelques résultats. J'ai également fourni des implémentations de niveau initial sur mon git repo Je suis totalement d'accord avec tout le monde sur la partie théorique de la recherche ternaire, mais pourquoi ne pas l'essayer? Selon l’implémentation, cette partie est assez facile si vous avez trois ans d’expérience dans le codage. J'ai constaté que si vous disposiez d’énormes quantités de données et que vous deviez effectuer plusieurs recherches, la recherche ternaire présente un avantage. Si vous pensez que vous pouvez faire mieux avec une recherche ternaire, foncez.
Théoriquement, le minimum de k/ln(k)
est atteint à e et puisque 3 est plus proche de e que 2, il nécessite moins de comparaisons. Vous pouvez vérifier que 3/ln(3) = 2.73..
et 2/ln(2) = 2.88..
La raison pour laquelle la recherche binaire pourrait être plus rapide est que son code a moins de branches et s'exécute plus rapidement sur les processeurs modernes.
Bien que vous obteniez la même complexité big-O (ln n) dans les deux arbres de recherche, la différence réside dans les constantes. Vous devez faire plus de comparaisons pour un arbre de recherche ternaire à chaque niveau. La différence revient donc à k/ln (k) pour un arbre de recherche k-aire. Cela a une valeur minimale à e = 2,7 et k = 2 fournit le résultat optimal.