Conception de structures de donn´ ees
Cours 6 Arbres binaires
22 avril 2013
Pourquoi les arbres ?
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, ...
enalgorithmique du texte (Huffamn, prefix-trees) :
compression, recherche de motifs, d´etection de r´ep´etitions, ...
eng´eom´etriealgorithmique (quadtrees, octrees, KD-trees, arbres rouge-noir, ...) ;
enlinguistique et en compilation(arbres syntaxiques) ; pour la gestion du cache, les bases de donn´ees, les syst`emes de fichiers, ... (B-trees,).
D´ efinition des arbres BINAIRES
Unarbre binaire est 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 unnoeudcontenant une donn´ee et ayant2 fils(gaucheet droit) qui sont eux-mˆemes des arbres binaires.
L’espace m´emoire utilis´e par un arbre n’est pas contigu.
Lataille d’un arbre est inconnue `a priori ;
Unarbre binaire est constitu´e denoeuds qui sont li´es entre eux par des pointeurs. On ne peut acc´eder directement qu’au 1er ´el´ement (laracine) de l’arbre.
Pouracc´eder `a un ´el´ement quelconqued’un arbre , il faut descendre dans l’arbrejusqu’`a cet ´el´ement.
Repr´ esentation graphique d’un arbre binaire
3
1 8
1 29 170
2 48
Arbres binaires r´ ecursifs
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
Ecrire une fonction r´ ´ ecursive sur les arbres.
Fonction r´ecursive fonctionRecsur 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))
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 hauteurk, 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
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);
} }
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 );
}
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 );
}
Parcourir un arbre en profondeur
La structure d’arbre n’imposepas un ordre totalsur les
´el´ements, or on voudrait avoir un ordre sur ces ´el´ements.
Pour cela, on fixe unem´ethode de parcours de l’arbre qui trie les ´el´ementspar orde de visite.
11
8 7
10
1 5
0 6 2
9
3
Parcourir un arbre en profondeur
La structure d’arbre n’imposepas un ordre totalsur les
´el´ements, or on voudrait avoir un ordre sur ces ´el´ements.
Pour cela, on fixe unem´ethode de parcours de l’arbre qui trie les ´el´ementspar orde de visite.
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours pr´ efixe (la racine en 1er)
11
8 7
10
1 5
0 6 2
9
3
Parcours infixe (la racine au milieu)
11
8 7
10
1 5
0 6 2
9
3
Parcours infixe (la racine au milieu)
11
8 7
10
1 5
0 6 2
9
3
Parcours postfixe (la racine en dernier)
11
8 7
10
1 5
0 6 2
9
3
Parcours postfixe (la racine en dernier)
11
8 7
10
1 5
0 6 2
9
3
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){ ... }
Arbres binaires en C
D´ efinition d’un arbre binaire en C
arbre vide:
3
1 8
1 29 170
arbre contenant 8 éléments
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){
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!");
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){
Arbres binaires modifiables
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);
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);
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);
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;
}
Extensions
Extensions
Probl`emes avec les arbres binaires (`a nnoeuds) : 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 : soitvide,
soit un noeud :
contenant une donn´ee (laracine), dont le fils gauche est unBSTdont les ´el´ements sont inf´erieurs `a la racine,
8 10 5
11
1 7
0 6
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
Extensions - fin
Un arbre g´en´eral (chaque noeud a une listede fils :)