Arbres Binaires

Exercice 1 : (Vocabulaire des arbres)

https://onecompiler.com/cpp/434ywvv99

exo1-serie4

Exercice 2 : (Arbre binaire représenté en tableau)

Soit le tableau suivant qui représente un arbre binaire T en triplets (info, gauche, droit) :

2323571113374119
-143-1-19-186-1
-150-1-1--121-1-1

La première colonne (indice 0) représente le nœud dont le champ info est 23 (valeur du nœud), le champ gauche est -1 (indice du fils gauche) et le champ droit est -1 (indice du fils droit), La seconde colonne (indice 1) représente le nœud dont le champ info est 2, le champ gauche est 4 et le champ droit est 5, et ainsi de suite. La valeur (-1) indique l’absence d’un fils gauche ou droit.

  1. Dessiner l’arbre binaire T et donner sa taille.
  2. Donner le code C pour représenter l’arbre T de cette manière.
  3. Écrire une fonction qui détermine la racine de l’arbre T.
  4. Écrire une procédure qui liste toutes les feuilles de l’arbre T.
  5. Donner le résultat du parcours de l’arbre T :

I : en ordre infixé,
ii : en ordre préfixé, et
iii : en ordre postfixé.

Solution :

#include  <iostream>

using  namespace  std  ;

struct  Cell
{
    int  data   ;
    int  left   ;
    int  right  ;
};

typedef  struct Cell * ATree  ;

int  tree_root(ATree atree, int nbre)
{
    if(nbre <= 0)
        return  -1  ;

    bool*  root_array  =  new  bool[nbre]   ;

    for(int i = 0; i < nbre ; i++)
        root_array[i]  =  true  ;

    for(int i = 0; i < nbre ; i++)
    {
        if(atree[i].left != -1)
            root_array[atree[i].left]  =  false  ;

        if(atree[i].right != -1)
            root_array[atree[i].right]  =  false  ;
    }

    for(int i = 0; i < nbre ; i++)
        if(root_array[i])
            return  i  ;

    return  -1  ;
}

void  tree_leaves(ATree atree, int nbre)
{
    for(int i = 0; i < nbre ; i++)
        if((atree[i].left == -1)&&(atree[i].right == -1))
            cout  <<  "leaf : "  <<  atree[i].data  <<  endl  ;

    return  ;
}

int  main()
{
    Cell  atree[]  =  { {23, -1, -1}, {2, 4, 5}, {3, 3, 0}, {5, -1, -1}, {7, - 1, -1}, {11, 9, -1}, {13, -1, 2}, {37, 8, 1}, {41, 6, -1}, {19, -1, - 1} } ;

    cout  <<  "the root index is : "  <<  tree_root(atree, 10)  <<  endl  ;

    tree_leaves(atree, 10)  ;

    return  0  ;
}

Exercice 3 : (Implémenter les arbres binaires et leurs fonctions)

Dans un arbre binaire écrire (l’algorithme récursif) :

  1. une fonction qui calcule le nombre de noeuds.
  2. une fonction qui fait la somme des valeurs contenues.
  3. une fonction qui calcule le nombre de feuilles.
  4. une fonction qui calcule la hauteur.
  5. tester si un arbre est équilibré.
  6. fonction de parcours par niveau (en largeur)

Solution :

#include <iostream>
using  namespace  std  ;

///////////  Array tree structure definition  ///////////////

struct  Cell
{
    int  data   ;
    int  left   ;
    int  right  ;
};

typedef  struct Cell * ATree  ;

int  tree_root(ATree atree, int nbre)
{
    if(nbre <= 0)
        return  -1  ;

    bool*  root_array  =  new  bool[nbre]   ;

    for(int i = 0; i < nbre ; i++)
        root_array[i]  =  true  ;

    for(int i = 0; i < nbre ; i++)
    {
        if(atree[i].left != -1)
            root_array[atree[i].left]  =  false  ;

        if(atree[i].right != -1)
            root_array[atree[i].right]  =  false  ;
    }

    for(int i = 0; i < nbre ; i++)
        if(root_array[i])
            return  i  ;

    return  -1  ;
}

///////////  Tree structure definition  ///////////////

struct  node
{
    int           data   ;
    struct node * left   ;
    struct node * right  ;
};

typedef  struct node *  Tree  ;

///////////  Queue structure definition  ///////////////

struct  element
{
    Tree   node  ;
    struct element * next  ;
};

typedef  struct element * Queue  ;

Queue  create_queue()
{
    return  NULL  ;
}

bool  is_empty_queue(Queue que)
{
    if(que == NULL)
        return  true  ;
    else
        return  false ;
}

