Vous êtes sur la page 1sur 9

Algo4 – Structures de données avancées - Exercices

1 - Graphe
. Réécrire l'algorithme de parcours d'un graphe en profondeur (vu en cours) en utilisant une version
non récursive faisant appel à une pile.

Rappel de l'algorithme de parcours en profondeur version récursive


void profondeur (graphe g, sommet s)
{
si non Marque(s) alors
{
marquer(s)
pour tout sommet j adjacent (voisin) de s das g faire profondeur(g,j)
fpour
}
}
Version non récursive : utilisation d'une pile
procedure profondeur (graphe g, sommet s)
{
pile p ; creer(p) ;sommet x ;
empiler(p,s)
while not vide(p)
{
x=depiler(p) ;
if non Marque(x)
{
Marquer(x)
pour tout sommet j voisin(adjacent) à x dans g faire
empiler(p,j)
fin_pour
}
}
}
2 - Arbre binaire et arbre binaire de recherche
. Ecrire une fonction récursive qui permet de calculer le nombre de nœuds d'un arbre binaire
int nb_noeuds(arbre a)
{
if (a==null) return 0
else return 1+nbnoeuds(a->gauche)+nbnoeuds(A->droit)
}

. Ecrire une fonction récursive qui permet de calculer le nombre de feuilles d'un arbre binaire
// on écrit d'abord une fonction pour vérifier si un nœud est une feuille ou pas
boolean feuille(arbre a)
{
return (a->gauche==null) and (a->droit==null)
}

// Calcul du nombre de feuilles dans un arbre binaire


int nbfeuilles (arbre a)
{
if (a==null) return 0
else if feuille(a) return 1
else return nbfeuille(a->gauche)+nbfeuille(a->droit)
}

. Ecrire une fonction récursive qui permet de calculer la hauteur d'un arbre binaire.
// on aura besoin de la fonction maximum
int maximum(int a, int b)
{
if (a>=b) return a else return b ;
}
Int hauteur (arbre a)
{
if (a==null) return 0
else if feuille(a) return 0
else return 1+ maximum(hauteur(a->gauche), hauteur(a->droit))
}
. Montrer par une démonstration par récurrence que la hauteur h d'un arbre binaire complet est de :
h=log2(n) (1) où n est le nombre de feuilles de l'arbre.

Démonstration par récurrence


. On vérifie que la propriété est vraie les deux premières valeurs :
– pour n=1 (l'arbre est une feuille, et donc la hauteur est h=0 (voir ci dessus). On a bien
log2(1)=0)
– pour n=2 (s'il y a deux feuilles, l'arbre binaire complet est donc composé d'une racine et
deux feuilles ; par conséquent sa hauteur est de 1. On a bien 1=log2(2))
. On fait l'hypothèse de récurrence suivante : on suppose que la propriété (1) est vraie pour une
valeur n du nombre de feuilles fixée.
Quand on passe d'un arbre binaire complet d'une hauteur h à une hauteur (h+1) le nombre de
feuilles passe de n à 2*n (trivial : car chacun des nœuds possède 2 fils).
Or log2(2*n) = log2(2)+log2(n).
et comme log2(2)=1 et log2(n)=h (hypothèse de récurrence), on obtient donc :
log2(2*n)=h+1

