typedef struct cell { int va; struct cell *ga,*dr; } *BST;
Écrire les fonctions
BST new_BST(int n,BST g,BST d);
BST insert(int n,BST b);
int height(BST b);
int size(BST b);
void prefix(BST b);
à savoir respectivement : un constructeur d'arbre binaire de
recherche, une fonction d'insertion aux feuilles de la valeur
n, une fonction de calcul de la hauteur de l'arbre, une
fonction de calcul de sa taille, et une fonction d'affichage des
valeurs de l'arbre le long d'un parcourt préfixe gauche. La fonction
d'insertion parcourera récursivement l'arbre b en cheminant
de la racine vers les feuilles et renverra l'arbre modifié.
On se convainc aisément que si l'on insère successivement des entiers 1, 2, ..., N à partir de l'arbre vide, l'arbre obtenu est très déséquilibré et de hauteur N. La recherche dans un tel arbre coûte donc en moyenne O(N) unités de temps. Le vérifier expérimentalement.
On a ainsi besoin d'un nouveau type pour représenter les paires d'arbres,
typedef struct pair { BST ga; BST dr; } *Pair;
et on demande d'écrire les fonctions
Pair split(int n,BST b);
BST root_insert(int n,BST b);
de séparation (qui sera récursive) et d'insertion à la racine.
Ici encore, vérifier expérimentalement que si l'on insère successivement des entiers 1, 2, ..., N à partir de l'arbre vide, l'arbre obtenu est très déséquilibré et de hauteur N, d'où une recherche en temps moyen O(N).
Plus précisément, on ajoute à chaque sommet l'information de la taille d'un des deux sous-arbres, ainsi que de celui sous-arbres dont on a la taille. Toutes les opérations récursives mettent à jour ces informations. On obtient ainsi les nouveaux types
typedef enum orientation { GAUCHE, DROITE } Orientation;
typedef struct scell {
int va,ta;
Orientation or;
struct scell *ga,*dr; } *sBST;
typedef struct spair { int ta; Orientation or; sBST ga; sBST dr; } *sPair;
La raison pour ne conserver la taille d'un seul des deux sous-arbres
est d'éviter, après une insertion à une feuille, d'avoir à
rétropropager l'incrémentation de la taille. Il faut donc aussi se
doter d'une variable globale taille pour sauvegarder la
taille de l'arbre dans lequel on opère récursivement.
Recopier et modifier les fonctions des questions précédentes de façon à écrire des fonctions
sBST new_sBST(int n,int t,Orientation o,sBST g,sBST d);
sBST sinsert(int n,sBST b,int t);
int sheight(sBST b);
void sprefix(sBST b,int t);
sPair new_sPair(int t,Orientation o,sBST g,sBST d);
sPair ssplit(int n,sBST b,int t);
sBST root_sinsert(int n,sBST b,int t);
opérant sur les nouvelles structures de données. Dans les cas où une
orientation o fait partie des entrées, t est la
taille du sous-arbre ou de l'élément de la paire indiqué par cette
orientation. Dans les autres cas, t est la taille de l'arbre
b.
Implanter la fonction randomisée
sBST randomized_sinsert(int n,sBST b,int t);
et vérifier expérimentalement que l'insertion successive des entiers
1, 2, ..., N à partir de l'arbre vide fournit un arbre
déséquilibré de hauteur O(ln2N), d'où une
recherche en temps moyen O(ln2N).