La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Présentations similaires


Présentation au sujet: ""— Transcription de la présentation:

80 Arbres racine noeud interne père fils droit fils gauche feuilles
Un arbre est soit un arbre atomique (une feuille), soit un noeud et une suite de sous-arbres. racine noeud interne père fils droit fils gauche feuilles L'ensemble des noeuds est constitué des nœuds internes et des feuilles

81 L’intérêt de cette organisation est de laisser à l’utilisateur le soin de regrouper les fichiers à sa convenance tout en maintenant une structure hiérarchique.

82 Représentation symbolique des arbres
Arbre vide Arbre singleton Arbre quelconque Arbre binaire CECI N'EST PAS UN ARBRE deux pères

83 Par définition un arbre est une structure de données constituée d’un nœud appelé racine et de sous-arbres fils de la racine. C’est donc une définition récursive. racine Un nœud peut contenir une ou plusieurs valeurs, et on parlera alors d'arbres étiquetés et de la valeur (ou des valeurs) d'un nœud.

84  x Les caractéristiques d’un arbre sont :
        La taille de l’arbre est le nombre total de nœuds.         La hauteur ou niveau d’un nœud x est le nombre de liens sur l’unique chemin allant de la racine à x, notée h(x).      La hauteur ou profondeur de l’arbre A, h(A) = max { h(x) }  x racine x

85 hauteur d'un nœud dans un arbre de racine r: si x = r h(x) = 0
sinon h(x) = 1 + h(père(x)) La profondeur d'un nœud est la longueur du chemin qui le joint à la racine. La racine est de hauteur 0, ses fils de hauteur 1 et les k autres nœuds de hauteur supérieure à 1. La longueur de cheminement de l’arbre A, LC(A) =  h(x) x

86 profondeur # noeuds # feuilles
Exemple de mesures profondeur # noeuds # feuilles LC(A) =  h(x) x h = 6 Taille = 12 Nbrf = 5

87 Arbres binaires a d g b b f c d a c e g e arbre équilibré f
La différence entre la hauteur du sous-arbre gauche et la hauteur du sous-arbre droit est d'au plus une unité. La recherche d'une clé d'un côté sera plus lente qu'une recherche de l'autre côté.

88 Arbre binaire typedef struct cellule { int data;
struct noeud *fils_gauche;  struct noeud *fils_droit;  } nœud;

