diff --git a/arbres/ARBRES_BINAIRES.md b/arbres/ARBRES_BINAIRES.md new file mode 100644 index 0000000..261e929 --- /dev/null +++ b/arbres/ARBRES_BINAIRES.md @@ -0,0 +1,443 @@ + + +## Les arbres binaires + +> Parmi la forêt d'arbres possibles, on s'intéressera essentiellement aux arbres dit binaires. +> Ceux ci sont principalement utilisés pour les bases de données (indexation), les moteurs de recherche, et les compilateurs. + + + +### Définition: +Un arbre **binaire** est un arbre de degré 2 (dont lesnoeuds sont de degré 2 au plus). + +Les enfants d'un noeud sont lus de **gauche à droite** et sont appelés **fils gauche** et **fils droit**. + +![fig15.png](assets/fig15.png) + +### Exercice 1: +Parmi les arbres du cours précédent, lesquels sont binaires ? + +Réponse + +### Remarque: +Les arbres binaires forment une structure de données qui peut se définir de façon récursive. + +Un arbre binaire est: +- soit vide +- soit composé d'une racine portant une étiquette (clé) et d'une paire d'arbres binaires, appelés sous-arbre gauche et sous-arbre droit. + +Les arbres binaires sont utilisés dans de très nombreuses activités informatiques, nous allons étudier et implanter cette structure de données. + +## Comment représenter un arbre binaire... à la main... + +L'idée est de représenter l'arbre avec un tableau. + +[r, a, b] La racine r suivie de ses fils gauche et droit. + +![fig16.png](assets/fig16.png) + +![fig17.png](assets/fig17.png) + +Puis on rajoute dans l'ordre les fils gauche et droit de a, puis ceux de b. + +[r, a, b, c, d, e, f] + +### Remarque: +Chaque noeud se repère par son indice *n* dans la liste, son fils gauche se trouvant alors à l'indice *2n + 1* et son fils droit à l'indice *2n + 2*. + +Exemple: **b** est d'indice 2, son fils gauche se trouve alors à l'indice 5 et son fils droit à l'indice 6. + +Si un noeud n'a pas de fils, on le précise en mettant *None* à sa place. Notre arbre est alors représenté par le tableau: + +[r, a, b, c, d, e, f, None, None, None, None, None, None, None, None] + +**Quelle taille doit avoir le tableau ?** + +![fig18.png](assets/fig18.png) + +Cet arbre est complet (tous les noeuds internes ont deux fils). + +Il possède 3 niveaux, sa hauteur ou profondeur est donc de 2. La taille du tableau sera de: $$2^0 + 2^1 + 2^2 + 2^3 = 2^4 -1 = 15$$ + +*Il faut compter le nombre de noeuds, y compris les noeuds "fantômes" des feuilles.* + +### Exercice : +1. Quelle est la taille du tableau qui permet de représenter cet arbre ? + +![fig19.png](assets/fig19.png) + +2. Ecrire le tableau représentant cet arbre et le stocker dans une variable **t** + +3. Quelle propriété ont les indices des fils gauches et droits ? + +4. Voici un tableau représentant un arbre binaire: + +['*','-',5,2,6,None,None,None,None,None,None,None,None,None,None] + + +Le dessiner. Que peut-il représenter ? + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + +> Voici un code python Python qui crée la liste représentant l'arbre de l'exercice 2 + + + +```python +def creation_arbre(r,profondeur): + """r : la racine (str ou int). la profondeur de l’arbre (int)""" + Arbre = [r]+[None for i in range(2**(profondeur+1)-2)] + return Arbre + +def insertion_noeud(arbre,n,fg,fd): + """Insére les noeuds et leurs enfants dans l’arbre""" + indice = arbre.index(n) + arbre[2*indice+1] = fg + arbre[2*indice+2] = fd + +# création de l’arbre +arbre = creation_arbre("r",5) +# ajout des noeuds par niveau de gauche à droite +insertion_noeud(arbre,"r","a","b") +insertion_noeud(arbre,"a","c","d") +insertion_noeud(arbre,"b","e","f") +insertion_noeud(arbre,"c",None,"h") +insertion_noeud(arbre,"d","i","j") +insertion_noeud(arbre,"e","k",None) +insertion_noeud(arbre,"f",None,None) +insertion_noeud(arbre,"h",None,None) +insertion_noeud(arbre,"i",None,None) +insertion_noeud(arbre,"j","m",None) +insertion_noeud(arbre,"k",None,None) +insertion_noeud(arbre,"m",None,None) + +#pour vérifier +print(len(arbre)) +print(arbre) +``` + + 63 + ['r', 'a', 'b', 'c', 'd', 'e', 'f', None, 'h', 'i', 'j', 'k', None, None, None, None, None, None, None, None, None, 'm', None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None] + + +### Exercice 3: +1. Ecrire une fonction qui retourne le parent d'un noeud s'il est dans l'arbre et None sinon. +2. Ecrire une fonction qui retourne **True** si l'arbre est vide +3. Ecrire une fonction qui retourne les enfants d'un noeud. +4. Un fonction qui renvoie le fils gauche d'un noeud s'il existe et None sinon +5. Même question pour le fils droit +6. Ecrire une fonction qui renvoie **True** si le noeud est la racine de l'arbre +7. Ecrire une fonction qui renvoie **True** si le noeud est une feuille +8. Ecrire une fonction qui renvoie **true** si le noeud comporte un frère gauche ou droit. + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + +--------- + +## Une seconde façon de faire... + +Comme vous l'avez sans doute constaté, il est assez fastidieux de représenter un arbre avec un unique tableau surtout pour un arbre très profond. + +L'idée est de représenter l'arbre ave cun tableau contenant des tableaux + +![fig20.png](assets/fig20.png) + +Cet arbre se représente par le tableau: + +['r', ['a', [ ], [ ]], ['b', [ ], [ ]]] + +### Exercice : +Ecrire le tableau représentant l'arbre ci-dessous et le stocker dans une variable **t** + +![fig21.png](assets/fig21.png) + +**Le code Python ci-dessous, construit l'arbre de l'exercice 1 de manière récursive.** + +* Les noeuds sont représentés par un dictionnaire. +* L'arbre se construit depuis la racine en construisant les sous-arbres des fils gauche et droit. + + +```python +def noeud(nom, fg =None, fd =None): + return{'racine': nom, 'fg' : fg, 'fd': fd} + +# création des noeuds +k = noeud('k') +f = noeud('f') +e = noeud('e', k,None) +b = noeud('b', e, f) +m = noeud('m') +j = noeud('j', m,None) +i = noeud('i') +d = noeud('d', i, j) +h = noeud('h') +c = noeud('c',None, h) +a = noeud('a', c, d) +racine = noeud('r', a, b) +# création de l’arbre +def construit(arbre): + if arbre is None: + return [ ] + else: + return [arbre['racine'],construit(arbre['fg']),construit(arbre['fd'])] + +arbre1 = construit(racine) +print(arbre1) +``` + + ['r', ['a', ['c', [], ['h', [], []]], ['d', ['i', [], []], ['j', ['m', [], []], []]]], ['b', ['e', ['k', [], []], []], ['f', [], []]]] + + +### Exercice : +Ecrire toutes les fonctions de l'exercice 3 dans le cas de cette implémentation de l'arbre. + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + + +```python + +``` + +Nous allons maintenant nous intéresser à la hauteur de l'arbre, ainsi qu'aux différentes façons de le parcourir: +* Le parcours en largeur +* Le parcours en profondeur (parcours fixe, parcours infixe et parcours suffixe). + +**Calcul de la hauteur de l'arbre:** +L'idée ets la suivante: +* Si l'arbre ets vide, la hauteur vaut -1 +* Sinon la hauteur vaut 1 auquel il faut ajouter le maximum entre les hauteurs des sous arbres gauche et droit. +* Ces sous-arbres sont eux même des arbres dont il faut calculer la hauteur. + +Une méthode **récursive** semble donc tout à fait adaptée à la situation. + +Voici l'algorithme: + +![fig22.png](assets/fig22.png) + +### Exercice : +1. Ecrire cette fonction pour l'arbre précédent et vérifier que sa profondeur est de 4. +2. Reprenez l'arbre d ela question 4 de l'exercice 2. Stockez le dans une variable avec cette nouvelle méthode puis calculez sa profondeur. + + +```python + +``` + + +```python + +``` + +## Les parcours + +**Le parcours en largeur:** +Le parcours en largeur d'un arbre consiste à partir de la racine. On visite ensuite son fils gauche puis sont fils droit, puis le fils gauche du fils gauche etc... Comme le montre le schéma ci-dessous: + +![fig23.png](assets/fig23.png) + + +L'idée est la suivante: + +On utilise une File. +* On met l'arbre dans la file. +* Puis tant que la file n'est pas vide: + * On défile la file + * On récupère sa racine + * On enfile son fils gauche s'il existe + * on enfile son fils droit s'il existe + + +Voici l'algorithme: + +![fig25.png](assets/fig25.png) + +### Exercice 7 + +1. Rappeler les fonction permettant de définir une structure de file en python. +2. Implémenter alors cette fonction et l'essayer sur l'arbre précédent. + + +```python + +``` + + +```python + +``` + +**Les parcours en profondeur** +On se balade autour de l'arbre en suivant les pointillés + +![fig24.png](assets/fig24.png) + +Voici un algorithme permettant de réaliser ce parcours: +![fig26.png](assets/fig26.png) + +### Exercice +1. Proposer une fonction permettant de réaliser le parcours en profondeur d'un arbre + + +```python + +``` + +Dans le schéma ci-dessus, on a rajouté des "noeuds fantômes" pour montrer que l'on peut considérer que chaque noeud est visité trois fois: +* une fois par la gauche +* une fois par en dessous +* une fois par la droite + +### Definition: +Dans un parcours **prefixe**, on liste le noeud la première fois qu'on le rencontre. + + +### Exercice +1. Ecrire les sommets dans l'ordre d'un parcours préfixe + + + +### Definition: +Dans un parcours **infixe**, on liste le noeud la seconde fois qu'on le rencontre. + +Ce qui correspond à: +* On liste chaque noeud ayant un fils gauche la seconde fois qu'on le voit +* on liste chaque noeud sans fils gauche la première fois qu'on le voit + +### Exercice +1. Ecrire les sommets dans l'ordre d'un parcours infixe + + + +### Definition: +Dans un parcours **suffixe**, on note le noeud la dernière fois qu'on le rencontre. + +Exercice 11 +1. Ecrire les sommets dans l'ordre d'un parcours suffixe + + + +### Exercice +1. Voici trois algorithmes récursifs, dire pour chacun d'entre eux à quel parcours il correspond. +![fig27.png](assets/fig27.png) +![fig28.png](assets/fig28.png) +![fig29.png](assets/fig29.png) +2. Implémenter ces trois fonctions en python et confirmer les réponses des questions précédentes + +------- + +## Une troisième façon de faire.... en programmation objet + +Nous allons créer une classe **Noeud** dont les attributs d'instances seront: +* le nom (ou valeur) de la racine +* son fils gauche (None par défaut) ou de type Noeud +* son fils droit (None par défaut) ou de type Noeud + +### Exercice +1. Implémentez cette classe Noeud +2. Stocker l'arbre comme étant l'objet de type "Noeud" correspondant à la racine. +3. Ecrire une méthode estFeuille qui renvoie True si le noeud est une feuille et False sinon +4. Définir une fonction hauteur prenant comme argument un arbre permettant de renvoyer la hauteur de cet arbre +5. Ecrire une méthode hauteur dans la classe Noeud permettant de faire la même chose +6. Proposer des fonctions pour le parcours infixe, prefixe et suffixe pour cette façon de coder un arbre. +7. Transformer alors vos fonctions en méthodes de la classe Noeud + + +```python + +``` + +------- + +### Sources + +- [Cours de Stephan Van Zulen](https://www.nsi-ljm.fr/NSI-TLE/co/section_chapitre3.html) +- [Cours de Jeremy Camponovo](https://github.com/jcamponovo) diff --git a/arbres/assets/fig15.png b/arbres/assets/fig15.png new file mode 100644 index 0000000..36a453b Binary files /dev/null and b/arbres/assets/fig15.png differ diff --git a/arbres/assets/fig16.png b/arbres/assets/fig16.png new file mode 100644 index 0000000..c8050cc Binary files /dev/null and b/arbres/assets/fig16.png differ diff --git a/arbres/assets/fig17.png b/arbres/assets/fig17.png new file mode 100644 index 0000000..779a765 Binary files /dev/null and b/arbres/assets/fig17.png differ diff --git a/arbres/assets/fig18.png b/arbres/assets/fig18.png new file mode 100644 index 0000000..639ef7d Binary files /dev/null and b/arbres/assets/fig18.png differ diff --git a/arbres/assets/fig19.png b/arbres/assets/fig19.png new file mode 100644 index 0000000..c0ff17e Binary files /dev/null and b/arbres/assets/fig19.png differ diff --git a/arbres/assets/fig20.png b/arbres/assets/fig20.png new file mode 100644 index 0000000..37144cb Binary files /dev/null and b/arbres/assets/fig20.png differ diff --git a/arbres/assets/fig21.png b/arbres/assets/fig21.png new file mode 100644 index 0000000..4958226 Binary files /dev/null and b/arbres/assets/fig21.png differ diff --git a/arbres/assets/fig22.png b/arbres/assets/fig22.png new file mode 100644 index 0000000..638a374 Binary files /dev/null and b/arbres/assets/fig22.png differ diff --git a/arbres/assets/fig23.png b/arbres/assets/fig23.png new file mode 100644 index 0000000..761ec10 Binary files /dev/null and b/arbres/assets/fig23.png differ diff --git a/arbres/assets/fig24.png b/arbres/assets/fig24.png new file mode 100644 index 0000000..fe711fb Binary files /dev/null and b/arbres/assets/fig24.png differ diff --git a/arbres/assets/fig25.png b/arbres/assets/fig25.png new file mode 100644 index 0000000..6d542fa Binary files /dev/null and b/arbres/assets/fig25.png differ diff --git a/arbres/assets/fig26.png b/arbres/assets/fig26.png new file mode 100644 index 0000000..6defb39 Binary files /dev/null and b/arbres/assets/fig26.png differ diff --git a/arbres/assets/fig27.png b/arbres/assets/fig27.png new file mode 100644 index 0000000..583be59 Binary files /dev/null and b/arbres/assets/fig27.png differ diff --git a/arbres/assets/fig28.png b/arbres/assets/fig28.png new file mode 100644 index 0000000..723a1ac Binary files /dev/null and b/arbres/assets/fig28.png differ diff --git a/arbres/assets/fig29.png b/arbres/assets/fig29.png new file mode 100644 index 0000000..a11e862 Binary files /dev/null and b/arbres/assets/fig29.png differ