les tableaux - Site de Bertrand LIAUDET

publicité
INGESUP - Paris
Algorithmique – 2
Structures de données
TAD – P.O.O.
Pointeurs – Récursivité
Polycopié en cours de réalisation !!!
Bertrand LIAUDET
SOMMAIRE
SOMMAIRE
1
0 - INTRODUCTION
4
1.
Structure de données
4
2.
Contenu pédagogique
4
1 - LES ENREGISTREMENTS (TYPE STRUCTURE)
5
1.
5
Présentation
Usages 5
Structures complexes
Renommer un type
5
6
2 - LES TABLEAUX
7
1.
Présentation
Le tableau
Le taille du tableau
Le nombre d’éléments du tableau
Imbrication de tableaux et d’enregistrements
7
7
7
7
7
2.
Méthodes de recherche
Recherche dans un tableau non trié
Recherche dans un tableau trié : la recherche dichotomique
7
7
7
3.
Méthodes de tri
Tri à bulles
Tri par extraction (élémentaire, heapsort)
Tri par insertion
Autres méthodes
7
7
7
8
8
ALGORITHMIQUE - Cours 02 - page 1/28 - Bertrand LIAUDET
4.
Exercices sur les tableaux
Tableaux à une dimension
Matrice 9
8
8
3 - LES POINTEURS
10
1.
Rappels sur la variable
Présentation
Formalisme NTVA
Déclaration et usage
10
10
10
10
2.
Pointeurs et opérateur & et *
Le type pointeur
Opérateur &
Opérateur *
Exemple
allocation, réservation de mémoire
libération de la mémoire
11
11
11
11
11
12
12
3.
Tableau de pointeurs
13
4.
Exercices sur les pointeurs
13
4 - LES LISTES
14
1.
Présentation
14
2.
Liste simplement chaînées
14
3.
Variantes
Liste doublement chaînée
Liste circulaire
Liste avec compteur de maillons
14
14
14
14
4.
Exercices sur les listes
14
5 - RECURSIVITE
16
1.
Présentation
Principe
Exemple : somme des N premiers nombres
Intérêt et limite de la récursivité
16
16
16
16
2.
Exercices
Exercice 1
Exercice 2
Exercice 3
Exercice 4
Exercice 5
17
17
17
17
17
17
6 - LES ARBRES
18
1.
Modèle logique des arbres
18
2.
ABOH (arbre planaire)
Modèle logique
Modèle physique des données – Version dynamique
Algorithmes
18
18
18
19
3.
Arbres équilibrés (AVL)
20
4.
Arbres B (B trees)
Présentation
20
20
ALGORITHMIQUE - Cours 02 - page 2/28 - Bertrand LIAUDET
Principes spécifiques
Exemple d’arbre B d’ordre 1
21
21
5.
Arbres BB
21
6.
Arbres SBB (bicolores).
21
7.
Exercices sur les ABOH
22
7 - LES GRAPHES
23
1.
23
Présentation
8 - HACHAGE
24
1.
24
Présentation
9 - LES TAD : VERS LA P.O.O.
25
1.
Présentation générale des TAD
Présentation
Principaux TAD
25
25
25
2.
Les chaînes de caractères
25
3.
Les piles
26
4.
Les files
27
5.
Les collections
27
6.
Les fichiers
27
10 - USAGES TECHNIQUES DES POINTEURS
28
1.
Gestion d’une pile LIFO avec une liste chaînée
28
2.
Gestion d’une file FIFO avec une liste chaînée
28
3.
Pointeurs et tableaux
Tableaux de pointeurs
Tableau et chaîne de caractères
Tableaux et pointeurs
28
28
28
28
4.
Pointeurs et chaînes de caractères
28
5.
Pointeurs et mode de passage des paramètres
28
ALGORITHMIQUE - Cours 02 - page 3/28 - Bertrand LIAUDET
0 - INTRODUCTION
1.
Structure de données
Dans la première partie du cours d’algorithmique, on a travaillé uniquement sur les types simples : entier, réel,
caractère et booléen. Le type chaîne de caractères a été abordé sans plus.
Dans ce cours, on va présenter différentes sortes de structures de données.
Une structure de données est un mode particulier d’organisation des données.
On peut aussi créer des types abstraits de données, TAD, qui se caractérise par un type particulier et par un jeu de
primitives (procédures et fonctions) permettant d’exploiter le type sans avoir à connaître les détails de son
implémentation : ils servent d’introduction à la notion de « CLASSE » de la programmation objet.
Pour travailler sur les structures de données, on sera amener à aborder le type « pointeur » et la récursivité.
2.
Contenu pédagogique
1.
Enregistrements : enregistrement de types de base, enregistrement d’enregistrement.
2.
Tableaux : tableau à 1, 2, n dimensions, tableau d’enregistrements, enregistrement de tableaux.
3.
Pointeurs.
4.
Listes : liste simplement chaînée, liste doublement chaînée, liste circulaire.
5.
Récursivité.
6.
Arbres : arbres binaires, arbres équilibrés (AVL), arbres B (B tree), arbres bicolores (SBB), arbres planaires.
7.
Graphes : graphes non orientés, graphes orientés, graphes valués.
8.
Hachage.
9.
TAD : chaînes de caractères, piles, files, collection, fichiers
ALGORITHMIQUE - Cours 02 - page 4/28 - Bertrand LIAUDET
1 - LES ENREGISTREMENTS (TYPE STRUCTURE)
1.
Présentation
Un enregistrement (ou type structuré) est un type de donnée permettant d’avoir dans une même variable plusieurs
informations pouvant être de type différent.
On parle d’enregistrement ou de structure.
Usages
Exemple traité
On veut définir un type de donnée correspondant à un élève. Un élève a un nom, un prénom et une note.
Définition du type
struct typEleve
nom : chaîne
prénom : chaîne
note : entier
fin
 commentaires
