type ('f, 'n) arbre =
| Feuille of 'f
| NoeudInterne of ('f, 'n) arbre * 'n * ('f, 'n) arbre
;;
let arbre =
NoeudInterne (Feuille 2, 1, NoeudInterne (Feuille 4, 3, Feuille 5))
;;
let rec symetrique arbre =
match arbre with
| Feuille _ -> arbre
| NoeudInterne (fils_gauche, noeud, fils_droit) ->
NoeudInterne (symetrique fils_droit, noeud, symetrique fils_gauche)
;;
symetrique arbre;;
1.
let rec initialise_complet n val_f val_n =
match n with
| 0 -> Feuille val_f
| _ -> let arbre = initialise_complet (n - 1) val_f val_n in
NoeudInterne (arbre, val_n, arbre)
;;
initialise_complet 2 1 0;;
2.
Un arbre complet de hauteur $n$ a $2^n$ feuilles de profondeur $n$ chacune. Son cheminement est donc de $n2^n$.
1.
let rec strahler arbre =
match arbre with
| Feuille _ -> 1
| NoeudInterne(fils_gauche, _, fils_droit) ->
let s_g = strahler fils_gauche in
let s_d = strahler fils_droit in
if s_g = s_d then
s_g + 1
else
max s_g s_d
;;
let arbre2 =
let sous_arbre = initialise_complet 2 0 0 in
NoeudInterne(
NoeudInterne(
sous_arbre,
0,
NoeudInterne(
sous_arbre,
0,
Feuille 0
)
),
0,
Feuille 0
)
;;
strahler arbre2;;
2.
Par récurrence sur $h\in\mathbb N$.
On peut aussi raisonner par induction structurelle.
3.
Un arbre de hauteur $h\neq0$ possède au moins un noeud interne, donc au moins un noeud avec deux feuilles qui aura $2$ comme nombre de Strahler. Comme le nombre de Strahler d'un noeud est toujours au moins aussi grand que ceux de ses fils, un arbre de hauteur $h\neq0$ a bien un nombre de Strahler au moins égal à $2$.
De plus, ce nombre sera égal à $2$ si et seulement si tous les noeuds internes ont un nombre de Strahler de $2$ (toujours vu la propriété de croissance). Cela signifie que chaque noeud interne doit avoir un fils dont le nombre de Strahler vaut $1$ et un fils dont le nombre de Strahler vaut $2$, ce qui correspond bien au type d'arbre décrit dans la question.
type ('f, 'n) noeud = F of 'f | NI of 'n;;
1.
NoeudInterne
code à l'arbre (triplet (fils gauche, étiquette, fils droit)) issu du noeud alors que NI
code seulement à l'étiquette du noeud.
2.
[NI 1; F 2; NI 3; F 4; F 5]
[F 2; NI 1; F 4; NI 3; F 5]
[F 2; F 4; F 5; NI 3; NI 1]
[NI 1; NI 3; F 5; F 4; F 2]
[F 5; NI 3; F 4; NI 1; F 2]
[F 5; F 4; NI 3; F 2; NI 1]
3.
let rec parcours_prefixe arbre =
match arbre with
| Feuille f -> [F f]
| NoeudInterne(fils_gauche, noeud, fils_droit) ->
(NI noeud) :: (parcours_prefixe fils_gauche) @ (parcours_prefixe fils_droit)
;;
parcours_prefixe arbre;;
parcours_prefixe (symetrique arbre);;
Version sans @
(liste chaînée utilisée comme pile)
let parcours_prefixe_bis arbre =
(* (parcours_prefixe arbre) @ liste est un invariant de aux *)
let rec aux arbre liste =
match arbre with
| Feuille f -> (F f) :: liste
| NoeudInterne(fils_gauche, noeud, fils_droit) ->
(NI noeud) :: (aux fils_gauche (aux fils_droit liste))
in
aux arbre []
;;
parcours_prefixe_bis arbre;;
parcours_prefixe_bis (symetrique arbre);;
4.
Chaque concaténation a un coût de $O(n)$ et il y a $n$ noeuds visités une et une seule fois donc la complexité est en $O(n^2)$. Cette complexité est atteinte lorsque chaque noeud interne a pour fils droit une feuille.
5.
let rec parcours_infixe arbre =
match arbre with
| Feuille f -> [F f]
| NoeudInterne(fils_gauche, noeud, fils_droit) ->
(parcours_infixe fils_gauche) @ ((NI noeud) :: parcours_infixe fils_droit)
;;
parcours_infixe arbre;;
parcours_infixe (symetrique arbre);;
let parcours_infixe_bis arbre =
(* (parcours_infixe arbre) @ liste est un invariant de aux *)
let rec aux arbre liste =
match arbre with
| Feuille f -> (F f) :: liste
| NoeudInterne(fils_gauche, noeud, fils_droit) ->
aux fils_gauche ((NI noeud) :: (aux fils_droit liste))
in
aux arbre []
;;
parcours_infixe_bis arbre;;
parcours_infixe_bis (symetrique arbre);;
let rec parcours_suffixe arbre =
match arbre with
| Feuille f -> [F f]
| NoeudInterne(fils_gauche, noeud, fils_droit) ->
(parcours_suffixe fils_gauche) @ (parcours_suffixe fils_droit) @ [NI noeud]
;;
parcours_suffixe arbre;;
parcours_suffixe (symetrique arbre);;
let parcours_suffixe_bis arbre =
(* (parcours_infixe arbre) @ liste est un invariant de aux *)
let rec aux arbre liste =
match arbre with
| Feuille f -> (F f) :: liste
| NoeudInterne(fils_gauche, noeud, fils_droit) ->
aux fils_gauche ( aux fils_droit ((NI noeud) :: liste))
in
aux arbre []
;;
parcours_suffixe_bis arbre;;
parcours_suffixe (symetrique arbre);;
6.
On trouve l'arbre :
. 1
/ \
2 4
/ \
4 5
NoeudInterne (NoeudInterne (Feuille 4, 2, Feuille 5), 1, Feuille 4)
7.
let reconstruire_prefixe liste_parcours =
(* Renvoie l'arbre construit à partir du début de la
liste et la liste de ce qu'il reste à construire *)
let rec construction_partielle liste =
match liste with
| [] -> failwith "Cette liste ne correspond pas à un parcours préfixe d'un arbre"
| (F f) :: suite -> (Feuille f, suite)
| (NI n) :: suite ->
let fils_gauche, suite_apres_gauche = construction_partielle suite in
let fils_droit, suite_apres_droit = construction_partielle suite_apres_gauche in
(NoeudInterne (fils_gauche, n, fils_droit), suite_apres_droit)
in
let resultat, reste = construction_partielle liste_parcours in
match reste with
| [] -> resultat
| _ -> failwith "Cette liste ne correspond pas à un parcours préfixe d'un arbre"
;;
reconstruire_prefixe [NI 1; F 2; NI 3; F 4; F 5];;
reconstruire_prefixe [NI 1; NI 3; F 5; F 4; F 2];;
reconstruire_prefixe [F 5; F 4; NI 3; F 2; NI 1];;
8.
Les arbres suivants ont même parcours infixe.
. 1
/ \
2 5
/ \
3 4
et
. 2
/ \
3 1
/ \
4 5