Queue  enqueue(Queue que, Tree node)
{
    Queue  elm  =  new  element  ;
    elm->node   =  node   ;
    elm->next   =  NULL  ;

    if(is_empty_queue(que))
    {
        que  =  elm  ;
        return  que  ;
    }

    Queue  ptr  =  que  ;

    while(ptr->next != NULL)
        ptr  =  ptr->next  ;

    ptr->next  =  elm  ;

    return  que  ;
}

Queue  dequeue(Queue que, Tree &node)
{
    if(!is_empty_queue(que))
    {
        Queue  ptr  =  que  ;

        node =  que->node ;
        que  =  que->next  ;
        delete  ptr        ;

        return  que  ;
    }
    else
    {
        cout  <<  "Error, the queue is already empty."  <<  endl  ;
        return  NULL  ;
    }
}

Tree  create_tree(ATree atree, int root)
{
    if(root == -1)
        return  NULL  ;

    Tree  ptr  =  new  node  ;

    ptr->data   =  atree[root].data  ;
    ptr->left   =  create_tree(atree, atree[root].left)   ;
    ptr->right  =  create_tree(atree, atree[root].right)  ;

    return  ptr  ;
}

void  postfix_display(Tree tree)
{
    if(tree != NULL)
    {
        postfix_display(tree->left)    ;
        postfix_display(tree->right)   ;
        cout  <<  " "  <<  tree->data  ;
    }

    return  ;
}

void  prefix_display(Tree tree)
{
    if(tree != NULL)
    {
        cout  <<  " "  <<  tree->data  ;
        prefix_display(tree->left)     ;
        prefix_display(tree->right)    ;
    }

    return  ;
}

void  infix_display(Tree tree)
{
    if(tree != NULL)
    {
        infix_display(tree->left)      ;
        cout  <<  " "  <<  tree->data  ;
        infix_display(tree->right)     ;
    }

    return  ;
}

int  nodes_number(Tree tree)
{
    if(tree == NULL)
    {
        return  0  ;
    }
    else
    {
        return  1 + nodes_number(tree->left) + nodes_number(tree->right)  ;
    }
}

int  nodes_sum(Tree tree)
{
    if(tree == NULL)
    {
        return  0  ;
    }
    else
    {
        return  tree->data + nodes_sum(tree->left) + nodes_sum(tree->right)  ;
    }
}

int  leaves_number(Tree tree)
{
    if(tree == NULL)
        return  0  ;

    if((tree->left == NULL)&&(tree->right == NULL))
    {
        return  1  ;
    }
    else
    {
        return  leaves_number(tree->left) + leaves_number(tree->right)  ;
    }
}

int  tree_height(Tree tree)
{
    if(tree == NULL)
    {
        return  0  ;
    }
    else
    {
        return  1 + max(tree_height(tree->left), tree_height(tree->right))  ;
    }
}

bool  balanced_tree(Tree tree)
{
    if(tree == NULL)
        return  true  ;

    if(abs(tree_height(tree->left) - tree_height(tree->right)) > 1)
        return  false  ;
    else
        return  balanced_tree(tree->left) && balanced_tree(tree->right)  ;
}

void  by_level_display(Tree tree)
{
    Queue  que  =  create_queue()  ;

    if(tree == NULL)
    {
        cout  <<  "Tree is empty."  <<  endl  ;
        return  ;
    }

    que  =  enqueue(que, tree)  ;

    while(!is_empty_queue(que))
    {
        Tree  ptr  ;

        que  =  dequeue(que, ptr)  ;

         cout  <<  ptr->data  <<  " "  ;

         if(ptr->left != NULL)
            que  =  enqueue(que, ptr->left)   ;

         if(ptr->right != NULL)
            que  =  enqueue(que, ptr->right)  ;
    }

    cout  <<  endl  ;

    return  ;
}

int  main()
{
    Cell  atree[]  =  { {23, -1, -1}, {2, 4, 5}, {3, 3, 0}, {5, -1, -1}, {7, - 1, -1}, {11, 9, -1}, {13, -1, 2}, {37, 8, 1}, {41, 6, -1}, {19, -1, - 1} } ;

    Tree  tree  =  create_tree(atree, tree_root(atree, 10))  ;

    postfix_display(tree)  ;  cout  <<  endl  ;
    prefix_display(tree)   ;  cout  <<  endl  ;
    infix_display(tree)    ;  cout  <<  endl  ;

    cout  <<  "The number of nodes on the tree is : "   <<  nodes_number(tree)   <<  endl  ;
    cout  <<  "The sum of nodes on the tree is : "      <<  nodes_sum(tree)      <<  endl  ;
    cout  <<  "The number of leaves on the tree is : "  <<  leaves_number(tree)  <<  endl  ;
    cout  <<  "The height/depth of the tree is : "      <<  tree_height(tree)    <<  endl  ;

    if(balanced_tree(tree))
        cout <<  "The tree is balanced."      <<  endl  ;
    else
        cout <<  "The tree is not balanced."  <<  endl  ;

    by_level_display(tree)  ;


    return  0  ;
}