On utilise le mot-clé « struct » pour déclarer le nouveau type.
typEleve est le nom du type créé. Il pourra s’utiliser comme n’importe quel type simple.
« nom », « prénom » et « note » sont trois champs typés.
Déclaration de variables
e1, e2, e3 : typEleve
Utilisation des variables
e1.nom  « toto »
e1.prenom  « olivier »
e1.note  12
e2.note  e1.note
// affectation d’un champs
e3  e1
// affectation globale de l’enregistrement
Structures complexes
Exemple traité
On veut définir un type de donnée correspondant à un élève. Un élève a un nom, un prénom. Il a un note par
matière, et il y a plusieurs matières
Définition des types
struct typMatiere
nomMatiere : chaîne
ALGORITHMIQUE - Cours 02 - page 5/28 - Bertrand LIAUDET
note : entier
fin
struct typEleve
nom : chaîne
prénom : chaîne
tabMatières[NMAX] : typMatiere
fin
Déclaration de variables
e1, e2 : typEleve
Utilisation des variables
e1.nom  « toto »
e1.prenom  « olivier »
e1.tabMatiere[1].nomMatiere  « algo »
e1.tabMatiere[1].note  12
e1.tabMatiere[2].nomMatiere  « langage C »
e1.tabMatiere[2].note  15
e2.tabMatiere[1].nomMatiere  e1.tabMatiere[1].nomMatiere
e2.tabMatiere[1].note  e1.tabMatiere[1].note
e2.tabMatiere[2]  e1.tabMatiere[2]
e2.tabMatiere[2].note  e1.tabMatiere[2]
e3  e1
Renommer un type
Il peut être pratique de pouvoir renommer un type.
On utilisera la syntaxe suivante :
Syntaxe
type classe as tableau[50] typEleve
 commentaires
On utilise le mot-clé « type » pour renommer un type et le mot-clé « as » pour séparer l’ancien nom du nouveau
nom.
« classe » est le nouveau nom.
tableau[50] typEleve est le type qu’on veut renommer.
Usage
Le type « classe » s’utilise comme n’importe quel type :
cl1, cl2 : classe
ALGORITHMIQUE - Cours 02 - page 6/28 - Bertrand LIAUDET
2 - LES TABLEAUX
1.
Présentation
Le tableau
Un tableau est un nouveau type de variable qui permet de regrouper dans une seule variable plusieurs valeurs de
même type.
Soit « tab » un tableau d’entiers :

Pour accéder à un élément du tableau, on écrit par exemple : tab[2].

Le premier élément du tableau c’est tab[1] (tab[0] en langage C et dans les langages dérivés du C)