. Utiliser la procédure d'insertion dans un arbre binaire de recherche afin de trier un vecteur par
ordre croissant.
L'idée de cette méthode consiste à insérer au fur et mesure les éléments du vecteur à trier dans un
arbre binaire de recherche (voir algorithme d'insertion vu en cours). Comme l'arbre binaire de
recherche est lui même trié, il suffit de choisir le bon parcours et copier les éléments ensuite dans
le vecteur. Le bon parcours pour avoir les éléments de l'arbre triés dans le vecteur serait de le
parcourir en Infixé suivant l'algorithme suivant :
parcours infixe (arbre a)
{
if (a!=null)
{
infixe(a->gauche)
traiter(a>element) // traitement quelconque sur l'élément du nœud courant.
infixe(a->droit)
}
}
Application pour écrire une méthode de tri d'un vecteur

// copie de l'arbre a dans le vecteur v en récursif


infixe_pour_le_tri (arbre a, vecteur v, int i)
{
if (a!=null)
{
infixe_pour_le_tri(a->gauche, v,i)
v[i]=a->element;
infixe_pour_le_tri( a->droit, v,i+1) ;
}

// La méthode de tri du vecteur


void tri (vecteur v, int n) // n taille du vecteur
{
arbre a=null ;
// construction de l'arbre binaire de recherche par insertion des éléments du vecteur
for (int i=0 ; i<n ; i++)
inserer (a,v[i]) ;

//parcours infixé de l'arbre et tri du vecteur


int i=0,
infixe_pour_le_tri(a,v,i)
}

. Ecrire une fonction récursive qui recherche la plus petit valeur d’un arbre binaire de recherche

Le plus petit élément dans un arbre binaire de recherche se trouve soit sur la feuille la plus à
gauche soit sur un nœud en fin de filiation à gauche sans sous arbre gauche (raisonnement
analogue : le maximum se trouve soit sur une feuille la plus à droite ou bien un nœud en fin de
filiation à droite sans sous arbre droit).

Int minimum (arbre a) int maximum(arbre a)


{ {
if (a->gauche!null) if (a->droit!null)
return minimum(a->gauche) return maximum(a->droit)
else return a->element ; else return a->element ;
} }
3 - Arbre_B
Soit le fichier séquentiel suivant (on ne donne pour chaque article du fichier que la clé sur laquelle
on souhaite construire l’arbre_B) : 1, 15, 3, 12, 6, 4, 11, 7, 2, 5, 14, 8, 9, 17, 10, 13, 16,
. Donnez l’arbre_B d’ordre 2 résultant après l’insertion de tous les articles du fichier séquentiel.
On obtient l'arbre suivant

. Que devient cet arbre s’il était d’ordre 1 ?


On obtient l'arbre suivant

. Combien de nœuds différents (racine et feuilles comprises) doit-on parcourir dans l’index de
l’arbre_B d’ordre1 pour répondre à une requête qui cherche des articles dont la clé appartient à
l’intervalle [2,12] ?
Si l'on applique l'algorithme de recherche dans l'arbre_B ci dessus d'une clé c dans l'intervalle
[2,12] on devrait trouver : nb_consultés=8 noeuds
4 - Les arbres AVL
. L'arbre ci dessous est-il un arbre AVL ? Si oui, expliquez pourquoi, si non, transformez le
en arbre AVL en effectuant des rotations que vous expliquerez.

15

10 25

5 12 30

Voici l'arbre ci dessus auquel on a rajouté les étiquettes aux nœuds correspondant à la différence
des hauteurs entre les sous arbres gauche et droit.

On remarque que toutes étiquettes possèdent une valeur absolue < 2 donc l'arbre est équilibré au
sens AVL.
. L'arbre ci dessous est-il un arbre AVL ? Si oui, expliquez pourquoi, si non, transformez le
en arbre AVL en effectuant des rotations que vous expliquerez.
9

7 10

4 8

Voici l'arbre ci dessus auquel on a rajouté les étiquettes aux nœuds correspondant à la différence
des hauteurs entre les sous arbres gauche et droit.

Comme on peut le constater le nœud 9 viole la contrainte d'équilibrage au sens AVL (car son
étiquette vaut 2). Donc l'arbre n'est pas équilibré (déséquilibré à gauche).
Pour l'équilibrer, on va appliquer l'algorithme AVL (vu en cours). Dans ce cas de figure
l'algorithme AVL nous dit d'effectuer au niveau du noeud 9 une rotation Droite (RD). Ce qui donne
l'arbre équilibré suivant :
. Insérez dans l'arbre proposé ci dessus les valeurs ci-dessous. Chaque insertion fera l'objet
d'un schéma commenté avant et après ré-équilibrage de l'arbre par rotations.
40 13 14 11 1

Je vous laisse le soin de terminer l'exercice en insérant les valeurs ci dessus sur le
même principe....

5 - Tables de hachage et Filtre de Bloom

5.1 - Considérer la fonction de hachage h(c) = c mod 13 et une table de hachage avec m = 13
adresses.
1. Donner l'état de la table après insertion des clés 26,37,24,30, 11 dans la table de hachage en
utilisant la résolution des collisions par adressage ouvert avec la fonction
hi(c) = (h(c)+i) mod m.
2. Rajouter maintenant les clés 1,2,3,4,5,6,7,8,9,10. Quel problème rencontrez-vous ? Quelles
solutions proposez-vous ? Donner l'état de la table de Hachage.
La table de hachage se remplit très vide et donc la taille n’est pas suffisante.
Dans ce cas, il y a deux solutions :
. On agrandit la taille de la table de hachage. Dans ce cas là, tous les éléments doivent être insérés
de nouveau. Il est courant de doubler la taille de la table de hachage
. On utilise la résolution des collision par chainage externe (les éléments ayant la même valeur de
fonction de hachage sont liés par une liste chainée).

3. On souhaite construire un filtre de Bloom de taille 10 à l'aide de trois fonctions de hachage


h0, h1 et h2 déduites à l'aide de la méthode par multiplication de valeur teta respectives de
0.1, 0.2 et 0.3 (voir cours).
. Donner l'état du filtre de Bloom après insertion des clés suivantes :
8, 12, 14, 15, 21, 23, 25, 36
En calculant les valeurs que retournent les trois fonctions de hachage h0, h1 et h2 (voir figure
ci dessous) pour les valeurs ci dessus, on obtient la table de Bloom suivante:

Filtre de Bloom
1 1 1 1 1 1 1 0 1 1
0 1 2 3 4 5 6 7 8 9

. Donner le taux de faux positifs dans le cas de la recherche des clés suivantes
21, 17, 27, 23, 36, 18, 3, 22, 15, 25, 8
On constate que les éléments 18 et 22 figurant sur cette liste ne font pas partie des éléments insérés
dans la base de données (ils ne font pas partie de la liste initiale).
Pourtant :
Si on calcule : h0(18)=1 et h1(18)=1 et h3(18)=1 donc il y a collision avec un élément déjà inséré :
donc 18 est un faut positif
Si on calcule : h0(22)=1 et h1(22)=1 et h3(22)=1 donc il y a collision avec un élément déjà inséré :
donc 22 et un faux positif.

D'ou le taux de faux positifs=(nombre de faux positifs/nombre total d'éléments)=2/11

Vous aimerez peut-être aussi