Une classe pour représenter un arbre

On utilise une classe pour représenter un arbre binaire avec pour objectif de pouvoir afficher cet arbre, de calculer la profondeur maximale ou moyenne, de compter le nombre de chemin, d’itérer sur tous les noeuds.

Premier jet

[2]:
class Noeud:
    def __init__(self, v):
        self.v = v
        self.left = None
        self.right = None


na = Noeud("A")
na.left = Noeud("B")
na.left.left = Noeud("C")
na.left.right = Noeud("D")
na.right = Noeud("E")

Afficher l’arbre

C’est toujours très utile pour vérifier que l’arbre qu’on a implémenté est bien celui qu’on avait en tête. Il faut donc parcourir tous les noeuds.

[3]:
import textwrap


def graph():
    na = Noeud("A")
    na.left = Noeud("B")
    na.left.left = Noeud("C")
    na.left.right = Noeud("D")
    na.right = Noeud("E")
    return na


class Noeud:
    def __init__(self, v):
        self.v = v
        self.left = None
        self.right = None

    def __str__(self):
        rows = [str(self.v)]
        if self.left is not None:
            rows.append("+-" + textwrap.indent(str(self.left), "  ")[2:])
        if self.right is not None:
            rows.append("+-" + textwrap.indent(str(self.right), "  ")[2:])
        return "\n".join(rows)


na = graph()
print(na)
A
+-B
  +-C
  +-D
+-E

Profondeur maximale : le plus grand chemin depuis la racine jusqu’aux feuilles

[6]:
class Noeud:
    def __init__(self, v):
        self.v = v
        self.left = None
        self.right = None

    def __str__(self):
        rows = [str(self.v)]
        if self.left is not None:
            rows.append("+-" + textwrap.indent(str(self.left), "  ")[2:])
        if self.right is not None:
            rows.append("+-" + textwrap.indent(str(self.right), "  ")[2:])
        return "\n".join(rows)

    def profondeur_maximale(self):
        pleft = 0 if self.left is None else self.left.profondeur_maximale() + 1
        pright = 0 if self.right is None else self.right.profondeur_maximale() + 1
        return max(pleft, pright)


na = graph()
print(na.profondeur_maximale())
2

Profondeur moyenne ?

L’astuce est souvent la même : il faut calculer la moyenne au dernier moment et jusqu’à ce moment-là, on conserve la somme et le compte. On divise les deux à la fin. Il reste une ambiguïté, est-ce qu’un noeud ayant une feuille à gauche ou droite mais une seul feuille est-il considéré comme une feuille également ? Une demi-feuille ? C’est une convention à choisir en fonction de l’usage qui est fait de cette moyenne. Certaines expressions n’existent pas en mathématique comme \(0^0\), est-ce que cela vaut 0, 1, ou \(\infty\) ? Ce choix vous est laissé. Dans le cas, présent, l’implémentation de la fonction fait qu’un noeud n’ayant qu’un fils est une demi-feuille.

[2]:
import textwrap


def graph():
    na = Noeud("A")
    na.left = Noeud("B")
    na.left.left = Noeud("C")
    na.left.right = Noeud("D")
    na.right = Noeud("E")
    return na


class Noeud:
    def __init__(self, v):
        self.v = v
        self.left = None
        self.right = None

    def __str__(self):
        rows = [str(self.v)]
        if self.left is not None:
            rows.append("+-" + textwrap.indent(str(self.left), "  ")[2:])
        if self.right is not None:
            rows.append("+-" + textwrap.indent(str(self.right), "  ")[2:])
        return "\n".join(rows)

    def profondeur_maximale(self):
        pleft = 0 if self.left is None else self.left.profondeur_maximale() + 1
        pright = 0 if self.right is None else self.right.profondeur_maximale() + 1
        return max(pleft, pright)

    def profondeur_somme_count(self):
        somme = 0
        count = 0
        if self.left is None:
            count += 0.5
        else:
            sleft, cleft = self.left.profondeur_somme_count()
            somme += sleft + cleft
            count += cleft
        if self.right is None:
            count += 0.5
        else:
            sright, cright = self.right.profondeur_somme_count()
            somme += sright + cright
            count += cright
        return somme, count


na = graph()
somme, count = na.profondeur_somme_count()
print(somme, count, somme / count)
5.0 3.0 1.6666666666666667

Intermède : is ou == ?

[1]:
class bizarre:
    def __eq__(self, a):
        return False


b = bizarre()
print(b is b, b == b)
True False
[ ]:


Notebook on github