Conception de structures de donn´ ees
Cours 6 Arbres binaires
22 avril 2013
Struct 1/30
Pourquoi les arbres ?
Structure de donn´ees omnipr´esente en Informatique :
structure naturelle : arbre de d´ecision, tournoi, g´en´ealogie, arborescence des r´epertoires, expressions arithm´etiques, ...
en algorithmique du texte (Huffamn, prefix-trees) :
compression, recherche de motifs, d´etection de r´ep´etitions, ...
en g´eom´etrie algorithmique (quadtrees, octrees, KD-trees, arbres rouge-noir, ...) ;
en linguistique et en compilation (arbres syntaxiques) ; pour la gestion du cache, les bases de donn´ees, les syst`emes de fichiers, ... (B-trees,).
Struct 2/30
Type abstrait Implantation Arbres modifiables Extensions
D´ efinition des arbres BINAIRES
Un arbre binaireest une structure permettant de stocker une collection de donn´ees de mˆeme type.
D´efinition r´ecursive : un arbre binaire est : soit vide,
soit un noeudcontenant une donn´ee et ayant 2 fils(gaucheet droit) qui sont eux-mˆemes des arbres binaires.
L’espace m´emoire utilis´e par un arbre n’est pas contigu.
La taille d’un arbre est inconnue `a priori ;
Un arbre binaireest constitu´e de noeudsqui sont li´es entre eux par des pointeurs. On ne peut acc´eder directement qu’au 1er ´el´ement (la racine) de l’arbre.
Pour acc´eder `a un ´el´ement quelconqued’un arbre , il faut descendre dans l’arbre jusqu’`a cet ´el´ement.
! ! ! Un arbre n’est PAS une structure LIN´EAIRE ! ! !
Type abstrait Implantation Arbres modifiables Extensions
Repr´ esentation graphique d’un arbre binaire
3
1 8
1 29 170
2 48
Arbres binaires r´ ecursifs
Struct 5/30
Type abstrait : BTree
typedef ... BTree;
BTree makeEmptyBTree(void); // renvoie un arbre vide int isEmptyBTree(BTree bt); // teste si l’arbre est vide
BTree makeNode(Element e, Btree l, Btree r);
// renvoie un arbre de racine e ayant l et r pour fils gauche et droit Element root(BTree bt); // renvoie l’´el´ement `a la racine de l’arbre BTree leftChild(BTree bt); // renvoie le fils gauche de l’arbre BTree rightChild(BTree bt); // renvoie le fils droit de l’arbre
BTree makeLeaf(Element e); // renvoie une feuille contenant l’´el´ement e int isLeaf(BTree bt); // teste si bt est une feuille
void freeNode(Btree bt); // lib`ere l’espace occup´e par la racine de bt
Struct 6/30
Type abstrait Implantation Arbres modifiables Extensions
Ecrire une fonction r´ ´ ecursive sur les arbres.
Fonction r´ecursive fonctionRec sur une arbre (bt) : Cas de base :
isEmptyBTree(bt) /* arbre vide */
isLeaf(bt) /* arbre r´eduit `a une feuille */
Cas g´en´eral (r´ecursif) : r´esoudre le probl`eme sur des arbres plus petits (les sous-arbres gauche et droit) et combiner les solutions.
fonctionRec(leftChild(bt)) fonctionRec(rightChild(bt))
/* combiner les deux (´eventuellement avec la racine)*/
Type abstrait Implantation Arbres modifiables Extensions
Exemples
Calculer la taille (nombre de noeuds) de l’arbre ; Lib´erer l’espace m´emoire occup´e par l’arbre ; Afficher l’arbre ;
Renvoyer la liste des feuilles de l’arbre ;
Calculer la hauteur, la somme des ´el´ements, la longueur de cheminement, le nombre de Strahler ...
Compter le nombre de noeuds (ou de feuilles) `a hauteur k, Tester l’´egalit´e, l’isomorphisme, l’inclusion de 2 arbres, ...
Fabriquer une copie ou le miroir d’un arbre, ...
Chercher un ´el´ement quelconque, le min (ou max), le premier ancˆetre commun de 2 noeuds, ...
Les fonctions size et freeBTree
int size(BTree bt){
if(isEmptyBTree(bt)) return 0;
else return 1+size(leftChild(bt))+size(rightChild(bt));
}
void freeBTreeRec(BTree bt){ /* fonction r´ecursive */
if(!isEmptyBTree(bt)){
BTree l=leftChild(bt); /* liens vers les fils */
BTree r=rightChild(bt);
freeNode(bt); /* lib´erer le noeud */
freeBTreeRec(l); /* lib´erer les fils r´ecursivement */
freeBTreeRec(r);
} }
/* fonction non r´ecursive */
void freeBTree(BTree *bt){ freeBTreeRec(*bt); *bt= NULL;}
Struct 9/30
La fonction printBTree
void shift(int n){
int i;
for(i = 0;i < n;i++) printf("\t");
}
void printBTree(BTree bt, int level){
if ( !isEmptyBTree(bt) ) {
printBTree( rightChild(bt), level+1 );
shift(level);
printf("%d\n", root(bt));
printBTree( leftChild(bt), level+1 );
} }
Struct 10/30
Type abstrait Implantation Arbres modifiables Extensions
La fonction listOfLeaves
/* concat´enation de 2 listes */
Rlist append(Rlist l1, Rlist l2){ ... }
Rlist listOfLeaves(BTree bt){
if( isEmptyBTree(bt) ) return newEmptyRlist();
else
if( isLeaf(bt) )
return cons( root(bt) , newEmptyRlist() );
else{
Rlist ll=listOfLeaves( leftChild(bt) );
Rlist lr=listOfLeaves( rightChild(bt) );
} return append( ll , lr );
}
Type abstrait Implantation Arbres modifiables Extensions
Parcourir un arbre en profondeur
La structure d’arbre n’impose pas un ordre total sur les
´el´ements, or on voudrait avoir un ordre sur ces ´el´ements.
Pour cela, on fixe une m´ethode de parcours de l’arbre qui trie les ´el´ements par orde de visite.
11
8 7
10
1 5
0 6 2
9
3
4
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
4
Struct 13/30
Parcours infixe (la racine au milieu)
11
8 7
10
1 5
0 6 2
9
3
4
Struct 14/30
Type abstrait Implantation Arbres modifiables Extensions
Parcours postfixe (la racine en dernier)
11
8 7
10
1 5
0 6 2
9
3
4
Type abstrait Implantation Arbres modifiables Extensions
Les 3 fonctions de parcours
void printPrefixOrder(BTree bt){
if(!isEmptyBTree(bt)){
printf("%d ",root(bt));
printPrefixOrder(leftChild(bt));
printPrefixOrder(rightChild(bt));
} }
void printInfixOrder(BTree bt){
if(!isEmptyBTree(bt)){
printInfixOrder(leftChild(bt));
printf("%d ",root(bt));
printInfixOrder(rightChild(bt));
} }
void printPostfixOrder(BTree bt){ ... }
Et une version it´erative ? Et le parcours en largeur ?
Arbres binaires en C
Struct 17/30
D´ efinition d’un arbre binaire en C
arbre vide:
3
1 8
1 29 170
2 48
arbre contenant 8 éléments
Struct 18/30
Type abstrait Implantation Arbres modifiables Extensions
D´ efinition d’un arbre binaire en C (suite)
typedef int Element;
typedef struct node{
Element elem;
struct node *left;
struct node *right;
}Node;
typedef Node *BTree;
BTree makeEmptyBTree(void){
return (BTree)NULL;
}
int isEmptyBTree(BTree bt){
return (bt==NULL);
}
Type abstrait Implantation Arbres modifiables Extensions
D´ efinition d’un arbre binaire en C (suite)
BTree makeNode(Element e, BTree l, BTree r){
BTree new;
if ((new=(BTree)malloc(sizeof(Node)))==NULL) erreur("Allocation rat´ee!");
new->elem=e;
new->left=l;
new->right=r;
return new;
}
BTree makeLeaf(Element e){
return makeNode(e,makeEmptyBTree(),makeEmptyBTree());
}
Element root(BTree bt){
if(isEmptyBTree(bt))
erreur("Pas de noeud `a la racine!");
return bt->elem;
}
D´ efinition d’un arbre binaire en C (suite)
BTree leftChild(BTree bt){
if(isEmptyBTree(bt)) erreur("Pas de fils gauche!");
return bt->left;
}
BTree rightChild(BTree bt){
if(isEmptyBTree(bt)) erreur("Pas de fils droit!");
return bt->right;
}
int isLeaf(BTree bt){
return !isEmptyBTree(bt) &&
isEmptyBTree(leftChild(bt)) &&
isEmptyBTree(rightChild(bt));
}
void freeNode(Node *c){
free(c);
}
Struct 21/30
Arbres binaires modifiables
Struct 22/30
Type abstrait Implantation Arbres modifiables Extensions
Quelques fonctions de modification
Fonctions “bas niveau” pour ins´erer ou supprimer des ´el´ements dans un arbre :
void insertRight(Node *n, Element e);
void insertLeft(Node *n, Element e);
Element deleteRight(Node *n);
Element deleteLeft(Node *n);
void insertRightmostNode(BTree *bt, Element e);
void insertLeftmostNode(BTree *bt, Element e);
Element deleteRightmostNode(BTree *bt);
Element deleteLeftmostNode(BTree *bt);
Attention : ces fonctions modifient les arbres ; elles ne fabriquent pas des copies!
Type abstrait Implantation Arbres modifiables Extensions
Quelques fonctions de modification
void insertRight(Node *n, Element e){
if(!isEmptyBTree(n) && isEmptyBTree(rightChild(n))) n->right=makeLeaf(e);
else erreur("insertRight impossible!");
}
void insertLeft(Node *n, Element e){
if(!isEmptyBTree(n) && isEmptyBTree(leftChild(n))) n->left=makeLeaf(e);
else erreur("insertLeft impossible!");
}
Element deleteRight(Node *n){
if(isEmptyBTree(n) || !isLeaf(rightChild(n))) erreur("deleteRight imossible!");
Element res=root(n->right);
n->right=makeEmptyBTree();
return res;
}
Quelques fonctions de modification
Element deleteLeft(Node *n){
if(isEmptyBTree(n) || !isLeaf(leftChild(n))) erreur("deleteLeft imossible!");
Element res=root(n->left);
n->left=makeEmptyBTree();
return res;
}
void insertRightmostNode(BTree *bt, Element e){
if(isEmptyBTree(*bt))
*bt=makeLeaf(e);
else{
BTree tmp=*bt;
while(!isEmptyBTree(rightChild(tmp))) tmp=rightChild(tmp);
insertRight(tmp,e);
} }
Struct 25/30
Quelques fonctions de modification
Element deleteLeftmostNode(BTree *bt){
Element res;
if(isEmptyBTree(*bt))
erreur("deleteLeftmostNode imossible!");
if(isEmptyBTree(leftChild(*bt))){
res=root(*bt);
*bt=rightChild(*bt);
} else{
BTree tmp=*bt;
while(!isEmptyBTree(leftChild(leftChild(tmp)))) tmp=leftChild(tmp);
res=root(leftChild(tmp));
tmp->left=(tmp->left)->right;
}
return res;
}
Struct 26/30
Type abstrait Implantation Arbres modifiables Extensions
Extensions
Type abstrait Implantation Arbres modifiables Extensions
Extensions
Probl`emes avec les arbres binaires (`a n noeuds) : Chercher un ´el´ement coˆute cher : O(n) ;
Ins´erer un ´el´ement (pas n’importe o`u !) :O(n) ; Supprimerun ´el´ement : on ne peut pas toujours...
Solution ? Ordonner (trier) les ´el´ements dans l’arbre...
Un arbre binaire de recherche (BST) est : soit vide,
soit un noeud :
contenant une donn´ee (la racine), dont le fils gauche est unBST dont les ´el´ements sont inf´erieurs `a la racine, dont le fils droit est unBST dont les ´el´ements sont sup´erieurs `a la racine.
8
10 5
11
1 7
0 6
3
9 2
4
Extensions (suite)
Arbre binaire ´equilibr´e (AVL) : les hauteurs des deux sous- arbres d’un mˆeme noeud diff`erent au plus de 1.
8
10 5
11
1 7
0 6
3
9 2
4
BST (pas AVL)
7
9 4
10
1 6
0 5 11
8 2
3
AVL
Difficult´e : conserver l’´equilibrage. Gain : meilleure complexit´e !
Struct 29/30
Extensions - fin
Un arbre g´en´eral (chaque noeud a une liste de fils :)
8
6 3
11
13 1
0 18
14
10 5
4
7
15 12
16 9
2
Struct 30/30