J'apprends Haskell et comme exercice que je fais des arbres binaires. Après avoir fait un arbre binaire régulier, je veux l'adapter pour être équilibré. Donc:
Mais crucialité, que recommandez-vous?
Je suppose que cela appartient ici parce qu'il est ouvert à débattre.
Je vous recommanderais de commencer avec un arbre noir rouge ou un AVL Tree .
L'arbre noir noir est plus rapide pour l'insertion, mais l'arbre AVL a un léger bord pour les recherches. L'arbre AVL est probablement un peu plus facile à mettre en œuvre, mais pas par tout ce qui repose sur ma propre expérience.
L'arbre AVL garantit que l'arbre est équilibré après chaque insertion ou supprime (aucun sous-arbre n'a un facteur de balance supérieur à 1/-1, tandis que l'arbre noir rouge assure que l'arbre est raisonnablement équilibré à tout moment.
Je considérerais une alternative si vous allez bien avec Randomized Structures de données: Listes de saut .
À partir d'un point de vue de haut niveau, c'est une structure d'arbres, sauf que cela n'est pas implémenté comme un arbre mais comme une liste avec plusieurs couches de liens.
Vous obtiendrez O (log n) insertions/recherches/suppresses, et vous n'aurez pas à gérer tous ces cas de rééquilibrage difficiles.
Je n'ai jamais envisagé de les mettre en œuvre dans une langue fonctionnelle et la page Wikipedia ne montre aucune, il peut donc ne pas être facile (WRT à l'immutabilité)
Si vous voulez une structure relativement facile de commencer avec (les deux arbres AVL et les arbres noirs rouges sont fidèles), une option est une seule combinaison d'une combinaison d'arborescence et de "tas".
Chaque nœud obtient une valeur "priorité", souvent assignée au hasard comme le noeud est créé. Les nœuds sont positionnés dans l'arborescence de sorte que le commandement clé soit respecté, de sorte que la commande de valeurs prioritaires ressemblant à des tas est respectée. Un commandant semblable à un tas signifie que les deux enfants d'un parent ont des priorités plus faibles que le parent.
ÉDITER supprimé "dans les valeurs clés" ci-dessus - la priorité et la commande de clés s'appliquent ensemble, la priorité est donc importante pour des clés uniques.
C'est une combinaison intéressante. Si les clés sont uniques et des priorités sont uniques, il existe une structure arborescente unique pour tout ensemble de nœuds. Malgré tout, les inserts et les suppressions sont efficaces. Strictement parlant, l'arbre peut être déséquilibré jusqu'au point où il s'agit d'une liste liée, mais cela est extrêmement improbable (comme avec des arbres binaires standard), y compris pour des cas normaux tels que des clés insérées dans l'ordre (contrairement aux arbres binaires standard).
Qui est le plus efficace?
Vague et difficile à répondre. Les complexités de calcul sont toutes bien définies. Si c'est ce que vous entendez par efficacité, il n'y a pas de vrai débat. En effet, tous les bons algorithmes viennent avec des preuves et des facteurs de complexité.
Si vous voulez dire "l'heure d'exécution" ou "utilisation de la mémoire", vous devez comparer les implémentations réelles. Ensuite, la langue, le temps d'exécution, le système d'exploitation et d'autres facteurs entrent en jeu, ce qui rend la question difficile à répondre.
Ce qui est le plus facile à mettre en œuvre?
Vague et difficile à répondre. Certains algorithmes peuvent vous apparaître complexes, mais trivial pour moi.
Qui est le plus souvent utilisé?
Vague et difficile à répondre. D'abord, il y a le "par qui?" une partie de cela? Haskell seulement? Qu'en est-il de C ou C++? Deuxièmement, il y a le problème logiciel propriétaire où nous n'avons pas accès à la source de faire une enquête.
Mais crucialité, que recommandez-vous?
Je suppose que cela appartient ici car il est ouvert à débattre.
Correct. Étant donné que vos autres critères ne sont pas très utiles, c'est tout ce que vous allez obtenir.
Vous pouvez obtenir une source pour un grand nombre d'algorithmes d'arbres. Si vous voulez apprendre quelque chose, vous pourriez simplement implémenter tout le monde que vous pouvez trouver. Plutôt que de demander une "recommandation", collectez-vous à tous les algorithmes que vous pouvez trouver.
Voici la liste:
http://fr.wikipedia.org/wiki/elf-balancing_binaire_search_tree
Il y a six personnes populaires définies. Commencez avec ceux-ci.
Si vous êtes intéressé par les arbres de l'épais, il y a une version plus simple de celles que je crois a été décrite pour la première fois dans un article par Allen et Munroe. Il n'a pas les mêmes garanties de performance, mais évite les complications dans le rééquilibrage de "Zig-Zig" contre "Zig-Zig".
Fondamentalement, lors de la recherche (y compris la recherche d'un point d'insertion ou de nœud à supprimer), le nœud que vous recherchez est tourné directement vers la racine, bas en bas (par ex. Sous forme de sortie de fonction de recherche récursive). À chaque étape, vous sélectionnez une seule rotation gauche ou droite selon que l'enfant que vous souhaitez extraire une autre étape vers la racine était le bon enfant ou l'enfant à gauche (si je me souviens de mes instructions de rotation correctement, c'est respectivement).
Comme les arbres de l'épaule, l'idée est que les articles récemment accessibles sont toujours près de la racine de l'arbre, si vite à accéder à nouveau. Être plus simple, ces arbres rotatifs allen-munroe (ce que je les appelle - ne connaissez pas le nom officiel) peut être plus rapide, mais ils n'ont pas la même garantie de performance amortie.
Une chose - puisque cette structure de données par définition muttait même pour trouver des opérations, il aurait probablement besoin d'être mis en œuvre de manière mondiale. Je ne suis peut-être pas un bon ajustement pour la programmation fonctionnelle.
Un arbre équilibré très simple est un arbre AA . C'est invariant est plus simple et donc plus facile. En raison de sa simplicité, sa performance est toujours bonne.
En tant qu'exercice avancé, vous pouvez essayer d'utiliser GADTS pour mettre en œuvre l'une des variantes d'arbres équilibrés dont l'invariant est appliqué par le type de système de type.