9. ABR (Arbre binaire de recherche)

Cf. TD4

Définition (ABR)

Soit un arbre binaire étiqueté par des valeurs qui peuvent être toujours comparées entre elles (i.e les valeurs sont donc des éléments d’un ensemble totalement ordonnés, par exemple les entiers).

On dit que c’est un arbre binaire de recherche si il vérifie :

Exemple

8 3 16 17 23 2 5 3 1 9 7
En partant d’un arbre vide, on veut ajouter la liste de nombres.
On commence par 8, on l’ajoute (ass(anul(), anul(), 8)
Ensuite on ajoute 3, on l’ajoute en suivant la définition de l’ABR, donc on l’ajoute sur la gauche.
Ensuite pour le 16, en comparant 8 et 16 on se rend compe que 16 est plus grand que 8 donc on va a droite et on le met sur la case vide.
Pour 17, on va a droite car 8 < 17 et 16 < 17.
Etc, on procède récursivement jusqu’à atteindre cet arbre :
exemple ABR

Remarque

Selon l’ordre d’ajout des éléments on peut obtenir des arbres différents, par exemple des arbres “file de fer”
exemple file de fer

Définition (profondeur d’un nœud)

Dans un arbre, la profondeur d’un noeud est le nombre de branche parcourues par un chemin entre la racine et ce nœud.

Définition (hauteur d’un arbre)

La hauteur d’un arbre est le maximum des profondeurs de ses nœuds.
exemple ABR profondeur
Le nombre maximale de nœuds d’un arbre de hauteur h est : 2^{h+1}-1

hauteur nb de nœud
0 1
1 3
2 7
h 2^{\ hauteur+1}-1

Implantation en C

typedef struct noeudABR {
    int entier;
    struct noeudABR * g;
    struct noeudABR * d;
    void * objet; // utile pour les dictionnaires
    int hauteur; // utile pour équilibrer les arbres (voir chapitre 10)
} NoeudABR;
typedef NoeudABR * ABR;

void ajouter(ABR * arbre; int val) {
    if (*arbre == NULL) {
        *arbre = (NoeudABR*)malloc(sizeof(NoeudABR));
        if (*arbre == NULL) exit(1);
        (*arbre) -> entier = val;
        (*arbre) -> g = NULL;
        (*arbre) -> d = NULL;
    } else {
        if ((*arbre) -> entier < val) {
            ajouter(&(*arbre) -> d, val);
        }
        if ((*arbre) -> entier > val) {
            ajouter(&(*arbre) -> g, val);
        }
        /*
            Dans cet exemple, on ne fait rien si on a une égalité
            entre `(*arbre) -> entier` et `val`.
        */
    }
}

Pour retirer une racine, on doit mettre à la place de l’arbre qu’on retire quelque chose :

-> On récupère la valeur maximale de l’arbre et on met cette dernière à la place de la racine (dans ce cas là)
explication extraction d’une racine

NoeudABR * ExtraireMax(ABR * a);
void       retirer(ABR * a, int val);