Exercice 4 : (Évaluation d’expression arithmétique)

a. Donner une fonction récursive pour évaluer une expression arithmétique sous la forme d’un arbre binaire.
b. Une autre pour imprimer l’expression infixe parenthésée.

Solution :

#include <iostream>

using  namespace  std  ;

struct  Node
{
    int           operand    ;
    char          operation  ;
    struct Node * left   ;
    struct Node * right  ;
};

typedef  struct Node *  Tree  ;

void  postfix_display(Tree tree)
{
    if(tree != NULL)
    {
        postfix_display(tree->left)    ;
        postfix_display(tree->right)   ;
        if(tree->operation == '\0')
            cout  <<  " "  <<  tree->operand    ;
        else
            cout  <<  " "  <<  tree->operation  ;
    }

    return  ;
}

void  prefix_display(Tree tree)
{
    if(tree != NULL)
    {
        if(tree->operation == '\0')
            cout  <<  " "  <<  tree->operand    ;
        else
            cout  <<  " "  <<  tree->operation  ;
        prefix_display(tree->left)     ;
        prefix_display(tree->right)    ;
    }

    return  ;
}

void  expression_infix_display(Tree tree)
{
    if(tree != NULL)
    {
        if((tree->left == NULL)&&(tree->right == NULL))
        {
            expression_infix_display(tree->left)   ;
            cout  <<  tree->operand                ;
            expression_infix_display(tree->right)  ;
        }
        else
        {
            cout  <<  '('                          ;
            expression_infix_display(tree->left)   ;
            cout  <<  tree->operation              ;
            expression_infix_display(tree->right)  ;
            cout  <<  ')'                          ;
        }
    }

    return  ;
}

int  expression_evaluation(Tree tree)
{
    if((tree->left == NULL)&&(tree->right == NULL))
        return  tree->operand  ;
    else
    {
        switch(tree->operation)
        {
            case '+' : return  expression_evaluation(tree->left) + expression_evaluation(tree->right)  ;
            case '-' : return  expression_evaluation(tree->left) - expression_evaluation(tree->right)  ;
            case '*' : return  expression_evaluation(tree->left) * expression_evaluation(tree->right)  ;
            case '/' : return  expression_evaluation(tree->left) / expression_evaluation(tree->right)  ;
        }
    }
}

int  main()
{
    Tree  n0  =  new  Node  ;

    n0->operation  =  '*'  ;
    n0->operand    =  0    ;

    Tree  n11  =  new  Node  ;

    n11->operation  =  '\0'  ;
    n11->operand    =  3     ;

    Tree  n12  =  new  Node  ;

    n12->operation  =  '/'  ;
    n12->operand    =  0    ;

    Tree  n21  =  new  Node  ;

    n21->operation  =  '+'  ;
    n21->operand    =  0    ;

    Tree  n22  =  new  Node  ;

    n22->operation  =  '\0'  ;
    n22->operand    =  2     ;

    Tree  n31  =  new  Node  ;

    n31->operation  =  '\0'  ;
    n31->operand    =  5     ;

    Tree  n32  =  new  Node  ;

    n32->operation  =  '\0'  ;
    n32->operand    =  1     ;

    n0->left   =  n11  ;
    n0->right  =  n12  ;

    n11->left   =  NULL  ;
    n11->right  =  NULL  ;

    n12->left   =  n21  ;
    n12->right  =  n22  ;

    n21->left   =  n31  ;
    n21->right  =  n32  ;

    n22->left   =  NULL  ;
    n22->right  =  NULL  ;

    n31->left   =  NULL  ;
    n31->right  =  NULL  ;

    n32->left   =  NULL  ;
    n32->right  =  NULL  ;

    postfix_display(n0)  ;  cout  <<  endl  ;
    prefix_display(n0)   ;  cout  <<  endl  ;

    cout  <<  "3*((5+1)/2) = "   <<  expression_evaluation(n0)   <<  endl  ;

    expression_infix_display(n0)  ;

    return  0  ;
}

Exercice 5 : (Arbre binaire de recherche)

  1. Dessiner l’arbre binaire de recherche obtenu en insérant les éléments de la liste suivante dans leur ordre d’arrivée: 30, 40, 23, 58, 48, 26, 11, 13, 20
  2. Donner le résultat des parcours préfixe, infixe et postfixe de l’arbre précédent
  3. Donner l’arbre précédent après la suppression des clés suivantes : 48 puis 23.
  4. Donner l’arbre précédent (avant la suppression) après l’ajout des clés suivantes : 60 puis 17.

Solution :

exo5-serie4