J'essaie de trouver la définition d'un arbre de recherche binaire et je continue à trouver différentes définitions partout.
Certains disent que pour tout sous-arbre donné, la clé enfant gauche est inférieure ou égale à la racine.
Certains disent que pour un sous-arbre donné, la clé enfant correcte est supérieure ou égale à la racine.
Et mon vieux livre de structures de données de collège dit: "chaque élément a une clé et aucun élément n’a la même clé".
Existe-t-il une définition universelle du bst? Particulièrement en ce qui concerne quoi faire avec des arbres avec plusieurs instances de la même clé.
EDIT: Peut-être que je n'étais pas clair, les définitions que je vois sont
1) left <= root <right
2) left <root <= right
3) left <root <right, de sorte qu’il n’existe aucune clé dupliquée.
De nombreux algorithmes spécifieront que les doublons sont exclus. Par exemple, les exemples d'algorithmes dans le livre MIT Algorithms) présentent généralement des exemples sans doublons. Il est assez simple d'implémenter des doublons (sous forme de liste au nœud ou dans une direction particulière).
La plupart (que j'ai vus) spécifie les enfants de gauche comme <= et les enfants de droite comme>. En pratique, un BST qui permet aux enfants de droite ou de gauche d'être égaux au nœud racine nécessitera des étapes de calcul supplémentaires pour terminer une recherche lorsque les nœuds en double sont autorisés.
Il est préférable d’utiliser une liste sur le nœud pour stocker les doublons, car l’insertion d’une valeur '=' sur un côté du nœud nécessite de réécrire l’arbre de ce côté pour que le nœud soit considéré comme l’enfant ou que le nœud soit placé en grand. -child, à un moment donné ci-dessous, ce qui élimine une partie de l'efficacité de la recherche.
Vous devez vous rappeler que la plupart des exemples en classe sont simplifiés pour décrire et présenter le concept. Ils ne valent pas la peine d'être accroupis dans de nombreuses situations du monde réel. Mais la déclaration "chaque élément a une clé et aucun élément ne possède la même clé" n'est pas violée par l'utilisation d'une liste au niveau du nœud de l'élément.
Allez donc avec ce que dit votre livre de structures de données!
Modifier:
La définition universelle d'un arbre de recherche binaire implique le stockage et la recherche d'une clé basée sur le déplacement d'une structure de données dans l'une des deux directions. Dans le sens pragmatique, cela signifie que si la valeur est <>, vous parcourez la structure de données dans l’une des deux "directions". Ainsi, dans ce sens, les valeurs en double n’ont aucun sens.
Ceci est différent de BSP, ou partition de recherche binaire, mais pas si différent. L'algorithme de recherche a l'une des deux directions pour "voyager", ou c'est fait (avec succès ou non). Je m'excuse donc, ma réponse initiale ne traitait pas du concept de "définition universelle", car les doublons sont vraiment distincts. sujet (quelque chose que vous traitez après une recherche réussie, pas dans le cadre de la recherche binaire.)
Si votre arbre de recherche binaire est un arbre noir rouge ou si vous souhaitez effectuer une quelconque opération de "rotation d'arbre", des nœuds en double poseront des problèmes. Imaginez que votre règle d’arbre soit la suivante:
left <racine <= right
Imaginons maintenant un arbre simple dont la racine est 5, l'enfant gauche est nul et l'enfant droit est 5. Si vous faites une rotation gauche de la racine, vous obtenez un 5 dans l'enfant gauche et un 5 dans la racine avec l'enfant droit. être nul. Maintenant, quelque chose dans l’arbre de gauche est égal à la racine, mais votre règle ci-dessus suppose que <racine.
J'ai passé des heures à essayer de comprendre pourquoi mes arbres rouges/noirs traversaient parfois en panne, le problème était ce que j'ai décrit ci-dessus. J'espère que quelqu'un lira ceci et économisera des heures de débogage dans le futur!
Les trois définitions sont acceptables et correctes. Ils définissent différentes variations d'une BST.
Le livre de votre structure de données de collège n'a pas précisé que sa définition n'était pas la seule possible.
Certes, autoriser les doublons ajoute de la complexité. Si vous utilisez la définition "left <= root <right" et que vous avez un arbre du type:
3
/ \
2 4
puis ajouter une clé en double "3" à cet arbre aura pour résultat:
3
/ \
2 4
\
3
Notez que les doublons ne sont pas à des niveaux contigus.
Ceci est un gros problème lorsque vous autorisez les doublons dans une représentation BST comme celle ci-dessus: les doublons peuvent être séparés par un nombre quelconque de niveaux. Par conséquent, vérifier l'existence des doublons n'est pas aussi simple que de rechercher les enfants immédiats d'un nœud.
Une option pour éviter ce problème consiste à ne pas représenter les doublons de manière structurelle (en tant que nœuds séparés), mais à utiliser un compteur qui compte le nombre d'occurrences de la clé. L'exemple précédent aurait alors un arbre comme:
3(1)
/ \
2(1) 4(1)
et après l’insertion de la clé "3" en double, elle devient:
3(2)
/ \
2(1) 4(1)
Cela simplifie les opérations de recherche, de suppression et d’insertion, au détriment de quelques octets supplémentaires et des opérations de comptage.
Dans un BST, toutes les valeurs descendant du côté gauche d'un nœud sont inférieures (ou égales à, voir plus loin) au nœud lui-même. De même, toutes les valeurs descendantes du côté droit d’un nœud sont supérieures (ou égales à) à la valeur des nœuds.(une).
Certains BST peuvent choisir d'autoriser les doublons, d'où le qualificatif "ou égal à" ci-dessus.
L'exemple suivant peut clarifier:
|
+--- 14 ---+
| |
+--- 13 +--- 22 ---+
| | |
1 16 +--- 29 ---+
| |
28 29
Cela montre un BST qui autorise les doublons - vous pouvez voir que pour trouver une valeur, vous commencez au nœud racine et descendez dans la sous-arborescence gauche ou droite, selon que votre valeur de recherche est inférieure ou supérieure à la valeur du nœud.
Cela peut être fait de manière récursive avec quelque chose comme:
def hasVal (node, srchval):
if node == NULL:
return false
if node.val == srchval:
return true
if node.val > srchval:
return hasVal (node.left, srchval)
return hasVal (node.right, srchval)
et en l'appelant avec:
foundIt = hasVal (rootNode, valToLookFor)
Les doublons ajoutent un peu de complexité car vous devrez peut-être continuer à chercher une fois que vous aurez trouvé votre valeur pour d'autres nœuds de la même valeur.
(une) Vous pouvez les trier dans la direction opposée si vous le souhaitez, à condition que vous ajustiez la façon dont vous recherchez une clé spécifique. Un BST n'a besoin que de maintenir un ordre de tri, peu importe que ce soit croissant ou décroissant.
Dans le livre "Introduction to algorithm", troisième édition, de Cormen, Leiserson, Rivest et Stein, un arbre de recherche binaire (BST) est explicitement défini comme permettant les doublons. Ceci est visible aux figures 12.1 et suivantes (page 287):
"Les clés d'un arbre de recherche binaire sont toujours stockées de manière à satisfaire la propriété d'arbre de recherche binaire: Soit
x
un noeud dans un arbre de recherche binaire. Siy
est un nœud dans le sous-arbre gauche dex
, puisy:key <= x:key
. Siy
est un noeud du sous-arbre de droite dex
, alorsy:key >= x:key
. "
De plus, un arbre rouge-noir est ensuite défini à la page 308 comme suit:
"Un arbre rouge-noir est un arbre de recherche binaire avec un bit de stockage supplémentaire par nœud: sa couleur"
Par conséquent, les arbres rouge-noir définis dans ce livre prennent en charge les doublons.
Lorsque je travaillais sur une implémentation d’arbre rouge-noir, je rencontrais des problèmes pour valider l’arborescence avec plusieurs clés jusqu’à ce que j’aperçois que la rotation de l’insert rouge-noir nécessite de relâcher la contrainte.
left <= root <= right
Comme aucune des documentations que je cherchais ne permettait de dupliquer des clés et que je ne souhaitais pas réécrire les méthodes de rotation pour en rendre compte, j'ai juste décidé de modifier mes nœuds pour autoriser plusieurs valeurs dans le nœud et aucune clé dupliquée dans l'arbre.
Toute définition est valide. Tant que vous êtes cohérent dans votre implémentation (mettez toujours des nœuds égaux à droite, toujours à gauche, ou ne les autorisez jamais), tout va bien. Je pense qu'il est très courant de ne pas les autoriser, mais c'est toujours une BST si elles sont autorisées et placées à gauche ou à droite.
Ces trois choses que vous avez dites sont toutes vraies.
Je suppose que vous pouvez inverser votre arborescence et placer les petites touches à droite, mais le concept de "gauche" et de "droite" n’est en réalité que cela: un concept visuel qui nous aide à réfléchir à une structure de données qui n’a pas vraiment de gauche. ou juste, donc ça n'a pas vraiment d'importance.
1.) left <= root <right
2.) left <racine <= right
3.) left <root <right, de sorte qu’il n’existe aucune clé dupliquée.
Je devrais peut-être aller fouiller dans mes livres d'algorithmes, mais la forme canonique est au sommet de ma tête (3).
(1) ou (2) ne se produisent que lorsque vous commencez à autoriser les nœuds en double et vous placez des nœuds en double dans l'arborescence elle-même (plutôt que le nœud contenant une liste).
Dupliquer les clés • Que se passe-t-il s'il y a plus d'un élément de données avec la même clé? - Cela pose un léger problème dans les arbres rouge-noir. - Il est important que les nœuds avec la même clé soient répartis des deux côtés des autres nœuds avec la même clé. - C’est-à-dire que si les clés arrivent dans l’ordre 50, 50, 50, • vous voulez que le deuxième 50 aille à la droite du premier et le troisième 50 à la gauche du premier. • Sinon, l’arbre devient déséquilibré. • Cela pourrait être traité par une sorte de processus de randomisation dans l'algorithme d'insertion. - Cependant, le processus de recherche devient alors plus compliqué si tous les éléments avec la même clé doivent être trouvés. • Il est plus simple d'interdire des éléments avec la même clé. - Dans cette discussion, nous supposerons que les doublons ne sont pas autorisés
On peut créer une liste chaînée pour chaque nœud de l’arbre contenant les clés dupliquées et stocker les données dans la liste.
La relation d’ordre des éléments <= est un ordre total , de sorte que la relation doit être réflexive, mais généralement un arbre de recherche binaire (ou BST) est un arbre sans doublons.
Sinon, s'il y a des doublons, vous devez exécuter deux fois ou plus la même fonction de suppression!