89 elt arbre nouveau_binaire(int elt, arbre racine) {
• Un Arbre est un pointeur sur un nœud, la racine de l’arbre : typedef nœud *arbre; • Un Arbre vide est un pointeur NULL : arbre = NULL; • Nouveau : il faut faire une allocation mémoire et placer l’étiquette. En cas d’erreur d’allocation le pointeur renvoyé est NULL (l’arbre est vide) : arbre nouveau_binaire(int elt, arbre racine) { racine = (nœud *) malloc(sizeof (nœud )); if (racine != NULL)){ racinedata = elt; racine fils_gauche= NULL; racine fils_droit=NULL; } return(racine); elt NULL NULL

90 Il faut relier un noeud à un ou plusieurs sous arbres.
arbre cons_binaire(arbre racine, arbre s_arb_g, arbre s_arb_d) { racine fils_gauche = s_arb_g; racine fils_droit = s_arb_d; return(racine); }

91 Hauteur int HauteurArbre(arbre A) { if(A non vide) return (1 + Max(HauteurArbre(Ag), HauteurArbre(Ad)) ); else return 0; } Complexité : O(n) Nombre noeud int NbrNoeud(arbre A) { if(A non vide) return (1 + NbrNoeud(Ag) + NbrNoeud(Ad) ); else return 0; }

92 Max noeud int MaxNoeud(arbre A) { if(A non vide) return Max(data, MaxNoeud(Ag), MaxNoeud(Ad)); else return 0; } Min noeud int MinNoeud(arbre A) { if(A non vide) return Min(data, MinNoeud (Ag), MinNoeud (Ad)) ; else return 0; }

93 Arbre binaire de recherche ABR
Utilisation importante en Info pour la localisation, +, -, tri … Un arbre binaire de recherche est un arbre binaire tel que pour tout nœud x , les nœuds de son sous arbre-gauche s’ils en existent ont des valeurs inférieures ou égales à celle de x, et les nœuds de son sous arbre-droit des valeurs strictement supérieures. X <=X >X Ce que l’on traduit par g(A)  racine(A) < d(A). 24 10 37

94 r Ag Ad <= r > r Un arbre binaire est soit vide, noté Ø, soit de la forme < r, Ag, Ad > où r est la racine et où Ag et Ad sont des arbres binaires.

95 Ag Ad Tout sous-arbre d’un ABR est un ABR 24 29 16 8 20 27 35 1 15
Exemple d’arbre binaire de recherche

96 Complexité : O(2n+1) * O(1) = O(n)
test si arbre binaire et de recherche bool TestABR(arbre T){ if(T non vide){ if( TestABR(Td) est un ABR && TestABR(Tg) est un ABR) { if((Td pas vide) && (Tddata <= Tdata)) return (probleme) else { if((Tg pas vide) && (Tgdata > Tdata)) else return (OK) } return (???) racine x Tg Td <= x > x Complexité : O(2n+1) * O(1) = O(n)

97 Parcours en profondeur d'un arbre binaire de recherche
12 Parcours en profondeur d'un arbre binaire de recherche 9 23 -2 10 22 78 -77 9 On considère l’opération de parcours d’un arbre binaire qui consiste à examiner systématiquement dans un certain ordre tous les nœuds de l’arbres pour effectuer un traitement de données.

98 Parcours préfixe Parcours préfixe : 12, 9, -2, -77, 9, 10, 23, 22, 78
Lister Père Prefixe(Fils_G) Prefixe(Fils_autres) 9 23 -2 10 22 78 void Prefixe(arbre racine) { if (! vide(racine)) { printf(“%d\t”,racinedata); Prefixe(racinefils_gauche); Prefixe(racinefils_droit); } -77 9 Le parcours en profondeur à gauche consiste à partir de la racine et à tourner autour de l’arbre en allant toujours le plus à gauche possible. Parcours préfixe : 12, 9, -2, -77, 9, 10, 23, 22, 78

99 Parcours infixe III I II 12 Infixe(Fils_G) Lister Père
Infixe(Fils_autres) 9 23 -2 10 22 78 void infixe(arbre racine) { if (! vide(racine)) { infixe(racinefils_gauche); printf(“%d\t”,racinedata); infixe(racinefils_droit); } -77 9 infixe : -77, -2, 9, 9, 10, 12, 22, 23, 78 SI ABR Le parcours infixe affiche les éléments dans l’ordre croissant.

100 Parcours suffixe ou Postfixe II I III 12 9 23 -2 10 22 78 -77 9
void Postfixe(arbre racine) { if (! vide(racine)) { Postfixe(racinefils_gauche); Postfixe(racinefils_droit); printf(“%d\t”,racinedata); } Parcours Postfixe : -77, 9, -2, 10, 9, 22, 78, 23, 12

101 Exemple: Parcours 3 5 1 4 6 2 Parcours préfixe : 3, 1, 0, 2, 5, 4, 6
2 Infixe(Fils_G) Lister Père Infixe(Fils_autres) Parcours infixe : 0, 1, 2, 3, 4, 5, 6 Posfixe(Fils_G) Posfixe(Fils_autres) Lister Père Parcours postfixe : 0, 2, 1, 4, 6, 5, 3

102 Exemple: Parcours 1 2 3 4 5 6 7 Parcours préfixe : Infixe(Fils_G)
Lister Père Infixe(Fils_autres) Parcours infixe : Posfixe(Fils_G) Posfixe(Fils_autres) Lister Père Parcours postfixe :

103 Recherche d’un élément
 Recherche dichotomoque rechercher : valeur x dans arbre == Rech(x,arbre)  booléen On compare l’élément à la valeur de la racine : -   si le sous-arbre sélectionné est vide, l’élément est absent  échec rechercher ( x ,  ) = faux -   si égalité  succès x = r  rechercher (x ,<r , g , d > ) = vraie 24 29 35 16 27 20 3 5 1 -   si la valeur est plus petite, on recommence récursivement dans le sous-arbre gauche ; et réciproquement si la valeur est plus grande dans le sous-arbre droit x < r  rechercher (x , < r , g , d > ) = rechercher (x , g ) x > r  rechercher (x , < r , g , d > ) = rechercher (x , d ) Complexité : La complexité au pire est en O ( hauteur de l’arbre ).

104 Soit à rechercher 20 dans l'arbre suivant
24 20 est plus petit que 24 20 est plus grand que 16 29 16 20 est trouvé 3 20 27 35 1 5

105 Adjonction d’un élément aux feuilles
L’adjonction aux feuilles d’un élément se réalise en deux étapes : -          étape de recherche pour savoir où insérer le nouvel élément ; -          adjonction elle-même. arbre ajout_feuille (arbre A, int e )  { if (A==  ) return < e ,  ,  > else if ( e  racine(A) ) return < racine(A) , ajout_feuille( g(A) , e ) , d(A) > else return < racine(A) ,g(A) , ajout_feuille( d(A) , e ) > } e La complexité d’une adjonction est O ( h(A) ).

106 x arbre insert(arbre T, int x) { if(T vide) { //sommet vide
T = (struct nœud *) malloc(sizeof(struct nœud)) Tdata = x Tdroit = NULL Tgauche = NULL }else{ //sommet non vide if(Tdata == x) //ne rien faire !! else { if(x < Tdata) //inserer ds arbre gauche Tg = insert(Tg, x) else //inserer ds arbre droit Td = insert(Td, x) } return T NULL x

107 mais pas la complexité de la programmation !!!
La complexité d’un ajout est O ( h(A) ). Alors que l’insertion dans un tableau nécessite de déterminer sa place, en parcourant le tableau depuis le début (k comparaisons) puis de décaler les (n-k) éléments successeurs pour ménager une place. Donc une complexité en O(n) avec n le nombre d’éléments du tableau. ABR  réduire la complexité en temps mais pas la complexité de la programmation !!!

108 remplace le nœud par son fils
Suppression d’un élément arbre supprimer (arbre , valeur)  arbre recherche de l’élément à supprimer suppression qui dépend de la place de l’élément soit on remplace le nœud à supprimer par le plus grand élément de son sous-arbre gauche, soit on le remplace par le plus petit élément de son sous-arbre droit. immédiate noeud avec deux fils nœud avec un seul fils nœud sans fils remplace le nœud par son fils

109 arbre suppression ( arbre A , int e ) {
if (A== ) // recherche de l’élément à supprimer return erreur; if ( e < racine(A) ) return < racine(A), suppression( g(A) , e ) , d(A) ); else if ( e > racine(A) ) return < racine(A), g(A) , suppression( d(A) , e ) ); else { // on l’a trouver donc suppression if est_feuille(A) return (  ); else if (g(A) == ) return d(A); else if (d(A) ==  ) return g(A); else { // on ajoute l’élément le plus à droite du sous-arbre gauche retourner < max_noeud(g(A)) , retire_max(g(A)), d(A) > }

110 La complexité est O ( h(A) ).
int max_noeud ( arbre A) { // retourne le plus grand élément de l’arbre A, le plus à droite if ( d(A) == ) return racine(A); else return max_noeud(d(A)) ; } // retourne l’arbre privé de son plus grand élément arbre retire_max ( arbre A ) { if ( d(A) == ) return g(A); else return < racine(A) , g(A) , retire_ max(d(A)) >; } La complexité est O ( h(A) ).

111 La structure de tas La structure de tas est un arbre vérifiant les deux propriétés suivantes: L’arbre est un arbre binaire parfait La valeur de tout nœud est >= à celle de ses descendants Arbres binaires complets Un arbre binaire est complet si tous les nœuds qui ne sont pas des feuilles ont 2 fils. 15 14 2 8 13 7 5

112 Arbres binaires parfaits, ordre hiérarchique
Un arbre binaire est parfait si toutes ses feuilles sont situées sur les deux derniers niveaux, l’avant dernier étant complet, et les feuilles du dernier sont le plus à gauche possible. Attention ! un arbre binaire parfait n’est pas forcément complet. tas 15 14 2 8 13

113 Tas = arbre binaire parfait partiellement ordonné ¨ arbre parfait:
– toutes les feuilles sont sur les deux derniers niveaux, – l'avant dernier niveau est complet – les feuilles du dernier niveau sont le plus à gauche possible ¨ partiellement ordonné: – tout nœud est plus grand que ses deux fils 24 23 7 16 1 22 10 8 5 4

114 Tests !! Arbres binaires complets 15 14 2 Arbre binaire complet ? 8 7
Un arbre binaire est complet si tous les nœuds qui ne sont pas des feuilles ont 2 fils. 15 14 2 Arbre binaire complet ? 8 7 5

115 Tests !! Arbres binaires complets 15 9 14 2 8 13
Un arbre binaire est complet si tous les nœuds qui ne sont pas des feuilles ont 2 fils. 15 9 14 2 8 13 Arbre binaire complet ? 7 5

116 Tests !! Arbres binaires parfaits, ordre hiérarchique
Un arbre binaire est parfait si toutes ses feuilles sont situées sur les deux derniers niveaux, l’avant dernier étant complet, et les feuilles du dernier sont le plus à gauche possible. Attention ! un arbre binaire parfait n’est pas forcément complet. 15 14 2 8 13 7 5 Arbre binaire parfait? Arbre binaire complet ?

117  = 2h+1 - 1 La structure de tas N <=  Racine = + gd valeur
Profondeur ou Nbr nœuds Niveau Max = 1 = 2 = 4 h= au Max 23 = 8 24 16 23 8 10 22 7 1 5 Exemple de tas  = 2h+1 - 1 N <=

118 Profondeur ou Nbr nœuds Niveau Max 0 20 = 1 1 21 = 2
Index Profondeur ou Nbr nœuds Niveau Max = 1 = 2 = 4 au Max 23 = 8 1 2 3 2*2=4 5 6 2*3+1=7 8 24 16 23 8 10 22 7 1 5 4 Exemple de tas Index 2*Index 2*Index + 1 Nœud x en i, son père est en i/2 Nœud x en i, son fils gauche en 2*i Nœud x en i, son fils droit en 2*i+1

119 Relation entre un tas et tableau
int pere(i){ return (i/2); } int gauche(i){ return (2 * i); int droit(i){ return (2 * i + 1); Relation entre un tas et tableau Index 1 2 3 2*2=4 5 6 2*3+1=7 8 24 16 23 8 10 22 7 1 5 4 i 24 16 23 8 10 22 7 1 5 4 tab[i]

120 Insertion d’un élément dans un tas
Opérations sur les tas Insertion d’un élément dans un tas 24 24 23 7 16 1 22 8 5 4 10 16 23 8 10 22 7 22 1 5 4 Nouveau nœud insérer le plus à gauche possible sur le niveau de profondeur le plus élevée.  tjr arbre binaire complet mais pas forcement un tas.

121 Insertion de n éléments  O(nlogn)
1 2 3 4 5 6 7 8 9 10 11 24 24 16 23 22 23 8 22 22 7 8 16 22 7 1 5 4 10 1 5 4 10 tant que ( y  racine ) et ( y > père(y) ) faire échanger y et père(y) Compléxité : O(h) avec h : hauteur du tas Or la hauteur d’un tas de taille n = log2n  l’insertion requiert un temps O(logn) Insertion de n éléments  O(nlogn)

122 VERIFICATION void ajouter (int tab[], int ntas , int val ) {
// ajoute l’élément x au tas de ntas éléments int i; ntas ++ ; i =ntas ; tab[i] = val ; while ( ( i > 1 ) && ( tab[i/2] < tab[i] ) ){ Echanger ( tab[i], tab[i / 2] ); i = i/2 ; } VERIFICATION

123 Echanger i = i/2  i=11/2=5 Avant l’ajout i 22 + 11 24 16 23 8 10 22 7 1 5 4 tab[i] 24 16 23 7 1 22 8 5 4 tab[i] 10 Echanger i = i/2  i=5/2=2 24 22 23 7 1 16 8 5 4 tab[i] 10 while ( tab[i /2] < tab[i ] ) { Echanger ( tab[i], tab[i / 2] ); i = i/2 ; }

124 i 24 22 23 8 16 22 7 1 5 4 10 tab[i] 1 2 3 4 5 6 7 8 9 10 11 24 22 23 CQFD 8 16 22 7 10 1 5 4

125 Exce : Construction d’un tas
8 15 2 13 14 5 3 tab[i] 15 8 2 13 tas + + 8 15 15 8 15 8 2 tas 15 13 2 8 + 15 13 2 8 14 tas 15 14 2 8 13 + tas 15 14 5 8 13 2 3

126 i 8 15 2 13 14 5 3 tab[i] int i; ntas ++ ; i =ntas ; tab[i] = val ; while ( ( i > 1 ) && ( tab[i/2] < tab[i] ) ){ Echanger ( tab[i], tab[i / 2] ); i = i/2 ; } 8 15 15 8 tab[2/2] < tab[2] 8 15 2 3 5 14 13 tab[i] i 8 15 2 3 5 14 13 tab[i] 13 15 2 3 5 14 8 13 15 2 3 5 14 8 14 15 2 3 5 13 8

127 int i; ntas ++ ; i =ntas ; tab[i] = val ; while ( ( i > 1 ) && ( tab[i/2] < tab[i] ) ){ Echanger ( tab[i], tab[i / 2] ); i = i/2 ; } i tab[i] 15 14 2 8 13 5 3 14 15 5 3 2 13 8 14 15 5 3 2 13 8 14 15 5 3 2 13 8

128 Suppression d’un élément
On remplace la valeur du nœud par celle du nœud le plus à droite possible sur le niveau de profondeur le plus élevée, nœud que l’on supprime alors, puis permutations. Exp: racine : suppression du premier élément de la file 24 4 16 23 16 23 8 10 22 7 8 10 22 7 1 5 4 1 5 4

129 4 23 4 7 16 1 22 10 8 5 16 23 8 10 22 7 23 22 7 16 1 4 10 8 5 1 5

130 Tri par tas [Heap sort] 15 14 5 8 13 2 3 3 14 5 8 13 2 15 Suppression
Principe : deux phases -   Construire un tas contenant les n éléments par adjonction successives ; en O (n log n). -   Tant que le tas n’est pas vide, répéter l'opération de prendre l'élément de la racine (max), le retirer du tas avec réorganisation, mettre ce max à sa place définitive  ; en O (n log n). 15 14 5 8 13 2 3 3 14 5 8 13 2 15 Suppression réorganisation

131 réorganisation 14 13 5 8 3 2 15 3 14 5 8 13 2 15 2 13 5 8 3 14 15 Suppression

132 trier_tas(A) { construire_tas(A) while( …) echanger A[1] avec A[taille] supprimer A[taille] taille = taille – 1 reorganisation() }

133 1: construction d’un tas
Test !!! i 3 5 14 13 2 15 8 tab[i] 1: construction d’un tas 2: ajout de 20

134 Test !!! 15 20 15 14 13 2 5 8 3 13 14 5 8 3 2 20 15 13 14 3 2 5 8 20 + i

135 5, 1, 7, 3, 4, 6, 2 Test !!! Construction d’un arbre binaire
de recherche (ABR). r i Ag Ad 5, 1, 7, 3, 4, 6, 2 <= r > r Prefixe, Infixe , Postfixe ??

136 Application : Imprimante en réseau
User1 FIFO Tri: Arbre JbU1 JbUn JbU1 JbUn User2 UserN JbU5 JbU1 JbUn

137 Diviser pour régner Existe-t-il une méthode pour rechercher une récursivité et évaluer a priori sa complexité? On peut couper un problème de taille N en A problèmes identiques Recomposition de ces A problèmes se fait en un temps d'ordre N

138 Exemple : TRI par FUSION
Pour trier un tableau t de n éléments, on le scinde en deux tableaux de même taille (à un élément près). On les note t1 de taille n1 et t2 de taille n-n1. Ces deux tableaux sont ensuite triés (appel récursif) et enfin fusionnés de manière à reformer le tableau t trié. tableau t scinder scinder scinder T(N) = 2 * T(N/2) + ordre N d'où T(N) = N log2N fusionner fusionner fusionner

139 Quicksort : tri rapide Principe : ‘’ diviser pour régner ‘’
On prend un élément au hasard dans le tableau à trier. Soit p (pivot) sa valeur. On partitionne le reste du tableau en 2 zones: les éléments plus petits ou égaux à p, et les éléments plus grands à p. Si on arrive à mettre en tête du tableau les plus petits que p et en fin du tableau les plus grands, on peut mettre p entre les deux zones à sa place définitive. On recommence récursivement la procédure Quicksort sur chacune des partitions tant qu'elles ne sont pas réduites à un élément. A la fin, la liste est triée par ordre croissant. p > pivot  pivot g > pivotG  pivotG d > pivotD  pivotD

140 p > pivot  pivot g d void Quicksort ( int tab[] , int g , int d ) { // Quicksort ( tab , 0 , n ) int k; //position du pivot if( g < d){ Placer (tab , g , d , &k); Quicksort (tab , g , k - 1); Quicksort (tab, k + 1 , d); }

141 La partition et le placement du pivot ne nécessitent qu’un parcours.
La fonction Placer : La partition et le placement du pivot ne nécessitent qu’un parcours. p  p > p x K j+1 i L j On utilise deux compteurs L et K qui partent des extrémités du sous-tableau, et qui vont l’un vers l’autre : -   L part de i+1 et avance tant que l’on rencontre un élément  à p. -   K part de j et recule tant que l’on rencontre un élément > à p. On échange les deux éléments et on recommence la progression jusqu’à ce que les deux compteurs se croisent : la place définitive du pivot est en k, et on y place le pivot p par échange avec un élément  à p. complexité en moyenne O (n log n).

142 Exemple de tri rapide 5 3 2 6 4 1 7 i j 5 3 2 6 4 1 7 3 2 6 4 1 7 3 2 4 1 6 7 5 3 2 4 1 6 7

143 Arbres balancés ou B-arbres
Les B_arbres sont des arbres de recherche équilibrés conçus pour être efficaces sur des disques ou d'autres unités de stockage secondaire à accès direct. Dans une application classique ayant recours aux B_arbres, la quantité de données gérées est si grande qu’elles ne tiennent pas toutes en même temps dans la mémoire principale. prendre en compte la taille des blocs disques regrouper les nœuds voisins dans un même bloc Généralisation des ABR

144 Éclatement d'une racine

145 Éviter de ‘’ réinventer la roue ‘’
Jeu de l'urne Soient -         B boules blanches et N boules noires dans une urne. -         B  0, N  0, B+N  1 -         Une réserve infinie de boules Mode de fonctionnement Tirage aveugle de 2 boules -         si les boules sont de même couleur, on remet une boule noire dans l'urne -         sinon, on remet une boule blanche Le jeu se termine lorsqu'il ne reste plus qu'une boule dans l'urne Question Quelle est la couleur de la dernière boule connaissant les nombres initiaux N et B?

146 Le jeu se terminera-t-il ou pas?
Tirage aveugle de 2 boules -  si les boules sont de même couleur, on remet une boule noire dans l'urne -  sinon, on remet une boule blanche Le jeu se terminera car à chaque tirage, le nombre de boules dans l'urne diminue de 1.

147 GENERALISER RESOLUTION : Exemple avec 3 Boules:
2Bles de même couleur  N sinon, on remet  boule blanche RESOLUTION : Le jeu se terminera car à chaque tirage, le nombre de boules dans l'urne diminue de 1. Exemple avec 3 Boules: GENERALISER

148 GENERALISER !! Impensable

149 Tirages possibles et propriétés?
AUTRE APPROCHE : Tirages possibles et propriétés? (B-2) + (N+1) B + (N-1) B + (N-1) Conclusion La parité des blanches est inchangée. Donc, si le nombre initial B est impair, la dernière boule sera blanche, sinon, elle sera noire.


Télécharger ppt ""

Présentations similaires


Annonces Google