tab[1] c’est une variable comme une autre, ici de type entier.
Le taille du tableau
Le nombre de valeurs maximum que peut recevoir un tableau est posé au moment de la définition du tableau.
Ce nombre, c’est la taille du tableau.
C’est un paramètre constitutif du tableau.
Le nombre d’éléments du tableau
Un tableau n’est pas forcément entièrement rempli.
Il faut donc distinguer entre la taille et le nombre d’éléments du tableau à un moment donné.
Ce nombre est nécessaire pour pouvoir parcourir tous les éléments du tableau.
Imbrication de tableaux et d’enregistrements
Tableau d’enregistrement
Enregistrement de tableaux
2.
Méthodes de recherche
Recherche dans un tableau non trié
Pour rechercher un élément dans un tableau non trié, il faut parcourir tout le tableau.
Si on a N éléments dans le tableau, la recherche se fera en au maximum N tests, N/2 tests en moyenne.
Recherche dans un tableau trié : la recherche dichotomique
Pour rechercher un élément dans un tableau trié, on fait une recherche dichotomique.
Si on a N éléments dans le tableau, la recherche se fera en au maximum log2(N), soit environ 20 pour N = un
million.
3.
Méthodes de tri
Tri à bulles
Le principe est de réorganiser (inverser) les couples non classés tant qu’il en existe.
Tri par extraction (élémentaire, heapsort)
ALGORITHMIQUE - Cours 02 - page 7/28 - Bertrand LIAUDET
L’opération de base consiste à rechercher l’extremum dans la partie non triée et à le permuter avec l’élément
frontière, puis à déplacer la frontière d’une position.
Tri par insertion
L’opération de base consiste à prendre l’élément frontière dans la partie non triée et à l’insérer à sa place dans la
partie triée, puis à déplacer la frontière d’une position.
Autres méthodes
Il existe de nombreuses autres méthodes qui ne sont pas abordées ici.
4.
Exercices sur les tableaux
Tableaux à une dimension
Exercice 1
Ecrire une fonction qui calcule la somme des éléments d’un tableau.
Exercice 2
Ecrire une fonction qui détermine la valeur la plus grande d’un tableau. On renverra le maximum puis la position
du maximum dans le tableau.
Exercice 3
Ecrire une fonction qui décale les éléments d’un tableau vers le bas (le i-ième passe en (i-1)ième, le premier passe
en dernier (Nième).
Exercice 4
Ecrire une fonction qui décale les éléments d’un tableau vers le haut (le i-ième passe en (i+1)ième, le dernier
(Nième) passe en premier.
Exercice 5
Ecrire une fonction qui inverse un tableau : le premier élément est permuté avec le dernier, le deuxième avec
l’avant dernier, etc.
Exercice 6
Ecrire une fonction qui recherche la première occurrence d’une valeur dans un tableau.
Exercice 7
Ecrire une fonction qui recherche la première occurrence d’une valeur dans un tableau trié en utilisant la méthode
de recherche dichotomique.
Exercice 8
Ecrire une fonction qui tri un tableau en utilisant la méthode de tri par extraction. Le principe de ce tri est d’aller
chercher le plus petit élément du tableau pour le mettre en premier, puis de recommencer l’opération en partant du
second élément du tableau, puis du troisième, etc.
Exercice 10
Ecrire une fonction qui supprime une valeur dans un tableau trié.
ALGORITHMIQUE - Cours 02 - page 8/28 - Bertrand LIAUDET
Exercice 11
Ecrire une fonction qui ajoute une valeur dans un tableau trié.
Exercice 12
Ecrire une fonction qui élimine les doublons d’un tableau d’entiers. On considérera d’abord le tableau comme
étant trié puis on traitera le cas général.
Matrice
Exercice 1
Ecrire une fonction qui calcule la moyenne des sommes des lignes et la moyenne des sommes des colonnes d’une
matrice.
Exercice 2
Ecrire une fonction qui calcule la moyenne par ligne et par colonne dans une matrice.
Exercice 3
Ecrire une fonction qui multiplie deux matrices.
Avec A matrice n lignes, m colonnes. B matrice m lignes, p colonnes. C matrice n lignes, p colonnes.
Ci,j=somme(k=0, m) Ai,k * Bk,j.
Exercice 4
Ecrire une fonction qui trie une matrice par ordre croissant selon une colonne définie.
ALGORITHMIQUE - Cours 02 - page 9/28 - Bertrand LIAUDET
3 - LES POINTEURS
1.
Rappels sur la variable
Présentation
Une variable est caractérisée par :

un nom : n

un type : int

une valeur (ou contenu) : 3

une adresse : ad_n

un contenant : le carré dessiné (il est à l’adresse ad_n et sa taille est donné par son type)

un sens (ou signification) : par exemple, le nombre d'éléments d'un tableau.
n, int
3
ad_n
Le nom de la variable c'est "n". Le nom fait référence à (on peut dire c'est) soit la valeur, soit le contenant.
Si le nom "n" est utilisé en entrée (c'est-à-dire à droite de l'affectation, en entrée d'une fonction ou plus
généralement en entrée de toute expression), "n" c'est la valeur de "n".
Si le nom "n" est utilisé en sortie (c'est-à-dire à gauche de l'affectation, en sortie d'une fonction ou plus
généralement en sortie de toute expression), "n" c'est le contenant de n. On parle aussi de "lvalue" ("left value",
"valeur à gauche" de l'affectation, ou "valeur_g" 1).
Formalisme NTVA
On peut représenter une variable sous la forme d'un quadruplet : (nom, type, val, ad)
C'est le formalisme NTVA : (Nom, Type, Val, Adresse)
nom
type
Val
ad
Exemple : (a, entier, 12, ad_A)
A
entier
12
adA
Déclaration et usage
1

Quand on déclare une variable, on crée un contenant qui a un nom, un type et une adresse. La valeur est
inconnue.

Formalisme NTVA : (a, entier, ?, adA)

Quand on affecte une valeur à une variable, on donne une valeur au contenant.
K&R91 p. 196, §A5.
ALGORITHMIQUE - Cours 02 - page 10/28 - Bertrand LIAUDET

2.
Initialiser une variable, c'est donner pour la première fois une valeur au contenant de la variable. A noter que
avant l'initialisation, la variable a quand même une valeur. En effet les bits constituant la variable sont dans un
certain état (0 ou 1). Cet état, interprété selon le type, aboutit forcément à une valeur. Donc la valeur
d'initialisation c'est la deuxième valeur que prend la variable.
Pointeurs et opérateur & et *
Le type pointeur
Un pointeur est une variable qui contient comme valeur une adresse.
Une adresse est de type « pointeur ».
Un type pointeur est spécialisé en fonction du type de variable auquel il correspond.
On l’écrit : « type * ».
Par exemple : « entier * », « réel * », « TypEleve * », etc
Opérateur &
L’opérateur unaire & appliqué à une variable produit une valeur : l’adresse de la variable à laquelle il s’applique.
La valeur de &a c’est l’adresse de a.
Opérateur *
L’opérateur unaire * appliquée à une valeur de type adresse produit une variable (et non pas une valeur). Cette
variable, c’est celle dont l’adresse correspond à la valeur de type adresse à laquelle on applique l’opérateur.
Exemple
Soit n un entier et pt_n un pointeur d'entier. On écrit ça :
n entier
pt_n entier *
pt_n est une variable avec ses caractéristiques : elle a une adresse, comme toute les variables et son type est
"pointeur d'entier" : int *.
pt_n entier *
ad_pt_n
n, entier
ad_n
Pour affecter à pt_n la valeur de l'adresse de n, on écrira :
pt_n  &n
Schématiquement cela donne :
pt_n entier *
n, entier
ad_n
ad_pt_n
ad_n
On dit que pt_n est un pointeur d'entier, comme on dit que n est un entier.
Définition
*pt_n c'est la variable dont l'adresse est donnée par la valeur de "pt_n" (dans notre exemple c'est n).
On dit aussi :
* pt_n c'est la variable pointée par pt_n.
ALGORITHMIQUE - Cours 02 - page 11/28 - Bertrand LIAUDET
*pt_n peut s’utiliser comme n’importe quelle variable.
On peut écrire :
*pt_n  5
Schématiquement cela donne :
pt_n entier *
n, entier
ad_n
5
ad_pt_n
ad_n
allocation, réservation de mémoire
new(pt)
avant : (pt, type*, ?, adpt)
après : (pt, type*, ad, adpt) ---> (*pt, type, ?, ad)
Quand on alloue dynamiquement une variable, on crée une variable qui n'a pas de nom.
Notez que pt est en sortie bien sur puisque sa valeur a été modifiée (elle passe de ? à ad).
pt est aussi en entrée car pour faire l'allocation, j'ai besoin de connaître le type de pt (type*), ce qui me permet de
déterminer le type de la variable créer et donc la taille de l'espace mémoire de cette variable.
Est en entrée une variable dont on utilise une des caractéristiques suivantes : la valeur ou le type. Pour les
algorithmes de haut niveau, seule l'utilisation de la valeur compte.
libération de la mémoire
free (pt)
avant : (pt, type*, ad, adpt) ---> (*pt, type, ?, ad)
après : (pt, type*, ad, adpt)
La variable pointée par pt est libérée (elle n’existe plus).
Notez que la valeur de pt n'a pas été modifiée par la libération : pt n'est qu'en entrée.
ALGORITHMIQUE - Cours 02 - page 12/28 - Bertrand LIAUDET
3.
Tableau de pointeurs
Un tableau peut contenir des pointeurs
L’intérêt d’un tableau de pointeur, du point de vue de l’optimisation, c’est de limiter les recopies à la recopie de
pointeurs (pour éviter de recopier toute une structure, par exemple).
4.
Exercices sur les pointeurs
Exercice 1
Décrire l’évolution de chaque variable après chaque instruction.
int x, n, *pt_n;
pt_n = &n;
*pt_n = 5;
n = 7;
x = *pt_n;
Exercice 2
Quel est le résultat des instructions suivantes :
int n, * ad1;
* ad1 = 3;
Exercice 3
Quel est le résultat des instructions suivantes :
int n, * ad1;
ad1 = &n;
* ad1 = 3;
Exercice 4
Soit les tois instructions suivantes :
int *ad1; int n=10; ad1 = &n
Que valent les expressions suivantes après les deux instructions précédentes. Faire des schémas.
ad1
&*ad1
*&ad1
n
*&n
&*n
ALGORITHMIQUE - Cours 02 - page 13/28 - Bertrand LIAUDET
4 - LES LISTES
1.
Présentation
Présentation générale : la chaîne, le maillon
Structure d’un maillon.
Variable liste : la tête de liste.
Liste simplement chaînées
Liste doublement chaînées
Listes circulaires
2.
Liste simplement chaînées
Structure d’un élément de liste
Afficher les éléments de la liste.
Ajouter un élément dans la liste
Supprimer un élément dans la liste
3.
Variantes
Liste doublement chaînée
Liste circulaire
Liste avec compteur de maillons
4.
Exercices sur les listes
Exercice 1
Ecrire un algorithme qui permet de trouver le maximum dans une liste de réels.
Exercice 2
Ecrire un algorithme qui permet d’ajouter un élément en queue de liste.
Exercice 3
Ecrire un algorithme qui permet d’ajouter un élément dans une liste triée.
Exercice 4
Ecrire un algorithme qui permet de supprimer toutes les occurrences d’un élément dans une liste non triée.
ALGORITHMIQUE - Cours 02 - page 14/28 - Bertrand LIAUDET
Exercice 5
Ecrire un algorithme qui permet de supprimer tous les doublons dans une liste non triée.
Exercice 6
Ecrire un algorithme qui inverse une liste chaînée (sans recopier ses éléments).
Exercice 7
Ecrire un algorithme qui fusionne deux listes d’entiers triés en une seule liste triée. Les deux listes initiales seront
détruites. On évitera de recopier les éléments.
Exercice 8
Ecrire un algorithme qui éclate une listes d’entiers en deux listes : une liste dont les valeurs seront supérieures à
une limite donnée, et une liste dont les valeurs seront inférieures. La liste initiale sera détruite. On évitera de
recopier les éléments.
Exercice 9
Le « problème de Joseph ». Soit une liste contenant dans l’ordre les n premiers entiers de N. Ecrire un algorithme
qui affiche et supprime les nœuds de k en k. jusqu’à ce que la liste soit vide. Exemple : n = 8 et k = 3. On affiche :
3, 6, 1, 5, 2, 8, 4, 7.
ALGORITHMIQUE - Cours 02 - page 15/28 - Bertrand LIAUDET
5 - RECURSIVITE
1.
Présentation
Principe
Une procédure (ou une fonction) est récursive quand elle s’appelle elle-même.
La récursivité est l’équivalent d’une boucle sans fin : le problème est de déterminer une condition de sortie.
Le problème algorithmique se ramène souvent à l’expression d’une suite mathématique.
Exemple : somme des N premiers nombres
Approche itérative
S = 1+2+3 ... + N-1 + N. On boucle N fois et on somme tous les nombres. Le problème est d’initialiser S : ici à 0.
 Algorithme
Somme(N) : entier // somme des N premiers nombres
S=0 ;
Pour i de 1 à N
S=S+i
FinPour
Return S
Fin
Approche récursive : formule de suite
S(0) = 0 : c’est la condition de sortie
S(N) = S(N-1) + 1 : c’est la formule récursive
 Algorithme
Somme(N) : entier // somme des N premiers nombres
Si N=0 return N ;
Return S(N-1) + 1;
Fin
Remarque
Il n’est pas toujours évident de trouver une formulation sous la forme d’une suite. Il faut toutefois chercher la
condition de sortie et la formule récursive.
Intérêt et limite de la récursivité
Intérêt
L’intérêt de la récursivité est qu’elle facilite considérablement l’écriture de certains algorithmes, particulièrement
les algorithmes sur les arbres.
Limites
La récursivité est limitée car le nombre d’appels récursifs est limité : environ un centaine au maximum (chaque
appel récursif implique pour le programme de mémoriser tout l’environnement, ce qui est coûteux en mémoire. En
général, les compilateurs limite le nombre d’appels récursifs à une centaine. Chaque environnement est empilé
pour être ensuite dépilé, d’où le message d’erreur : « stack overflow ».).
Il faut donc vérifier que cette limitation n’est pas contraignante.
ALGORITHMIQUE - Cours 02 - page 16/28 - Bertrand LIAUDET
Dans l’exemple traité, l’usage de la récursivité est à proscrire car on peut souhaiter calculer la somme des 10 000
premiers nombres. L’usage de la boucle est toutefois à optimiser en utilisant la formule = S = N(N+1)/2 !
2.
Exercices
Exercice 1
Ecrire l’algorithme récursif permettant de calculer N !
Le choix de la récursivité est-il pertinent ?
Exercice 2
On désire calculer le terme d’ordre n de la suite de Fibonacci définie par :
F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2).
Écrire une fonction itérative et une fonction récursive qui permet de calculer F(n) et un programme pour la tester.
Le choix de la récursivité est-il pertinent ?
Exercice 3
Ecrire l’algorithme récursif permettant de calculer X puissance N
Le choix de la récursivité est-il pertinent ?
Exercice 4
Ecrire l’algorithme récursif permettant de faire une recherche dichotomique dans un tableau trié.
Le choix de la récursivité est-il pertinent ?
Exercice 5
Ecrire l’algorithme récursif permettant de faire une recherche dans une liste chaînée.
Le choix de la récursivité est-il pertinent ?
ALGORITHMIQUE - Cours 02 - page 17/28 - Bertrand LIAUDET
6 - LES ARBRES
1.
Modèle logique des arbres
Un arbre est une collection d’éléments appelés « nœuds ».
Ces nœuds sont reliés entre eux par un lien orienté : le « noeud parent » est au départ du lien, le « noeud enfant »
est à l’arrivée du lien.
Un noeud a un parent et un seul sauf un noeud particulier qui n’a pas de parent : la « racine ».
2.
ABOH (arbre planaire)
Modèle logique
Un ABOH (arbre binaire orienté horizontalement) ou arbre « planaire » est un arbre dans lequel :

les parents n’ont pas plus de deux enfants (arbre binaire)

Les enfants sont distingués en « enfant gauche » et « enfant droit »

les valeurs de « enfant gauche », parent, et « enfant droit » sont triées (arbre orienté horizontalement).
Modèle physique des données – Version dynamique
Principe
arbre = pointeur sur un nœud
nœud = éléments de l'arbre; l'élément contient des informations et deux pointeurs sur deux nœuds. C’est pointeurs
sont appelés sous arbre droit et gauche, sad et sag.
racine = nœud origine de l'arbre = premier nœud pointé par l'arbre. Chaque nœud peut être considéré comme la
racine d'un arbre
feuille = nœud qui n'a pas de sous arbres
branche = suite des nœuds de la racine jusqu'à une feuille sans jamais remonter
Exemple
10
6
14
3

8


12

17


13

ALGORITHMIQUE - Cours 02 - page 18/28 - Bertrand LIAUDET


Définition des types
Type TypElementArbre
info : entier
sag : TypElementArbre *
sad : TypElementArbre *
fin
Type Arbre as TypElementArbre *
Algorithmes
Méthode
Quel que soit l'exercice qu'on a à résoudre, il faut se demander :

Est-ce qu'on va parcourir tous les nœuds ?

Est-ce qu'on va parcourir une branche pour rechercher un nœud particulier ?
Selon la réponse, on aboutira à un algorithme type ou à un autre.
Deux algorithmes types
Les deux algorithmes types correspondent aux deux façons de circuler dans un arbre :
 Parcourir tous les nœuds
Algorithme de parcours en ordre (pour l'ordre), en post ordre (pour remonter les info des feuilles à la racine), en
pré ordre (pour archiver et reconstituer l'arbre) : ce sont des algorithmes récursifs. Leurs versions itératives sont
compliquées et utilisent des piles.
 Parcourir une branche
Le parcours d’une branche est utilisé pour l’accès à un élément d’un arbre : pour la recherche, l’insertion, la
suppression, etc.
L’algorithme est de même type que celui d’un parcours de liste chaînée. Il peut être itératif ou récursif.
Algorithme type de parcours de tous les noeuds
tsLesNoeudsEnOrdre(A)
si A!= 0
// traiter(*a.info) : pour le pré-ordre
tsLesNoeudsEnOrdre(*a.sag)
traiter(*a.info) // pour l’ordre
tsLesNoeudsEnOrdre(*a.sad)
// traiter(*a.info) : pour le post-ordre
finsi
ALGORITHMIQUE - Cours 02 - page 19/28 - Bertrand LIAUDET
Algorithme type de recherche de tous les noeuds
 Version itérative
arbre : chercher(A, info)
nc  A
tq nc != 0
si *nc.info = info
return nc
sinon si *nc.info < info
nc  *nc.sag
sinon
nc  *nc.sad
finsi
fintq
return null
fin
 Version récursive
arbre : chercher(A, info)
si A = null
return A
finsi
si *A.info = info
return A
sinon si *A.info < info
chercher (*nc.sag, info)
sinon
chercher(*nc.sad, info)
finsi
fin
3.
Arbres équilibrés (AVL)
Le problème des arbres est qu’ils peuvent devenir déséquilibré, c’est-à-dire ressembler à une liste chaînée.
Les arbres équilibrés sont des arbres dont les algorithmes d’insertion et de suppression sont adaptés de telle sorte
qu’ils permettent de maintenir l’équilibre de l’arbre.
Le critère d’équilibre parfait est : pour tout nœud, les nombres de nœuds du SAG et du SAD diffèrent au
maximum de 1.
Un critère d’équilibre partiel courant est : pour tout nœud, les hauteurs du SAG et du SAD diffèrent au
maximum de 1.
4.
Arbres B (B trees)
Présentation
L’arbre B est un compromis entre les organisations arborescentes et les organisations séquentielles indexées.
Ce sont des arbre n-aires orientés horizontalement (planaires).
ALGORITHMIQUE - Cours 02 - page 20/28 - Bertrand LIAUDET
Un nœud est appelé « page » et contient plusieurs enregistrements successifs.
L’objectif d’une telle structure est de limiter les transferts disques.
Principes spécifiques

Un arbre B a un numéro d’ordre : N.

Les nœuds ont au maximum 2 * N + 1 enfants.

Les nœuds non-feuilles et non racines ont au minimum N + 1 enfants.

Chaque nœud non-feuille porte NF-1 enregistrements, avec NF = nombre de fils du nœud.

Chaque nœud feuille porte 2* N enregistrements au maximum (2*N fiches ou 2*N tuples par exemple).
Exemple d’arbre B d’ordre 1
3
6
9
18
12
15
10-11
1-2
4-5
7-8

21
24
16-17
13

14

19-20
22-23
25-26
A noter que cet arbre B est un arbre BB.
5.
Arbres BB
Ce sont des arbres B dit « de Bayer » : arbre BB.
Ils contiennent 1 ou 2 enregistrements par page.
Ils sont aussi appelés « arbre 2-3 » car chaque page contient 2 ou 3 pointeurs sur ses pages filles.
Ce type d’arbre n’est pas intéressant pour stocker une table sur disque car la petite taille des pages implique un
grand nombre d’accès disque.
Par contre, ce type d’arbre est intéressant pour gérer des tables entièrement en mémoire.
6.
Arbres SBB (bicolores).
Ce sont des arbres BB symétrique : SBB pour Symetric Binary B Tree. On parle aussi d’arbres « bicolores ».
Le SBB est un arbre BB équilibré.
ALGORITHMIQUE - Cours 02 - page 21/28 - Bertrand LIAUDET
7.
Exercices sur les ABOH
Exercice 1
Définir la structure d’un élément d’arbre binaire.
Construire un arbre binaire avec les séries de valeurs suivantes :
5, 2, 1, 10, 8, 12
7, 5, 10, 1, 3, 12, 30, 25, 1, 2, 3
Qu’est-ce qu’un nœud ?
Qu’est-ce qu’une feuille ?
Qu’est-ce qu’une racine ?
Qu’est-ce qu’une branche ?
Exercice 2 : parcours d’une branche : recherche d’un élément
Ecrire l’algorithme itératif et récursif de recherche d’un élément dans un arbre.
Exercice 3 : parcours de tout l’arbre en ordre, pré-ordre, post-ordre
Afficher tous les éléments d’un arbre, dans l’ordre croissant (en ordre). Ecrire l’algorithme correspondant.
Afficher tous les éléments d’un arbre en « pré-ordre » . Ecrire l’algorithme correspondant.
Afficher tous les éléments d’un arbre en « post-ordre » . Ecrire l’algorithme correspondant.
Remarque : intérêt de l’ordre, du pré-ordre, et post-ordre
L’ordre, comme son nom l’indique, permet de parcourir l’arbre dans l’ordre.
Le pré-ordre permet de traiter chaque nœud complètement (comme un sous-arbre), en commençant par la racine.
En enfilant les résultats, on peut reconstruire l’arbre en défilant.
Le post-ordre permet de traiter chaque nœud complètement (comme un sous-arbre), en finissant par la racine. En
empilant les résultats, on peut reconstruire l’arbre en dépilant.
Exercice 4 : Compter le nombre d’éléments d’un arbre binaire
Exercice 5 : Ajouter un élément dans un arbre binaire
Exercice 6 : Suppression d’un élément dans un arbre binaire
On commencera par écrire un algorithme qui permet de remplacer la racine par le plus grand élément de son sousarbre gauche, et un algorithme qui permet de remplacer la racine par le plus petit élément de son sous-arbre droit.
Ensuite on écrira l’algorithme de suppression d’un élément dans un arbre.
Exercice 7 : Calculer la hauteur d’un arbre binaire
Exercice 8 : Vérifier l’équilibre partiel d’un arbre
Arbre parfaitement équilibré : pour tout nœud, abs ( nbNoeuds(sag) - nbNoeuds(sad) ) <=1
Arbre partiellement équilibré : pour tout noeuc, abs ( hauteur(sag) –hauteur(sad) ) <=1
ALGORITHMIQUE - Cours 02 - page 22/28 - Bertrand LIAUDET
7 - LES GRAPHES
1.
Présentation
ALGORITHMIQUE - Cours 02 - page 23/28 - Bertrand LIAUDET
8 - HACHAGE
1.
Présentation
ALGORITHMIQUE - Cours 02 - page 24/28 - Bertrand LIAUDET
9 - LES TAD : VERS LA P.O.O.
1.
Présentation générale des TAD
Présentation
TAD : type abstrait de donnée.
Un TAD est un type complexe caractérisé par sa structure et par un ensemble de primitives permettant de s’en
servir.
Principaux TAD
Chaînes de caractères
Piles
Files
Collections
Fichiers
2.
Les chaînes de caractères
Présentation
Une chaîne de caractères est un nouveau type : « Chaîne »
Les constantes chaînes de caractères sont entre guillemets, tandis que les caractères sont entre apostrophes.
Primitives d’utilisation des chaînes de caractères :

Longueur (ch) : entier // renvoie la longueur d’une chaîne.

Concat (ch1, ch2) : chaîne // renvoie la concatenation de deux chaînes (on peut aussi utiliser le signe « + »)

Substr (ch, debut, lgr) : chaîne // renvoie le morceau de chaîne commençant en « début » et de longueur
« lgr ».

ch[4] : caractère // renvoie le 4ème caractère de la chaîne (même principe que pour un tableau)
Dans les algorithmes, on peut appliquer les primitives de chaînes aux caractères.
Exercice 1
Écrire un algorithme qui détermine si une chaîne est un palindrome (exemples : Laval, radar, kayak, « Engage le
jeu que je le gagne »).
Exercice 2
Ecrire un algorithme qui détermine si une chaîne est un anagramme d’une autre (exemples : aimer et marie,
baignade et badinage).
Exercice 3
Ecrire un algorithme qui compte les occurrences d’un mot dans un texte.
Exercice 4
Ecrire un algorithme qui compte les occurrences de tous les mots d’un texte. L’algorithme permettra de produire
un fichier avec la liste des mots comptés et triés par ordre alphabétique.
Dans un premier temps, on écrira l’algorithme en se dotant de sous-procédures qui traitent les principaux
problèmes.
ALGORITHMIQUE - Cours 02 - page 25/28 - Bertrand LIAUDET
On considère que les séparateurs de mots sont des caractères contenus dans une chaîne de séparateurs. On ne
s’intéresse qu’aux mots d’au moins 3 lettres. On se donne un tableau de mots d’au moins 3 lettres pour lesquels on
ne fera pas le calcul.
3.
Les piles
Présentation
Une pile est une structure de données permettant de gérer des collections d’éléments de même type, le principe
d’utilisation étant que le dernier entré sera le premier sorti : LIFO (Last In, First Out, principe de la pile
d’assiettes).
Une pile est un nouveau type : typPile.
Les primitives permettant d’utiliser une pile sont les suivantes :

initPile (p) // permet d’initialiser une pile.

pileVide (p) : booleen // dit si la pile est vide

pilePleine (p) : booleen // dit si la pile est pleine

dépiler (p, val, ok) // dépile la valeur val de la pile p. Ok vaut faux si la pile était vide. ES :p :typPile.
S:val:typeAuChoix. S:ok:booleen.

empiler (p, val, ok) // empile une valeur val dans la pile p. Ok vaut faut si la pile était pleine. ES :p :typPile.
E:val:typAuChoix. S :ok :booleen.
Exercice 1
La notation algébrique classique est la suivante : 5* ( (9 + 8)*(4 + 6) + 7 )
Elle peut être transformée par une écriture dite en « polonaise inversée » : 5 9 8 + 4 6 + * 7 + *
Ou encore : 9 8 + 4 6 + * 7 + 5 *
En notation polonaise inversée (notation post-fixée), l’opérateur figure après les opérandes sur lesquels il agit.
La notation est gérée comme une pile : on empile les opérandes, et on en dépile deux dès qu’on tombe sur un
opérateur, on fait l’opération et on empile le résultat. Par exemple : on empile 9, puis 8, puis on les dépile, on fait
l’opération 9+8 et on empile le résultat 17. Puis on empile 4, puis 6 et on les dépile, etc.
Ecrire un algorithme qui gère avec une pile une calculette en polonaise inversée. On considèrera que la calculette
ne contient les touches suivantes :
Chiffres : 10 touches pour constituer les opérandes : 0 à 9. (On ne gère pas la virgule, on ne gère la saisie que de
chiffres <10).
Opérateurs binaires : 4 touches d’opérateur : +, -, *, / . (On ne gère pas les opérateurs unaires).
Annuler : 1 touche « ESC » pour tout annuler.
Ecrire l’algorithme de la calculette en utilisant une pile et les primitives de pile. En cas d’erreur, on annulera tout le
calcul en cours.
Exercice 2

Définir la structure de donnée statique nécessaire pour gérer une pile (structure avec un tableau).

Ecrire les algorithmes des primitives de gestion des piles.
ALGORITHMIQUE - Cours 02 - page 26/28 - Bertrand LIAUDET
4.
Les files
Présentation
Une file est une structure de données permettant de gérer des collections d’éléments de même type, le principe
d’utilisation étant que le premier entré sera le premier sorti : FIFO (FIRST In, First Out, principe de la file
d’attente).
Une pile est un nouveau type : typFile.
Les primitives permettant d’utiliser une pile sont les suivantes :

initFile (p) // permet d’initialiser une pile.

fileVide (p) : booleen // dit si la file est vide

filePleine (p) : booleen // dit si la file est pleine

défiler (f, val, ok) // défile la valeur val de la file f. Ok vaut faux si la file était vide. ES :p :typFile.
S:val:typeAuChoix. S:ok:booleen.

enfiler (f, val, ok) // emfile une valeur val dans la file f. Ok vaut faut si la file était pleine. ES :p :typFile.
E:val:typAuChoix. S :ok :booleen.
Exercice 1
Ecrire un algorithme qui permette de d’afficher tous les éléments d’une file en conservant la file et en n’utilisant
que les primitives de file.
Exercice 2
5.

Définir la structure de donnée statique nécessaire pour gérer une file (structure avec un tableau circulaire).

Ecrire les algorithmes des primitives de gestion des files.
Les collections
Une collection est une structure de données qui permet de gérer une collection quelconque.
Les primitives permettant d’utiliser une collection sont :
initCollection (c)
collectionVide (c). Renvoie vrai si la collection est vide.
collectionPleine (c). Renvoie vrai si la collection est pleine.
ajouter(c, val, ok). Ajoute un élément de valeur val dans la collection/
retirerVal(c, val, ok). Retier l’élément de valeur val de la collection.
rechercher(c, val, ok) : entier // Récupère la position de l’élément de valeur val dans la collection. 0 si pas trouvé.
getCollec(c, i) : val // Renvoie la valeur du ième élément de la collection. Equivaut à c[i].
affecter(c, i, val) // Affecte val dans le ième élément de la collection. Equivaut à c[i] <- val.
Les tableaux, les piles, les files, les listes, les arbres sont différents types de collection.
6.
Les fichiers
Les fichiers sont une forme de TAD. On les abordera à la fin de ce document.
ALGORITHMIQUE - Cours 02 - page 27/28 - Bertrand LIAUDET
10 - USAGES TECHNIQUES DES POINTEURS
1.
Gestion d’une pile LIFO avec une liste chaînée
2.
Gestion d’une file FIFO avec une liste chaînée
3.
Pointeurs et tableaux
Tableaux de pointeurs
Tableau et chaîne de caractères
Tableaux et pointeurs
4.
Pointeurs et chaînes de caractères
5.
Pointeurs et mode de passage des paramètres
ALGORITHMIQUE - Cours 02 - page 28/28 - Bertrand LIAUDET
Téléchargement