Vous êtes sur la page 1sur 200

Algorithmique et

Structures de données
Partie 1 (5h)

Ye-Qiong SONG

Professeur à l’ENSEM-Université de Lorraine,


song@loria.fr
Objectifs et contenu
• Objectifs:
– Notions avancées en algorithmique et programmation
– Programmation en java
• Contenu:
– 2h CM, 1h TD, 3h TP sur l’initiation à Java
– 5h: Algorithmique et Structures de données
dynamiques (liste, pile, graphe, arbre, tas, table
associative/dictionnaire, hachage), collection java
– 2h: Algorithmique: problèmes combinatoires et
programmation dynamique
– 1h: Vérification et test unitaire de programme

cours d’algo. et prog. par Y.Q. Song 2


Contenu
• Contenu en Tutorat et TP (prévision):
– Tutorat1: Initiation à java
– Tutorat2: Liste chaînée et graphe
– Tutorat3: Arbres
– Tutorat4: Algorithme « backtracking »
– Tutorat5: Vérification et test unitaire
– TP1: Programmation objet en java
– TP2: Listes chaînées, graphes et Dijkstra
– TP3: Algorithmes sur arbres
– TP4: Algorithme « Backtracking »
– TP5: Test unitaire (Junit) sur exemple de Hash table
Références: principalement selon le cours de l’école polytechnique
(Philippe Baptiste, Luc Maranget et Olivier Bournez), poly
accessible sur le WEB
cours d’algo. et prog. par Y.Q. Song 3
Rappel: problèmes classiques en algo.

• Tri
• Recherche
• Traitement des chaînes de caractères
• Graphes (le plus court chemin, coloriage,…)
• Problèmes combinatoires (voyageur de
commerce, sac à dos)
• Calcul numérique (intégrale, systèmes
d’équations, …)
cours d’algo. et prog. par Y.Q. Song 4
Stratégies de conception d’algo.

• Force brute (recherche exhaustive, OK pour des pb simples)


• Diviser pour régner (découper un problème en petite taille,
typiquement à l’aide de la récursivité)
• Approche gloutonne (espérer que l’optimalité locale conduit à
l’optimalité globale,
mais peut ne pas marcher dans certains cas,
eg. rendu de monnaie)
• Programmation dynamique (optimiser des sommes de fonctions
monotones croissantes sous contrainte, par le principe : toute solution
optimale s'appuie elle-même sur des sous-problèmes résolus
localement de façon optimale)
• Backtracking (ne pas explorer des impasses avec une approche de
retour en arrière à sans exploiter tout espace d’état)

cours d’algo. et prog. par Y.Q. Song 5


Exemple 1: problème de rendu de
monnaie
• Problème: minimiser le nombre de pièces de
monnaie à rendre
• Suivant le système de pièces, l'algorithme
glouton peut être optimal ou non
– Optimal dans le système de pièces européen
– Non optimal dans un système de pièces (1, 3, 4)
– exemple: rendre 6 centimes
– Question : quelle solution optimale si limite de
stock de pièces (e.g. distributeur de boissons) ?
Réponse possible : cf TP distributeur, Sac à dos
cours d’algo. et prog. par Y.Q. Song 6
Exemple 2: un bar écologique qui
recycle
• Prix d’une bouteille de bière: 2€
• 2 bouteilles vides = une bière
• 4 capsules = une bière
• Questions:
– combien de bières au maximum pour 10€ ?
– comment allez-vous y prendre (votre algo.) ?

cours d’algo. et prog. par Y.Q. Song 7


Exemple 3: algo. Min-Max
• Souvent utilisé en IA très basique pour jeux à
deux
• Joueur1 maximise son gain et Joueur2 minimise le
gain d’adversaire (e.g. TP puissance4,
reversi/Othello)
• L’arbre de coups possibles souvent trop élevé è
élagage de certaines branches « inintéressantes »
(limiter la profondeur, coupes alpha et beta,
branch & bound (séparation et évaluation), …)

cours d’algo. et prog. par Y.Q. Song 9


Exemple 3: algo. Min-Max, jeu
• Jeu de Nim à 3 allumettes, comment gagner ?

Arbre du jeu

Source image: http://www.grappa.univ-


lille3.fr/~torre/Enseignement/Cours/Intelligence-
Artificielle/jeux.php
cours d’algo. et prog. par Y.Q. Song 10
Exemple 3: algo. Min-Max, jeu
• Jeu de Nim à 3 allumettes, comment gagner ?
Etiquetage de feuilles
+1 gagnant
-1 perdant

Source image: http://www.grappa.univ-


lille3.fr/~torre/Enseignement/Cours/Intelligence-
Artificielle/jeux.php
cours d’algo. et prog. par Y.Q. Song 11
Exemple 3: algo. Min-Max, jeu
• Jeu de Nim à 3 allumettes, comment gagner ?
Remonter les évaluations depuis les feuilles jusqu'à la racine
Bleu : maximise
Vert : minimise

Exercice: l’arbre du jeu avec 4 ? et 6 allumettes ?


Appliquer Min-Max à Puissance 4
Source image: http://www.grappa.univ-
cours d’algo. et prog. par Y.Q. Song lille3.fr/~torre/Enseignement/Cours/Intelligence- 12
Artificielle/jeux.php
37
Exemple
Problème du 4: Sac
sac à à dos
dos (*) (Knapsack)
Résolution
Déjà vu en Python [cours V. Chevrier]
© CC BY-SA 2.5
Exemple:
c peut supporter 15 kg.
ie a echargee e =e 15cha ge
.
paquets =de12,
avoir un sous-ensemble ces2, 4, 1,
paquets 1,1 [source: Wikipedia]
plissent complètement mon sac ?
Exemple:
= 15 charge = 14 (15-1)
= 12, 2, 4, 1, 1 paquets = 12, 2, 4, 1, 1
=
Exemple:
Exemple:
Exemple:
charge = 14charge = 13
charge = 15
paquets = 12, 2, 4, 1, 1
réponse= paquets = 12, 2, 4, 1
paquets = 12, 2, 4, 1, 1,1
réponse=
cours d’algo. et prog. par Y.Q. Song
(*) ici solution exacte 13
35
Exemple 4: Sac à dos (Knapsack)
Un sac a dos de capacité b avec des produits x1, x2, …, xn qui
ont un poids b1, b2, …, bn et rapportent un prix c1, c2, …, cn par
unité, de façon à maximiser le profit :
Max Z = c1x1+ c2x2+ … +cnxn
tel que b1x1+ b2x2+ … +bnxn ≤ b
xi ∈ ℝ
Exemple:
Max Z = x1 + 2x2 + 3x3 + 4x4
tel que 4x1 + 3x2 + 5x3 + 2x4 ≤ 12
Avec pièces de produits disponibles:
x1 ∈ {0, 1, 2, 3}
x2 ∈ {0, 1, 2}
x3 ∈ {0, 1}
x4 ∈ {0, 1, 2, 3, 4}
cours d’algo. et prog. par Y.Q. Song 14
Exemple 4: Sac à dos (arbre complet)
x1 + 2x2 + 3x3 + 4x4 4x1 + 3x2 + 5x3 + 2x4 ≤ 12

x4, x2, x3, x1: ordre décroissant prix/poids à méthode exacte


Question: une méthode pour éviter d’explorer tout l’arbre?
cours d’algo. et prog. par Y.Q. Song 15
Exemple 4: Sac à dos (branch&bound)
x1 + 2x2 + 3x3 + 4x4 4x1 + 3x2 + 5x3 + 2x4 ≤ 12

Evaluation:
cout réel du produit + cout estimé du produit suivant
e.g. pour x4
c4x4 + c2(b-x4b4)/b2

x4 = 4, éval = 4*4 +2(12 - 4*2)/3 = 18,67


x4 = 3, éval = 4*3 +2(12 - 3*2)/3 = 16
x4 = 2, éval = 4*2 +2(12 - 2*2)/3 = 13,33
x4 = 1, éval = 4*1 +2(12 - 1*2)/3 = 10,67
x4 = 0, éval = 4*0 +2(12 - 0*2)/3 = 8
cours d’algo. et prog. par Y.Q. Song 16
Introduction à structures de données
• Certaine manière d’organisation des données afin
de permettre un traitement automatique de ces
dernières plus efficace et rapide (e.g. diminuer la
complexité)
• Structures finies
– Constantes, variables, …
• Structures indexées
– Tableaux, tableaux associatifs ou indexé (c’est à dire
dictionnaires avec clé-valeur)
• Structures récursives
– Listes chaînées, graphe, arbre, …
cours d’algo. et prog. par Y.Q. Song 17
1: Structures linéaires (liste)
• Modèles de données les plus élémentaires
• Une séquence non ordonnée d’éléments,
accessibles de façon séquentielle
s = <e1, e2, …, en>
• Chaque élément a un successeur, sauf le
dernier
• Opérations de base: recherche (parcourt),
ajout et suppression
• Les structures les plus connues: liste (et
ses formes particulières: pile et file)
cours d’algo. et prog. par Y.Q. Song 18
Les listes
• Liste: une séquence finie d’éléments repérés selon leur
rang (indice)
• Ajout et suppression peuvent se faire à n’importe où dans
la séquence
• Peut être implantée en utilisant un tableau ou une
structure chaînée - ensemble d’éléments

- longeur()
- ième()
- supprimer()
- ajouter()

• « Vector » est un exemple de listes (ArrayList ou LinkedList


aussi)
cours d’algo. et prog. par Y.Q. Song 19
Les listes
• Implantation en Java, utilisant « interface »
comme « design pattern »
public interface Liste{
public int longueur();
public Object ième(int r) throws RangInvalideExcept;
public void supprimer(int r) throws RangInvalideExcept;
public void ajouter(int r Object e) throws RangInvalideExcept;
}

public class RangInvalideExcept extends RuntimeException {


public RangInvalideExcept(){
super();
}
}

cours d’algo. et prog. par Y.Q. Song 20


Listes implantées avec tableaux
0 1 2 3 4 éléments.length-1
éléments 5 -13 23 182 100 … …

lg = 5

En utilisant un tableau, l’opération ième() est simple grâce à l’indice


du tableau

Algorithme ajouter(r, e)
Algorithme supprimer(r)
pourtout i de lg-1 à r-1 faire
pourtout i de r à lg faire
éléments[i+1] = éléments[i]
éléments[i-1] = éléments[i]
finpour
finpour
éléments[i-1] = e
lg = lg-1
lg = lg+1
Rmq: la suppression de l’élément de tête est coûteuse à cause du décalage de tous
les éléments à temps de calcul long (e.g. cas dans une file d’attente FIFO)
cours d’algo. et prog. par Y.Q. Song 21
Listes implantées avec tableaux
• Solution: gestion circulaire d’un tableau
– Indice de début et indice de fin de la liste
– Plus besoin du décalage lors de la suppression de l’élément de tête, donc
plus rapide. Demande un peu plus de mémoire (deux indices au lieu d’un)
tête queue
éléments 23 182 100 20 30

queue tête
éléments 100 20 30 23 182

Incrémentation en fin du tableau (suppr en tête ou ajout en queue):


tête = (tête= = éléments.length-1) ? 0 : ++tête
queue = (queue= = éléments.length-1) ? 0 : ++queue
Indice r = tête+r-1
Décrémentation en début du tableau (suppr en queue ou ajout en tête ):
tête = (tête= = 0) ? éléments.length-1 : --tête
cours queue
d’algo. et=prog.
(queue= =Song
par Y.Q. 0) ? éléments.length-1 : -- queue 22
Listes implantées avec structures
chaînées
• Liste avec chaînage simple, permet un parcours
de tête vers la queue
tête tête
5 20 4 9 45

• Liste avec chaînage double, permet un parcours


dans les deux sens
tête queue tête queue

5 20 4 9 45

cours d’algo. et prog. par Y.Q. Song 23


Listes implantées avec structures
chaînées
• Opérations de suppression et d’ajout dans la liste
chaînée simple
Nœud de rang r

Nœud de rang r

cours d’algo. et prog. par Y.Q. Song 24


Listes implantées avec structures
chaînées
• Opérations de suppression et d’ajout dans la liste
chaînée double
Nœud
de rang r

Nœud de rang r

cours d’algo. et prog. par Y.Q. Song 25


Définition d’une liste chaînée en Java
• Une liste chaînée simple est la référence (ou pointeur)
d'un noeud, noeud qui contient la donnée et la référence
(pointeur) du nœud suivant.
@30: 4, @10
Liste
@20: 3, @null
4 12 3 null
@10: 12, @20

• On définit un nœud de la liste par deux attributs


– La donnée
– La référence du nœud suivant
• On définit alors une liste de façon récursive
class Liste{ int contenu;
Liste suivant;}
cours d’algo. et prog. par Y.Q. Song 26
Définition d’une liste chaînée en Java
public class Liste{ @30: 4, @10
int contenu;
@20: 3, @null
Liste suivant;
@10: 12, @20
public Liste(int c, Liste suiv){
this.contenu = c;
this.suivant = suiv;
}

public static void main(String[] args){


Liste l; // l = null
l = new Liste(3, null); // l = @20 (1)
l = new Liste(12, l); // l = @10 (2)
l = new Liste(4, l); // l = @30 (3)
}
}
cours d’algo. et prog. par Y.Q. Song 27
Exemple d’utilisation de listes chaînées
Liste chaînée circulaire : l’élection de Joseph
2 1 1
2 2
9 9
3 3

8 8 8 8
4 4

5 7 7
6 6

L’algorithme travaille de la manière suivante.


- méthode de construction d’une liste circulaire
créer un simple nœud pour la personne 1
insérer à la suite les nœuds pour les personnes de 2 à N
- méthode d’élimination de nœuds
tant que il reste plus d’un noeud
parcourir la liste en comptant jusqu’à M-1
supprimer le prochain nœud (en pensant à refermer le cercle)
fin tant que.
cours d’algo. et prog. par Y.Q. Song 28
Exemple d’utilisation de listes chaînées

public class Noeud {


int val;
Noeud next;

Noeud(int v) { val = v; }
}

cours d’algo. et prog. par Y.Q. Song 29


public class electionJeseph {

public static void main(String[] args)


{ int N = 9;
int M = 5;
Noeud t = new Noeud(1);
Noeud x = t;
for (int i = 2; i <= N; i++)
x = (x.next = new Noeud(i));
x.next = t; //pour boucler la boucle
while (x != x.next)
{
for (int i = 1; i < M; i++) x = x.next;
System.out.println("Le numéro " + x.next.val+" est éliminé" );
x.next = x.next.next;
}
System.out.println("Le survivant est " + x.val);
}
}
cours d’algo. et prog. par Y.Q. Song 30
Exercice sur Liste chaînée
Soit la définition d’un nœud de la liste chaînée suivante :

public class Noeud {


int valeur;
Noeud next;

public Noeud(int val, Noeud next) {


this.valeur = val;
this.next = next;
}
}

Que donne schématiquement la liste après l’exécution des instructions suivantes ?


Noeud a = new Noeud(2, null);
Noeud a = new Noeud(4, a);
Noeud a = new Noeud(6, a);
a
6 4 2 null
cours d’algo. et prog. par Y.Q. Song 31
Les piles

• Opérations empiler (ajouter) et dépiler


(supprimer) au sommet de la pile
empiler dépiler
• Structure très utilisée en informatique:
e.g. undo des logiciels d’édition, appel
des sous-
programmes/fontions/méthodes,
opérations récursives (pile système),

• Peuvent être implantées en utilisant
un tableau, un vecteur, une structure
chaînée
cours d’algo. et prog. par Y.Q. Song 32
Piles implantées avec tableaux
class Pile {
int hauteur;
int[] t;
public Pile (int taille){
t = new int[taille];
hauteur = -1;
}
public boolean estVide(){
return hauteur == -1;
}
public void empiler(int x){
hauteur += 1;
t[hauteur] = x;
}
public int depiler(){
return t[hauteur--];
}
}
cours d’algo. et prog. par Y.Q. Song 33
Piles implantées avec tableaux

• Un petit programme de test pourra être:

class TesterPile{
public static void main(String[] args){
Pile p = new Pile(10);
int x;

p.empiler(1);
p.empiler(2);
x = p.depiler();
System.out.println(x);
}
}

Exercice: proposez une pile implémentée avec la liste chaînée


cours d’algo. et prog. par Y.Q. Song 34
Piles: quelques détails d’implantation

• En utilisant un tableau. Pb: dimension fixe


• En utilisant une structure dynamique (cf. doc de java dans
java.util.*):
– Vector (remplcé par ArrayList)
– Stack qui « extends Vector »
– LinkedList
• Ces classes ne peuvent pas contenir des types
élémentaires (ou primitifs), il faut alors définir sa propre
classe d’objets. Exemple, une pile des int n’est pas
possible, il faut redéfinir int par une classe entier:
class entier {int n;
public entier(int x){n=x}
}
cours d’algo. et prog. par Y.Q. Song 35
Pile implémentée avec une liste chaînée

public class Noeud {


int valeur;
Noeud next;

public Noeud(int val, Noeud next) {


this.valeur = val;
this.next = next;
}
}

cours d’algo. et prog. par Y.Q. Song 36


Exercice: complémenter ces méthodes
public class Pile_chainee {
Noeud pointeur;

public Pile_chainee() {
pointeur = null;
}

public boolean estVide() {


//à compléter
}

public void empiler(int val) {


//à compléter
}

public int depiler() {


//à compléter

}
}

cours d’algo. et prog. par Y.Q. Song 37


public class Pile_chainee {
Noeud pointeur; //pointeur de pile qui designe la tête de la pile
//(le premier élément de la liste chaînée)

public Pile_chainee() {
pointeur = null;
}
public boolean estVide() {
return (pointeur == null);
}
public void empiler(int val) {
pointeur = new Noeud(val, pointeur);
} pointeur pointeur
int depiler() { 6 4 2 null
if (!estVide()) {
int val = pointeur.valeur;
pointeur = pointeur.next;
return val; pointeur
} 4 2 null
else System.out.println(‘‘la pile est vide’’);
}
} cours d’algo. et prog. par Y.Q. Song 38
• Un petit programme de test pourra être:
class TesterPile{
public static void main(String[] args){
Pile_chainee p = new Pile_chainee();
int x;
p.empiler(2);
p.empiler(4);
p.empiler(6);
x = p.depiler();
System.out.println(x);
}
}

cours d’algo. et prog. par Y.Q. Song 39


Les Files d’attente

ajout suppression

• La forme la plus utilisée est FIFO (premier


arrivée, premier sortie). Suppression en
tête, ajout en queue
• Peuvent être implantées en utilisant un
tableau, un vecteur, ou une structure
chaînée
• Un exemple d’implantation avec un tableau
cours d’algo. et prog. par Y.Q. Song 40
Files implantées avec tableaux

class Queue{
int fin;
int[] t;
public Queue(int taille){
t = new int[taille];
fin = 0;
}
}

public boolean estVide(){


return fin == 0;
}

cours d’algo. et prog. par Y.Q. Song 41


Files implantées avec tableaux

public boolean ajouter(int i){


if(fin >= t.length)
return false;
t[fin] = i;
fin += 1;
return true;
}

public void servirClient(){


if(!estVide()){
System.out.println("Je sers le client "+t[0]);
for(int i = 1; i < fin; i++)
t[i-1] = t[i];
fin -= 1;
}
}
cours d’algo. et prog. par Y.Q. Song 42
Files implantées avec tableaux
• Un programme d’essai pourra être:
class Poste{
static final int TMAX = 100;
public static void main(String[] args){
Queue q = new Queue(TMAX);
q.ajouter(1);
q.ajouter(2);
q.servirClient();
q.servirClient();
q.servirClient(); }
}

Exercice: implanter une file avec


(1) un tableau circulaire,
(2) une liste chaînée.
cours d’algo. et prog. par Y.Q. Song 43
Tableau circulaire

debut fin
éléments 23 182 100 20 30

Après 2 clients servis: debut fin


éléments 23 182 100 20 30

Après 2 clients arrivés:


fin debut
éléments 2 100 20 30 1

cours d’algo. et prog. par Y.Q. Song 44


Aparté: Type abstrait de données

• TA est une spécification mathématique d'un ensemble de


données et de l'ensemble des opérations qu'elles peuvent
effectuer
• Un type abstrait est composé de cinq champs (dit TUOPA):
– TA (Type Abstrait): nom
– Utilise: les autres types utilisés (e.g., boolean, entier, …)
– Opérations: signature de chaque opération (l’entête d’une
méthode: nom, type d’arguments et de retour)
– Pré-conditions: que doivent vérifier les arguments des opérations
lors de l’invocation
– Axiomes: formules logiques sur les opérations, pour preuves
d’algorithmes

cours d’algo. et prog. par Y.Q. Song 45


TA: exemple de Pile
Séparer la définition (abstraite) de
la représentation

Type abstrait: défini par des


opérations sur le type et des
propriétés de ces opérations

Type concret: implémentation du


type abstrait. l'implémentation doit
vérifier les propriétés du type
abstrait

A un type abstrait peut


[Source: cours Liafa, Paris 7] correspondre de nombreux types
concrets qui l'implémentent

cours d’algo. et prog. par Y.Q. Song 46


Pourquoi type abstrait: approches de
conception de programmes
• Deux façons de concevoir un programme
– L’approche ascendante
• Par assemblage de briques de base
• Puis par construction de modules de plus en plus importants
(eg. Des classes qui utilisent les méthodes d’autres classes)
– L’approche descendante
• Par une description (spécification formelle) globale du
programme en terme d’objets opaques munies d’opérations
• Puis par raffinement successif des objets en terme d’objets plus
petits

cours d’algo. et prog. par Y.Q. Song 47


Conception ascendante

• Choix d’une représentation des objets de base de


l’application en terme d’objets du langage de
programmation
• Les opérations (méthodes) sont implémentées pour
optimiser au mieux les traitements supportés par les objets
de l’application
• On parle dans ce cas de « bonne programmation »
• Cette méthode est:
– Réservée à la programmation de petits algorithmes bien compris
pour lesquels on cherche la performance
– À déconseiller pour un large programme complexe

cours d’algo. et prog. par Y.Q. Song 48


Conception descendante

• Le programmeur établit dans l’ordre:


– La définition des objets en terme de types de données
abstraits, c’est-à-dire de spécification. Cette
spécification est indépendante de tout langage
d’implémentation (e.g. UML)
– La conception des algorithmes et des représentations
des types des objets de l’application
– Le choix des types d’objets disponibles dans un
langage de programmation donnée pour aboutir à un
programme exécutable
• On parle dans ce cas de « bonne conception »
cours d’algo. et prog. par Y.Q. Song 49
Structures de données simples en Java Listes, piles, files

Relation type
Relation typeabstrait
abstrait / /représentation
représentation
REPRÉSENTATION 1
TYPE_X EN JAVA

Types abstraits structure de


données 1
MODÈLE réalisation 1 des
opérations
- TYPE_X -
opérations
conditions REPRÉSENTATION 2
axiomes TYPE_X EN JAVA
structure de
données 2
réalisation 2 des
opérations

[Source: cours de VD Cung & Y. 10


Viémont]
Langage formel à langage de programmation
cours d’algo. et prog. par Y.Q. Song 50
Exemple: définition du type Pile de X
(X est un type quelconque)
• Nom du TA: Pile[X]
• types des opérations (signature des méthodes)
– Pile :-> Pile[X]
– estVide: Pile[X] -> Boolean
– empiler: XxPile[X] -> Pile[X]
– dépiler: Pile[X] -> XxPile[X]
• Propriétés des opérations
– Pré-conditions: dépiler(X): ¬estVide(X)
– Axiomes:
Pour tout x de X pour tout s de Pile[X]
•estVide(Pile()) (une pile créée est initialement vide)
•¬estVide(empiler(x,s)) (un empilement ne laisse pas la pile vide)
•dépiler(empiler(x,s))=(x,s) (empiler puis dépiler laisse la pile inchangée)
cours d’algo. et prog. par Y.Q. Song 51
Interface java pour spécifier une pile

// Interface Pile simple


interface Pile {
public Object depiler();
public void empiler(Object o);
public boolean estVide();
}

Une interface en Java est composée de déclarations de


méthodes mais sans définition de méthodes ni présence de
variables d'instance

cours d’algo. et prog. par Y.Q. Song 52


Implémentation de pile avec liste
chaînée (revisitée)
// listes d’Object
class Noeud {
Object item;
Noeud suivant;
public Noeud(Object o) {
item=o;
suivant=null;
}
public Noeud(Object o, Noeud n){
item=o;
suivant=n;
}
}
cours d’algo. et prog. par Y.Q. Song 53
Implémentation de pile avec liste
chaînée (revisitée)
class PileListe implements Pile{
private Noeud sommet;
public PileListe(){sommet=null;}
public boolean estVide(){ return (sommet==null);}
public void empiler(Object o){
sommet=new Noeud(o,sommet);
}
public Object depiler(){
Object tmp=sommet.item;
sommet=sommet.suivant;
return tmp;
}
}
cours d’algo. et prog. par Y.Q. Song 54
Implémentation de pile avec tableau
(revisitée)
class PileTable implements Pile{
private Object[] v;
private int taillemax=1000;
private int sommet;
public PileTable(){
v=new Object[taillemax];
sommet=0;
}
public PileTable(int n){
taillemax=n;
v=new Object[taillemax];
sommet=0;
}
public boolean estVide(){return sommet==0;}
public Object depiler(){ return v[--sommet];}
public void empiler(Object o){v[sommet++]=o;}
cours d’algo. et}prog. par Y.Q. Song 55
2: Graphes
s1 s9

s2
s4 s3

s7 s8
s5
s6
Un graphe (orienté) G(V,E) est un ensemble de sommets V (vertices) reliés par
des arcs E (Edges), avec a=(x,y) ∈E qui possède une extrémité initiale x ∈V et
une extrémité finale y ∈V. Si x=y, l’arc est appelé une boucle.
Si les relations entre les sommets sont symétriques, on peut avoir un graphe non
orienté. On parle alors des arêtes au lieu des arcs.
Il est possible d’ajouter des informations sur les sommets pour les identifier, ou
sur les arcs pour les pondérer. Un graphe dont les arcs (ou arêtes) portent des
valuations est appelé graphe valué.
cours d’algo. et prog. par Y.Q. Song 56
Graphes: terminologie
• Un chemin est une liste de sommets dans lequel deux sommets
successifs sont reliés par un arc. La longueur d’un chemin est égale au
nombre d’arcs. Un chemin ne rencontrant pas deux fois le même
sommet est dit élémentaire. Un cycle est un chemin dont le premier
sommet et le dernier sommet sont identique
• Un graphe est dit connexe s’il existe un chemin reliant toute paire de
sommets. (Dans l’exemple de graphe précédent, il existe deux
composantes connexes)
• Un graphe est dit creux s’il existe peu d’arcs (ou arêtes) et dense dans
le cas contraire
• Un graphe simple est un graphe sans boucle, ni arc multiple. Le
nombre d’arcs d’un graphe simple à n sommets est compris entre 0 et
n(n-1), et n(n-1)/2 si le graphe est non orienté
• Deux arcs sont dits adjacents s’ils ont au moins un sommet commun

cours d’algo. et prog. par Y.Q. Song 57


Graphes: représentation avec une
matrice d’adjacence (un tableau)
s1 s2 s3 s4 s5 s6 s7 s8 s9

s1 0 1 0 1 0 0 0 0 1
s2 0 0 0 0 0 0 0 0 0 s1
s3 0 0 0 1 0 0 0 0 0
s4 0 0 1 0 0 1 0 0 0
s5 0 0 0 1 0 0 0 0 0 s2 s9
s6 0 0 0 0 1 0 0 0 0
s7 0 0 0 0 0 0 0 1 0
s8 0 0 0 0 0 0 0 1 0
s4 s3
s9 0 0 0 0 0 0 0 0 0

Elle a une complexité spatiale (espace mémoire) de n2 s5


s6

cours d’algo. et prog. par Y.Q. Song 58


Graphes: représentation avec une liste
d’adjacence (tableau de listes chaînées)
s1
s1 s2 s3 s4 s5 s6 s7 s8 s9
s2 s9
s2 s4 s3 s4 s5 s8 s8
s4 s3

s4 s6
s5
s6
Pour un graphe de n sommets et p arcs,
s9 cette représentation a une complexité spatiale (espace mémoire)
de n+p si le graphe est orienté, et n+2p si le graphe est non
orienté

Elle est intéressante pour un graphe creux (p<<n) en terme de


besoin en mémoire
cours d’algo. et prog. par Y.Q. Song 59
Implantation en Java avec un tableau
(matrice d’adjacence)
import utilensemjava.*;
public class AdjacencyMatrix {
public static void main(String[] args){
int V = Lecture.lireEntier("nombre de sommets =? ");
int E = Lecture.lireEntier("nombre d'arêtes =? ");
boolean adj[][] = new boolean[V][V];
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
adj[i][j] = false;
for (int i = 0; i < V; i++) adj[i][i] = true;
System.out.println("saisir les arêtes");
for (int k=0; k<E; k++){
int i = Lecture.lireEntier("sommet 1 du "+k+ arête =? ");
int j = Lecture.lireEntier("sommet 2 du "+k+" arête =? ");
adj[i][j] = true; adj[j][i] = true;
}
} 0 1

cours d’algo. et prog. par Y.Q. Song 3 2 60


Implantation en Java avec un tableau
(matrice d’adjacence)
0 a0 1
a3 a4 a1
3 a2 2
0 1 2 3
0 true true true true
1 true true true false
2 true true true true
3 true false true true

cours d’algo. et prog. par Y.Q. Song 61


Implantation avec une liste chaînée
(liste d’adjacence)
public class AdjacencyLists {
static class Node {
int v; Node next;
Node (int v, Node t)
{ this.v = v; next = t; }
}
public static void main(String[] args)
{ int V = Lecture.lireEntier("nombre de sommets =? ");
int E = Lecture.lireEntier("nombre d'arêtes =? ");
Node adj[] = new Node[V];
for (int i = 0; i < V; i++) adj[i] = null;
for (int k=0; k<E; k++){
int i = Lecture.lireEntier("sommet 1 du "+k+" arête =? ");
int j = Lecture.lireEntier("sommet 2 du "+k+" arête =? ");
adj[j] = new Node(i, adj[j]);
adj[i] = new Node(j, adj[i]);
}
}
cours d’algo. et prog. par Y.Q. Song
Voir un exemple plus loin 62
Algorithmes de parcours de graphes
• Deux méthodes: recherches en-profondeur-d’abord et en-
largeur-d’abord
• Exemple d’un graphe non orienté:

0 0 7 5 2 1 6
6
1 7 0
2
2 7 0
7 3 5 4
1
4 6 5 7 3
3 5 0 4 3
4 6 4 0
5 7 1 2 0 4

cours d’algo. et prog. par Y.Q. Song 63


Algorithmes de parcours de graphes

• Recherche en-profondeur-d’abord (depth-first search)


Démarrer à un nœud v
• passer par v;
• Passer (récursivement) par chaque nœud
attaché à v (par lequel nous ne sommes pas
déjà passés)
• Si le graphe est connexe, on atteint tous
les nœuds

cours d’algo. et prog. par Y.Q. Song 64


Algorithmes de parcours de graphes

• Recherche en-largeur-d’abord (ou BFS, pour Breadth


First Search)

Étapes de l'algorithme :
1.Mettre le nœud de départ dans la file.
2.Retirer le nœud du début de la file pour l'examiner.
3.Mettre tous les voisins non examinés dans la file (à la fin).
4.Si la file n'est pas vide reprendre à l'étape 2.

cours d’algo. et prog. par Y.Q. Song 65


Algorithmes de parcours 0
6

de graphes 2
7
1
Arbre de recherche
en-profondeur-d’abord 3
4
0 5
0 7 5 2 1 6
7 1 7 0
2 7 0
1 2 4 3 5 4
4 6 5 7 3
6 5 5 0 4 3
6 4 0
3 7 1 2 0 4
cours d’algo. et prog. par Y.Q. Song 66
0 7 5 2 1 6
1 7 0
2 7 0
3 5 4
4 6 5 7 3
En-profondeur-d’abord
5 0 4 3 En-largeur-d’abord
6 4 0
7 1 2 0 4
0
6
0
6
2
2
7
1
7
1
3
4 3
5 4
cours d’algo. et prog. par Y.Q. Song 5 67
Algorithmes de parcours de graphes

• Donner l’ordre du parcours de ce graphe selon les


deux méthodes (largeur et profondeur)

En largeur: A, B, C, E, D, F, G
En profondeur: A, B, D, F, C, G, E
cours d’algo. et prog. par Y.Q. Song 68
Graphes: application
• Problème de recherche du plus court chemin dans un graphe
• Solution de Dijkstra (algorithme de Dijkstra [1959])
• Exemple d’un graphe valué

1 s: source
x = (sx, dx)
S0 S1

7
8 dx = min(tous les chemins de source
10 1 sommet x, noté sx)
S2 On note:
dx=∞ si pas de chemin entre s et sx
S3 4 S4 2 dx=0 si x=s
L’ensemble solution S pour source s=s0:
2 S = {(s0,0), (s1,1), (s2,4), (s3,6),(s4,2), (s5, ∞)}
S5
cours d’algo. et prog. par Y.Q. Song 69
Graphes: application
• Algorithme de Dijkstra (condition: valeur des arcs >= 0)
aussi connu sous SPF (Shortest Path First)
Construire l’ensemble S de façon itérative: 1
S0 S1
Au début: 8 7

dx=∞ si pas de chemin entre s et sx 10 1 S2


dx=0 si sx=s S3 S4
4 2

S=∅ 2
S5
D = {(s0,0), (s1, ∞), (s2, ∞), (s3, ∞),(s4, ∞), (s5, ∞)}
A chaque itération:
∃ m = (sm,dm) ⊂ D, t.q. ∀x ⊂ D, dm=min(dx)
m est alors retiré de l’ensemble D et ajouté dans S
(Affirmation: dm est le plus court chemin entre s et sm)

cours d’algo. et prog. par Y.Q. Song 70


Graphes: application
Ensuite, on calcule dx de chaque x ⊂ D qui possède un arc avec sm :
1
S0 S1
Si dm + valeurArc(sm,sx) < dx alors
7
dx = dm + valeurArc(sm,sx) 8
10 1
Finsi S2
S3 S4
4 2
où valeurArc(sm,sx) est la valeur de l’arc entre sm et sx
2
S5
A la dernière itération, D= ∅ et S contient la solution.
Exemple:
S D
{(s0,0)} {(s1,1), (s2, ∞), (s3,10), (s4, ∞), (s5, ∞)}
{(s0,0), (s1,1)} {(s2, 8), (s3,9), (s4, 2), (s5, ∞)}
{(s0,0), (s1,1), (s4,2)} {(s2, 4), (s3,6), (s5, ∞)}
{(s0,0), (s1,1), (s4,2), (s2, 4)} {(s3,6), (s5, ∞)}
{(s0,0), (s1,1), (s4,2), (s2, 4), (s3,6)} {(s5, ∞)}
{(s0,0), (s1,1), (s4,2), (s2, 4), (s3,6), (s5, ∞)}
cours d’algo. et prog. par Y.Q. Song
∅ 71
Graphes: application
• Remarques: peut être représenté par un tableau
(matrice d’adjacence)
1
S0 S1 Source dest valeur
7 S0 S1 1
8
10 1 S0 S3 10
S2 S1 S2 7
S3 S4 2 S1 S3 8
4 S1 S4 1
2 S4 S2 2
S5 S4 S3 4
S5 S3 2

cours d’algo. et prog. par Y.Q. Song 72


Graphes: application
• Représenté par un tableau de listes chaînées
(Liste d’adjacence)
1 s1 1 s3 10 null
0
S0 S1 s3 8 s4 1
7 1 s2 7 null
8 2 null
10 1
S2 3 null
S3 S4 2 4 s2 2 s3 4 null
4
5 s3 2 null
2
S5 •Tab[i] pointe vers la liste des sommets
directement connectés au sommet « si »
•Pour simplifier, un sommet est codé par un
entier, avec i = si

cours d’algo. et prog. par Y.Q. Song 73


Graphes: application
• Représenté par un tableau de listes chaînées
public class GrapheParListe {
public Liste adj[ ]; //un tableau de listes chaînées
//constructeur
GrapheParListe(int nb_sommets, int nb_arcs){
adj = new Liste[nb_sommets];
for (int i = 0; i < nb_sommets; i++) adj[i] = null;
//on saisie les arcs par sommet du départ
for (int k=0; k<nb_arcs; k++) {
int i = Lecture.lireEntier(
"sommet sortant du "+(k+1)+"ème arc (0-"+(nb_sommets-1)+")=? ");
int j = Lecture.lireEntier(
"sommet d'arrivée du "+(k+1)+"ème arc (0-"+(nb_sommets-1)+")=? ");
int val=Lecture.lireEntier("valeur du "+(k+1)+"ème arc =? ");
adj[i] = new Liste(j, adj[i], val);
}
} cours d’algo. et prog. par Y.Q. Song 74
Graphes: application
• listes chaînées
public class Liste {
int num_noeud; //pour représenter le numéro d'un sommet
int valeur; //pour représenter la valuer de l'arc
Liste suivant;
Liste (int n, Liste t, int v) {
num_noeud = n;
suivant = t;
valeur=v;
}
}

Exercice sur liste chaînée:


Que donne schématiquement la liste après l’exécution de:
Liste a = new Liste(2, new Liste(7, new Liste(11, null, 1), 2),3)

cours d’algo. et prog. par Y.Q. Song 75


Graphes: application
• Les éléments dans les deux ensembles D et S
peuvent être représentés par une classe
public class Element { //(sx,dx)
int sommet; //on code le numéro d'un sommet par un entier
int distance; //distance vers le sommet source
Element(int s, int d){
sommet=s;
distance=d;
}
}

Un tel élément peut être stocké soit dans une liste


chaînée, soit dans un Vector ou ArrayList
cours d’algo. et prog. par Y.Q. Song 76
Graphes: application
Liste Element
- int num_noeud Vector - int sommet
- int valeur - int distance
- Liste suivant
Graphe
Attribut:
- Liste adj[ ]
Méthodes
- constructeur
- String toString()
- boolean arc (int source, int dest)
{//parcours de la liste chaînée}
- int valeurArc(int source, int dest)
- Vector plusCourtChemin(int num_sommet)
{Algo. Dijkstra}
cours d’algo. et prog. par Y.Q. Song 77
Graphes: application
• Parcourir une liste d’ajacence 1
S0 S1
public boolean arc (int source, int dest){ 7
8
boolean arcExiste=false; 10 1 S2
if (adj[source]!=null) {
Liste a = adj[source]; S3 S4 2
while (a != null) { 4
if (a.num_noeud == dest) arcExiste = true; 2
S5
if (arcExiste) a=null; // interrompre la boucle
else a = a.suivant;
}
s1 1 s3 10 x
} 0
return arcExiste; 1 s2 7 s3 8 s4 1 x
} 2
3
4 s2 2 s3 4 x
cours d’algo. et prog. par Y.Q. Song
5 s3 2 x 78
Exercice sur l’algo de Dijkstra

Trouver les chemins les


plus courts de A vers
toutes les autres villes

S {(A,0)}
D{(B,85), (C,217), (E,173), (D,∞),
(F,∞), (G,∞), (H,∞), (I,∞), (J,∞)}
[source: wikipédia]
cours d’algo. et prog. par Y.Q. Song 79
S D
{(A,0)} {(B,85), (C,217), (E,173), (D,∞), (F,∞),
(G,∞), (H,∞), (I,∞), (J,∞)}
{(A,0), (B,85)} {(C,217), (E,173), (D,∞), (F,165), (G,∞),
(H,∞), (I,∞), (J,∞)}
{(C,217), (E,173), (D,∞), (G,∞), (H,∞),
{(A,0), (B,85), (F,165)} (I,415), (J,∞)}

{(A,0), (B,85), (F,165), (E,173)} {(C,217), (D,∞), (G,∞), (H,∞), (I,415),


(J,675)}
{(A,0), (B,85), (F,165), (E,173), (C,217)} {(D,∞), (G,403), (H,320), (I,415), (J,675)}

{(A,0), (B,85), (F,165), (E,173), (C,217), {(D,503), (G,403), (I,415), (J,487)}


(H,320)}
{(A,0), (B,85), (F,165), (E,173), (C,217), {(D,503), (I,415), (J,487)}
(H,320), (G,403)}
{(A,0), (B,85), (F,165), (E,173), (C,217), {(D,503), (J,487)}
(H,320), (G,403), (I,415), (J,487)}
{(D,503)}

{(A,0), (B,85), (F,165), (E,173), (C,217),



(H,320), (G,403),
cours d’algo. et (I,415), (J,487),
prog. par Y.Q. Song (D,503)} 80
Complexité de l’algo de Dijkstra

• Sous l’hypothèse d’un graphe sous forme de listes


d'adjacence et en utilisant un tas comme une file à
priorités pour réaliser la méthode
plusCourtChemin(int num_sommet), si le graphe
possède m arcs et n nœuds, en supposant que
les comparaisons des poids d'arcs soient à temps
constant, alors la complexité de l'algorithme est :
O((m+n) x ln (n))
• L'utilisation de tas de Fibonacci donne un meilleur
temps d'exécution amorti : O(m + n x ln (n))
cours d’algo. et prog. par Y.Q. Song 81
Algorithme A*
• L’algo A* (P.E. Hart et al., 1968) est un algo heuristique de
recherche de chemin dans un graphe entre un sommet de
départ et un sommet d’arrivée.
• Il peut être plus rapide que l’algo de Dijkstra dans certains
cas car sans exploiter tous les voisins, mais vers une
direction (on suppose connaître la direction vers la
destination)
• il ne trouve pas toujours le chemin optimal
• Il peut être inefficace dans certains cas

cours d’algo. et prog. par Y.Q. Song [Source: wikipédia] 82


3: Les structures arborescentes
• Un arbre est une forme particulière
d’un graphe
• Les structures arborescentes sont +
largement utilisées en informatique:
système d’organisation de fichiers
x 2
dans un disque, …
• En informatique, on s’intéresse à
a b
des formes particulières d’arbre de
plus en plus contraintes: arbre libre, a x b + 2
arbre enraciné, arbre ordonné, arbre
binaire, arbre équilibré, …
Ordre infixe

cours d’algo. et prog. par Y.Q. Song 83


Arbres libres
Un arbre libre G(S,A) est un graphe non orienté, non vide,
connexe et sans cycle (ou circuit)

Propriétés:
-Deux nœuds quelconques de S sont connectés par un chemin simple unique,
-G est connexe, mais ne l’est plus si l’on retire une arête quelconque,
-G est sans circuit, mais ne l’est plus si l’on ajoute une arête quelconque,
-G est connexe, et Card(A) = Card(S) – 1,
-G est sans cycle, et Card(A) = Card(S) – 1

cours d’algo. et prog. par Y.Q. Song 84


Arbres enracinés
Un arbre enraciné ou arbre (rooted tree) est un arbre libre
muni d’un nœud distingué, appelé racine.
Soit T un arbre de racine r. 1
Pour tout nœud x il existe un chemin simple unique
de r à x. 2 3 4
Tout nœud y sur ce chemin est un ancêtre de x, et
x est un descendant de y.
Le sous-arbre de racine x est l’arbre contenant 5 6 7 8 9
tous les descendant de x.
L’avant-dernier nœud y sur l’unique chemin reliant
r à x est le parent de x, et x est un enfant de y.
L’arité d’un nœud est le nombre de ses enfants.
Un nœud sans enfant est une feuille, un nœud
d’arité >0 est appelé nœud interne.
La hauteur d’un arbre T est la longueur maximale
d’un chemin reliant sa racine à une feuille.
Un arbre réduit à une seul nœud est de hauteur 0.
cours d’algo. et prog. par Y.Q. Song 85
Arbres enracinés
Les arbres admettent une définition récursive: un arbre sur un
ensemble fini de nœuds est un couple formé de sa racine et d’une
partition des nœuds restants en un ensemble d’arbres.

Exemple de l’arbre ci-contre:


T = (1, {(2, {(5), (6)}), (3, {(7), (8), (9)}), (4)}) 1

2 3 4
Une forêt est un ensemble d’arbres

5 6 7 8 9

cours d’algo. et prog. par Y.Q. Song 86


Arbres ordonnés
Un arbre ordonné est un arbre dans lequel l’ensemble des enfants de
chaque nœud est totalement ordonné.

1 2 3

1.1 1.2 2.1 2.2 2.3

1.2.1 1.2.2

cours d’algo. et prog. par Y.Q. Song 87


Arbres binaires
Un arbre binaire est un arbre qui possède au plus deux fils, un sous-
arbre gauche, et un sous-arbre droit.
Un arbre binaire non vide est représenté sous forme d’un triplet:
A = (Ag, r, Ad).
Exemple: les deux arbres binaires suivants sont différents

1 1

2 2

3 3

(∅, 1, ((∅, 3, ∅), 2, ∅)) ((∅, 2, (∅, 3, ∅)), 1, ∅)

cours d’algo. et prog. par Y.Q. Song 88


Arbres binaires
Propriété:
Soit A un arbre binaire à n nœuds, de hauteur h. Alors h+1 ≥ log2(n+1).
Preuve. Il y a au plus 2i nœuds à distance i, donc n ≤ 2h+1 − 1. □.

Cette propriété permet de déterminer la complexité de la plupart des


algorithmes sur les arbres binaires: entre O(log2n) et O(n).
Preuve: n-1+1 ≥ h+1 ≥ log2(n+1) è n-1 ≥ h ≥ log2(n+1) -1 et le nombre
d’opérations est souvent h.

Arbre équilibré: Comme la complexité dépend de la hauteur h, et au


pire cas = n-1, il est toujours intéressant de structurer les données avec
un arbre « équilibré » afin d’avoir h proche de la moyenne.
Par exemple, un arbre binaire équilibré AVL (Adelson-Velskii et Landis
1962) a pour tout nœud, les hauteurs des sous-arbres gauche et droit
diffèrent d’au plus 1. Sa hauteur est donc bornée par:
log 2 (n +1) ≤ h +1 ≤ α log 2 (n + 2), avec α = 1/ log 2 ((1+ 5) / 2) ≤ 1.44
Il existe d’autres familles d’arbres équilibrés: 2-3, rouge et noir, ...
cours d’algo. et prog. par Y.Q. Song 89
Parcourir un arbre binaire

Parcours récursif Préfixe:

VisiterPréfixe(Arbre A)
{
Visiter(A)
Si Non_Vide(gauche(A))
VisiterPréfixe(gauche(A))
Si Non_Vide(droite(A))
VisiterPréfixe(droite(A))
}
cours d’algo. et prog. par Y.Q. Song 90
Parcourir un arbre binaire

Parcours recursif Postfixe (ou sufixe):

VisiterPostfixe(Arbre A)
{
Si Non_Vide(gauche(A))
VisiterPostfixe(gauche(A))
Si Non_Vide(droite(A))
VisiterPostfixe(droite(A))
Visiter(A)
}
cours d’algo. et prog. par Y.Q. Song 91
Parcourir un arbre binaire

Parcours récursif infixe:

VisiterInfixe(Arbre A)
{
Si Non_Vide(gauche(A))
VisiterInfixe(gauche(A))
Visiter(A)
Si Non_Vide(droite(A))
VisiterInfixe(droite(A))
}
cours d’algo. et prog. par Y.Q. Song 92
Parcourir un arbre binaire

Exercice: donner l’ordre de visite des noeuds pour:


-Parcours infixe
-Parcours postfixe (sufixe)
-Parcours préfixe

cours d’algo. et prog. par Y.Q. Song 93


ABR: Arbre Binaire de Recherche
• chaque nœud possède une clé, telle que chaque nœud
du sous-arbre gauche ait une clé inférieure ou égale à
celle du nœud considéré, et que chaque nœud du sous-
arbre droit possède une clé supérieure ou égale à celle-ci

cours d’algo. et prog. par Y.Q. Song 94


Parcourir un arbre binaire de recherche

Exercice: donner l’ordre de visite des noeuds du


parcours infixe

Propriété:
Un parcours infixe d’un
arbre binaire de recherche
traite les sommets par clés
croissantes.

cours d’algo. et prog. par Y.Q. Song 95


sommets du sous-arbre Arbres binaires de recherche
che ont une clé inférieure à k. 7
Sont-ils
t ont une clé supérieure à k.
3
tous 9ABR?
1 Autre5 exemple:
8
4
7 7
3 9 3 9
Contre-exemple:
1 4 8 1 5 8
5 4
7
4 9
es clés sont représentées dans les Contre-exemple:
dessins)
1 5 8 Exemples du cour d’Olivier Bournez
3 7
9
4 9
Question:
1 5 8
-pour un ensemble de clés {1, 3, 4, 5, 7, 8, 9} dans
3
l’ordre 10

quelconque, obtient-on le même ABR?


-Sinon, combien peut-on générer d’ABR différents?
cours d’algo. et prog. par Y.Q. Song 96
Algorithme de tri par ABR

• Deux sous-algorithmes
– construction d'un ABR à partir d'une suite
d'éléments,
– parcours en profondeur dans l'ordre infixe de
cet ABR.

cours d’algo. et prog. par Y.Q. Song 97


Tableau à trier: {6 8 3 1 4 9 2 7 5}

Insertion du 6
6

Exemple extrait de N. Dailly: http://www.dailly.info


cours d’algo. et prog. par Y.Q. Song 98
Tableau à trier: {6 8 3 1 4 9 2 7 5}

public static int[] triArbreBinaireDeRecherche(int tableau[])


{
ArbreBinaireDeRecherche
arbre=ArbreBinaireDeRecherche.construitArbre(tableau);
return arbre.parcoursInfixe();
}
cours d’algo. et prog. par Y.Q. Song 99
Implémentation d’arbre binaire

• Liste chaînée est un cas particulier d’arbre


binaire (h = n-1)
• Un arbre binaire non vide est représenté
sous forme d’un triplet: A = (Ag, r, Ad).

cours d’algo. et prog. par Y.Q. Song 100


class Arbre
{
int contenu;
Arbre filsG, filsD;

Arbre(Arbre g, int c, Arbre d)


{
filsG = g;
contenu = c;
filsD = d;
}
}

Un arbre à un seul noeud: new Arbre(null, x, null);

cours d’algo. et prog. par Y.Q. Song 101


a = new Arbre(
new Arbre(
new Arbre(null, 3, null),
5,
new Arbre(
new Arbre(
new Arbre(null, 6, null), 8, null),
12,
new Arbre(null, 13, null)
)
),
20,
new Arbre(new Arbre(null, 21, null), 25 ,new Arbre(null, 28, null))
);

Exercice: quel arbre ?

cours d’algo. et prog. par Y.Q. Song 102


static Arbre composer(Arbre g, int c, Arbre d)
{
return new Arbre(g, c, d);
}
static int cle(Arbre a)
{
return a.contenu;
}
static Arbre filsGauche(Arbre a)
{
return a.filsG;
}
static Arbre filsDroit(Arbre a)
{
return a.filsD;
}
cours d’algo. et prog. par Y.Q. Song 103
static int taille(Arbre a)
{
if (a == null) return 0;
return 1 + taille(a.filsG) + taille(a.filsD);
}

static void parcoursPrefixe(Arbre a)


{
if (a == null)return;
System.out.print(a.contenu + " ");
parcoursPrefixe(a.filsG);
parcoursPrefixe(a.filsD);
}

cours d’algo. et prog. par Y.Q. Song 104


static void parcoursInfixe(Arbre a)
{
if (a == null) return;
parcoursInfixe(a.filsG);
System.out.print(a.contenu + " ");
parcoursInfixe(a.filsD);
}

static void parcoursSuffixe(Arbre a)


{
if (a == null) return;
parcoursSuffixe(a.filsG);
parcoursSuffixe(a.filsD);
System.out.print(a.contenu + " ");
}
cours d’algo. et prog. par Y.Q. Song 105
Construire un ABR à partir d'une liste
(insertions d'éléments dans un ABR)
• On part de la racine de l'arbre
• Une valeur v à insérer dans l'ABR.
• Si l'élément en cours n'existe pas, on insère v à cet
emplacement.
• Sinon, on compare v à l'élément en cours.
– S'il a une valeur supérieure, on l'insère dans le sous-arbre droit,
– Sinon, on l'insère dans le sous-arbre gauche (récursivité).
• En appliquant cet algorithme d’insertion à chaque
élément de la liste (donc en insérant chaque élément dans
l'ABR résultant de la précédente insertion), l'arbre binaire
de recherche prend forme petit à petit.
cours d’algo. et prog. par Y.Q. Song 106
Insertion d’une clé dans un ABR
static Arbre inserer(int x, Arbre a)
{
if (a == null)
return new Arbre(null, x, null);
if (x < a.contenu)
a.filsG = inserer(x, a.filsG);
else if (x > a.contenu)
a.filsD = inserer(x, a.filsD);
return a;
}

Exercice: donner le code java permettant de créer un ABR à


partir du tableau {6 8 3 1 4 9 2 7 5}
cours d’algo. et prog. par Y.Q. Song 107
Rechercher une clé dans un ABR

static Arbre chercher(int x, Arbre a)


{
if (a == null || x == a.contenu)
return a;
if (x < a.contenu)
return chercher(x, a.filsG);
return chercher(x, a.filsD);
}

cours d’algo. et prog. par Y.Q. Song 108


Suppression d’une clé dans un ABR

• Suppresion est plus complexe, trois cas:


– Si le nœud s est une feuille, alors on l’élimine
– si le nœud s possède un seul fils, on élimine s
et on « remonte » ce fils
– si le nœud s possède deux fils, on cherche le
prédécesseur t de s dans l’ordre infixe (ou la clé
du successeur). Celui-ci n’a pas de fils droit. On
remplace le contenu de s par le contenu de t, et
on élimine t.

cours d’algo. et prog. par Y.Q. Song 109


Le nœud s est une feuille, alors on l’élimine

cours d’algo. et prog. par Y.Q. Song 110


Si le nœud s possède un seul fils,
on élimine s et on « remonte » ce fils

cours d’algo. et prog. par Y.Q. Song 111


Si le nœud s possède deux fils (exemple s=15),
on cherche le prédécesseur t (exemple t=14) de s dans
l’ordre infixe (c-à-d. la clé maximum dans abre.filsG) ou
bien la clé du successeur.
Celui-ci n’a pas de fils droit. On remplace le contenu de
s par le contenu de t (exmple s=14 et t=15)
On élimine t.

cours d’algo. et prog. par Y.Q. Song 112


On recherche le nœud portant la clé à supprimer

static Arbre supprimer(int x, Arbre a)


{
if (a == null)
return a;
if (x == a.contenu)
return supprimerRacine(a);
if (x < a.contenu)
a.filsG = supprimer(x, a.filsG);
else
a.filsD = supprimer(x, a.filsD);
return a;
}
cours d’algo. et prog. par Y.Q. Song 113
On supprime la clé selon ce qu’on vient de décrire

static Arbre supprimerRacine(Arbre a)


{
if (a.filsG == null)
return a.filsD;
if (a.filsD == null)
return a.filsG;
Arbre f = dernierDescendant(a.filsG);
a.contenu = f.contenu;
a.filsG = supprimer(f.contenu, a.filsG);
return a;
}
cours d’algo. et prog. par Y.Q. Song 114
Enfin, la méthode permettant de trouver le prédécesseur de la
clé, celui-ci n’a pas de fils droit

static Arbre dernierDescendant(Arbre a)


{
if (a.filsD == null)
return a;
return dernierDescendant(a.filsD);
}

cours d’algo. et prog. par Y.Q. Song 115


Arbres avec h de l’ordre de log n
La complexité dans un ABR
Si hauteur h et nombre de nœuds n, opérations de
« Insertion », « Recherche » et «bien)
Un arbre (très Suppression
équilibré: »h ont une
= log n.
complexité O(h)
bres avec h de l’ordre de log n

Un arbre binaire équilibré: Un arbre à peu près équilibré:


h=log2(n) h ≤ 2log2(n)
rès bien) équilibré: h =
Unlog n. à peu près équilibré: h 2 log n.
arbre

peu près équilibré: h 2 log n.


cours d’algo. et prog. par Y.Q. Song 116
Deux Un autre
arbres très arbre
mal très mal équilibré:
équilibrés: h = n − 1 h=n
mal équilibré: h = n 1.

Avec quelle séquence de clés


peut-on obtenir cet arbre avec la
méthode d’insertion donnée
précédemment?
très
• Aumal équilibré:
pire h = nde Insertion,
cas, opérations 1. Recherche et
Suppression ont une complexité O(n)
• Pour garantir un pire cas en O(logm n), on utilise des
arbres équilibrés (m=2 si abre binaire)
cours d’algo. et prog. par Y.Q. Song 117
Arbre équilibré: Arbre-B (B-tree)
• Arbre équilibré (Balanced tree), une extension d’ABR
(plusieurs clés au lieu d’une), inventé en 1972 par R. Bayer &
MaCreight de Boeing
• Très utilisé dans l’indexation de bases de données car permet
d’accéder rapidement à un enregistrement stocké en mémoire
externe (e.g. blocks de disque dur)
10 40

3 15 20 30 50

1 2 11 12 14 22 25 26 41 42
4 5 6 9 16 17 31 32 33 36 55 60 70
Arbre-B: définition
• Chaque nœud contient un nombre de « clés » qui servent
à séparer les sous arbres, pointés par des « pointeurs »
• Les clés de chaque nœuds sont rangés dans l’ordre
croissant
• Comme dans un ABR, prenons l’exemple d’un nœud de 2
clés k1 et k2 (k1<k2):
– Toutes clés k du sous-arbre gauche respectent k<k1
– Toutes clés k du sous-arbre entre k1 et k2 respectent k1<k<k2
– Toutes clés k du sous-arbre droit de k2 respectent k>k2

cours d’algo. et prog. par Y.Q. Song 119


Arbre-B: propriétés
• un arbre-B de l’ordre m (c’est à dire maximum m fils et
minimum ceil[m/2] fils,⌈m⁄2⌉ )
– Chaque nœud possède au plus m fils
– Chaque nœud interne (sauf racine) possède au moins ceil[m/2] fils
– Un nœud peut être étendu du m/2 à m ou réduit
• Ajouter une clés à un nœud déjà plein (m-1 clés) provoque la création
de deux nœuds de m/2 chacun, et l’ajout d’une clé supplémentaire au
nœud parent
• A l’inverse, si un nœud et son voisin ont m/2 clés, la suppression d’une
clé (m/2 – 1) peut provoquer une fusion des deux nœuds pour former
un nœud de m-1 clés, dont une est descendu du nœud parent
– Exception: la racine possède au moins 2 fils, si elle-même n’est pas
une feuille (c’est à dire la racine a entre 2 et m fils)
– Un nœud interne ayant k fils contient k-1 clés
– Toutes les feuilles apparaissent au même niveau
cours d’algo. et prog. par Y.Q. Song 120
Arbre-B: recherche
Exemple arbre-B d’ordre 5 (pointeurs) ou d’ordre 2 (clés)
Commencer ici Si on cherche 59 ?

57 . . .

14 40 . . 72 84 . .

01 12 . . 15 16 17 . 47 56 . . 58 60 61 . 74 75 76 78 85 86 99 .

cours d’algo. et prog. par Y.Q. Song [Exemple de semaphore co.] 121
Arbre-B: insertion

Commencer ici Si on insert 59 ?

57 . . .

14 40 . . 72 84 . .

01 12 . . 15 16 17 . 47 56 . . 58
5859
6060
6161
. 74 75 76 78 85 86 99 .

cours d’algo. et prog. par Y.Q. Song [Exemple de semaphore co.] 122
Arbre-B: insertion

Commencer ici Si on insert 77 ?


à overflow

57 . . .

14 40 . . 72
72 76
84 84
. ..

01 12 . . 15 16 17 . 47 56 . . 58 60 61 . 74 75 76 78 85 86 99 .

74 75 . . 77 78 . .

cours d’algo. et prog. par Y.Q. Song [Exemple de semaphore co.] 123
Arbre-B: suppression

On veut supprimer 37

xx 37 xx xx xx 41 xx xx

… xx xx xx xx … xx xx xx xx

xx xx xx xx xx xx xx xx

41 43 xx xx 43 xx xx .

cours d’algo. et prog. par Y.Q. Song [Exemple de semaphore co.] 124
Arbre-B: suppression
On veut supprimer 67 è underflow pour un abre-B d’ordre 3 (2x3 clés)

xx 55 xx

22 24 26 28 33 44 66 67 68 . . .

xx 33 xx

22 24 26 28 . . 44 55 66 68 . . .

cours d’algo. et prog. par Y.Q. Song [Exemple de semaphore co.] 125
Arbre-B: suppression
On veut supprimer 52 è underflow (arbre-B de 2x2 clés)
Mais son nœud voisin n’a pas de clé à redistribuer (sinon underflow)
35 45 55 .

40 42 . . 50 52 . .

35 55 . .

40 42 45 50

cours d’algo. et prog. par Y.Q. Song [Exemple de semaphore co.] 126
Arbre-B: complexité
50
51
52
Un arbre-B de l’ordre m (maxi m fils) et de hauteur h a n feuilles:
[m/2]h ≤ n ≤ mh

La hauteur maximale d’un arbre-B d’ordre m:


ℎ ≤ log ! !!
!
Pire cas:
- Recherche: O(log(m)*logm(n)) = O(log n)
- Insertion/suppression: O(m*logm(n))
cours d’algo. et prog. par Y.Q. Song 127
Arbre-B: structure de données en java

public interface intArbreB {


static final int MINIMUM = 200;
static final int MAXIMUM = 2*MINIMUM;
int[] data = new int[MAXIMUM + 1];
intArbreB[] subset = new intArbreB[MAXIMUM + 2];

// add: add a new element to this set,


// if the element was already in the set, then there is no change.
public void add(int element);

// contains: determine whether a particular element is in this set


public boolean contains(int target);

// remove: remove a specified element from this set


public boolean remove(int target);
}

cours d’algo. et prog. par Y.Q. Song 128


Autres arbres binaires de recherche
« self-balancing »
• Arbre AVL (Georgy Adelson-Velsky et
Evgenii Landis)
• Arbre rouge-noir, un cas similaire à un
arbre-B d’ordre 4
• Arbre 2-3
• …
Ils ont la complexité O(log n) pour recherche,
insertion et suppression
cours d’algo. et prog. par Y.Q. Song 129
Les tas (heap)
• Un tas est un arbre binaire tassé dont les
sommets sont étiquetés par des clés, tel que tout
sommet possède une clé supérieure ou égale aux
clés de ses fils pour un tas-max. (ou inférieur ou
égale aux clés de ses fils pour un tas-min)

cours d’algo. et prog. par Y.Q. Song 130


4 8 2
Leslestas
On numérote (heap)
sommets par un parcours en largeur, de
gauche
• Un tas peut être à droite.
facilement représenté par un tableau dynamique
•Tas tableauxLe
Onetnumérote lessommet
sommetsi parestun
rangé dansenlalargeur,
parcours case d’indice i duà tableau.
de gauche droite
• naturellement
sente Le sommet pari estunrangé dans la case d’indice i du tableau
tableau.
0 0 1 2 3 4 5 6 7 8 9
23
1 2 tab 23 15 7 12 5 6 1 4 8 2
15 7
3 4 5 6Racine: sommet 0
12 5 6 1
7 8 9 Parent du sommet i : sommet ⎣(i-1)/2⎦
4 8 2 Fils gauche du sommet i: sommet 2i+1
Fils droit du sommet i: sommet 2i+2
s sommets par un parcours en largeur, de
Nœud i est une feuille: 2i+1 ≥ n
.
Nœud i a un fils droit: 2i+2 < n
t rangé dans la case d’indice i du tableau.
Les opérations sur un tas a une complexité en général de O(log n)
0 1 2 3 4 5 6 7 8 9
Très utilisé en informatique (file de priorité, tri par tas, …)
23 15 7cours
12d’algo.
5 6et prog.
1 par
4 Y.Q.
8 Song
2 131
Application de tas: files de priorité
Files d’attente avec priorité
Opérations:
- trouver le plus grand élément
- insérer un élement
- retirer le plus grand élément
Implémentation par tableau ou liste chaînée a une complexité
trop élevée.
Une file de priorité implémentée en tas réduit la complexité
Implémentation Trouver max Insérer Retirer max
Tableau ou liste non ordonné O(n) O(1) O(n)
Tableau ou liste ordonné O(1) O(n)* O(1)
Tas O(1) O(log n) O(log n)
* Supposé en recherche linéaire. Si dichotomique, O(log n)
cours d’algo. et prog. par Y.Q. Song 132
Insertion d’un élément dans un tas
se procède en deux étapes:
-ajouter le noeud v à la fin du dernier niveau (pour rester un
arbre tassé)
-comparer le contenu du noeud v à celui de son père. Tant que
le contenu du père est plus petit que v, le contenu du père est
descendu vers le fils. A la fin, on remplace par v le dernier
contenu abaissé

cours d’algo. et prog. par Y.Q. Song 133


Insertion dans un tas: exemple

[Source: Wikipédia]
cours d’algo. et prog. par Y.Q. Song 134
3 4 5 6
12 5 6 1

Suppression de la racine d’un tas


7 8 9 10
4 8 2 21

se
Fig.procède aussi
18 – Un tas, avecen deux de
remontée étapes:
la valeur 21 après insertion.
-le contenu de la racine est remplacé par celui du nœud le plus à droite du
La suppression se fait de manière similaire. D’abord, le contenu du nœud le plus à droite du
dernier niveau, et ce nœud est supprimé. (pour rester un arbre tassé)
ier niveau est transféré vers la racine, et ce nœud est supprimé. Ceci garantit que l’arbre
-le contenu
tassé. Ensuite, le contenu v delalaracine
v de nouvelle racine
est comparé est comparé
à la plus à la plus
grande des valeurs de sesgrande
fils des valeurs
de ses
en a). Si cette fils
valeur est(s’il en a).
supérieure à v,Sielle
cette valeur etestremplace
est remontée supérieure à v,duelle
le contenu père.est remontée et
ontinue ensuite avec le fils. Par exemple, la suppression de 16 dans l’arbre de gauche de la
e 19 conduit remplace le contenu
d’abord à l’arbre de droitedu depère. On continue
cette figure, 5. au
et enfin ensuite
FILES
tas avec20Éle fils.
DElaPRIORIT
de figure

0 0 0
16 10 v 15

1 2 1 2 1 2
14 11
15 11 15 11
3 4 5 6
3 4 5 6 3 4 5 6
8 10 9 3
8 14 9 3 8 14 9 3
7 8 9
7 8 9 10 7 8 9 2 4 7
2 4 7 10 2 4 7
Fig. 20 – Le tas de la figure 19 après suppress

La complexité de ces opérations est majorée par la hauteur de


Fig. 19 – Un tas, et la circulation des valeurs pendant la suppression de 16.
Tas(int n)
l’arbre,
La complexité donc
de chacune de ceslogarithmique
opérations est majoréeen
par la taille
{ de l’arbre qui est,
la hauteur
nTas = 0;
logarithmique en la taille.
cours d’algo. et
Un tas est naturellement prog. par
présenté Y.Q. Song
comme
a = new int[n];
une classe, fournissant les trois méthodes maxi- 135
}
(), inserer(), supprimer(). On range les données dans un tableau interne. Un constructeur
Implémentation en java de Tas et files
de priorité
public class Tas {
int[] a;
int nTas=0; // nb de nœuds dans le Tas

Tas(int n) {
nTas = 0; a = new int[n];
}

int maximum() {
return a[0];
}

void ajouter(int v) {...} //exercice 1: écrire cette méthode


void supprimer() {...} //exercice 2: écrire cette méthode
}

cours d’algo. et prog. par Y.Q. Song 136


Insertion dans un Tas
void ajouter(int v) {
int i = nTas;
++nTas;
while (i > 0 && a[(i-1)/2] <= v) {
a[i] = a[(i-1)/2];
i = (i-1)/2;
}
a[i] = v;
}

Rappel: (i-1)/2 est l’indice du père


Question: quand la boucle while s’arrête?
Complexité: nb de comparaisons (boucle while) borné par
la hauteur de l’arbre log2n, on a donc O(log n)
cours d’algo. et prog. par Y.Q. Song 137
Suppression dans un Tas
void supprimer() {
nTas--;
a[0] = a[nTas]; //remplace la racine par le
dernier
int v = a[0];
int i = 0;
while (2*i + 1 < nTas) { // i n’est pas une
feuille
int j = 2*i + 1; //fils gauche
if (j+1 < nTas && a[j+1] > a[j]) ++j;
//si existeFilsD(i) et cle(filsD(i)) > cle(filsG(i)), j=filsD(i)
if (v >= a[j]) break;
a[i] = a[j];
i = j;
}
a[i] = v;
}
cours d’algo. et prog. par Y.Q. Song 138
Tri par tas (heapsort)
Exercice3: comment trier en se servant d’un Tas?
int[] triParTas(int[] a) {
int n = a.length;
Tas t = new Tas(n);
for (int i = 0; i < n; i++) t.ajouter(a[i]);
for (int i = n - 1; i >= 0; --i) {
int v = t.maximum();
t.supprimer();
a[i] = v;
}
return a;
}

Exercice4: quelle complexité? n fois ajouter() et n fois supprimer()


cours d’algo. et prog. par Y.Q. Song
donc O(n log n) 139
Tester le tous

public class testTas {


public static void main(String[] args) {

int [] tab = {5, 6, 1, 4, 8, 2, 23, 15, 7, 12};

Tas t = new Tas(tab.length);

System.out.println(t);

for (int i = 0; i < tab.length; i++)


System.out.print( t.triParTas(tab)[i] );
}
}

cours d’algo. et prog. par Y.Q. Song 140


4. Dictionnaire (map, hashmap)

• Un dictionnaire est un modèle de données pour la


gestion ”simple” d'une collection (”ensemble
dynamique”)
• Un dictionnaire n'est doté que des opérations
d'insertion, de suppression et de recherche
• Chaque élément de cette collection est représenté
par un ”objet”
• Un des champs (attributs) de l'objet contient une
clé qui sert d'identifiant (non ambiguïté)

cours d’algo. et prog. par Y.Q. Song 141


Dictionnaire
• Si les clés sont toutes différentes on peut voir la collection
comme une collection de valeurs de clés
• Si la collection formée par ces clés est totalement
ordonnée alors la gestion d'un dictionnaire pourra se voir
adjoindre des opérations supplémentaires telles que
minimum, maximum, prédécesseur ou successeur
• Tableaux associatifs en général (issus de la mise en
correspondance entre un ou des objets et un index qui sert
de clé de recherche)
• Un dictionnaire peut être implémenté en tableau ordinaire
ou de hachage, ou en arbres binaires (e.g. un annuaire)

cours d’algo. et prog. par Y.Q. Song 142


Dictionnaire en tableau ordinaire

• Avantages
– La structure de tableau permet, par un adressage
direct, d'examiner ou de modifier une position du
tableau en O(1)
– À chaque élément de la collection est associé une clé
dans l'univers U={0,1,...,m-1} de toutes les clés
possibles
– L'implémentation d'un dictionnaire dans un tableau
ordinaire suppose que le tableau soit de taille m (toutes
les clés possibles)

cours d’algo. et prog. par Y.Q. Song 143


Dictionnaire en tableau ordinaire
• Dans ce cas l'implémentation des opérations est
triviale et efficace
Inconvénient:
Rechercher(Tableau,clé) Si l'univers de toutes les clés
Retourner Tableau[clé] possibles est trop
grand (voire infini),
conserver un tableau d'une
Inserer(Tableau,x)
telle taille peut s'avérer
Tableau[clé(x)] ← x
impossible
De plus, si le nombre de clés
Supprimer(Tableau,x) stockées est très
Tableau[clé(x)] ← NULL petit comparé à celui-ci, cette
place est gaspillée
cours d’algo. et prog. par Y.Q. Song 144
Table de hachage
• Besoin d’accès rapide (O(1) aux données non-ordonnées
via une clé (exemple de l’annuaire téléphonique)
• Pas possible avec un tableau car recherche selon le nom
(un String)
Fonction de hachage

[extrait de Wikipedia]

cours d’algo. et prog. par Y.Q. Song 145


Adressage indexé
Soit k ∈ U (univers des clés),
t[ ] un tableau de M cases,
h(k) ∈ {0, 1, …, M-1} (un peu plus que le nombre d’éléments à
ranger).

Au lieu de ranger l’élément de clé k directement dans une case t[k]


(adressage direct, qui n’est pas toujours possible si k n’est pas un
entier),
on le range dans t[h(k)] (similaire à l’adressage indexé vu en partie
assembleur en info1).

Idéalement: h(k1) = h(k2) si k1=k2


h(k1) ≠ h(k2) si k1≠k2
Dans la pratique, la 2ème condition est difficile à remplir car M<<U
cours d’algo. et prog. par Y.Q. Song 146
Fonction de hachage
Une fonction pour produire un nombre entier à partir de la clé
(e.g., String).
Par exemple, on peut interpréter chaque caractère comme un
chiffre d’une base B et la chaîne comme un entier écrit dans
cette base. C’est à dire que la chaîne a0a1 . . . an−1 est l’entier
a0·Bn−1 + a1·Bn−2 +··· +an−1. En java B=31.

Ce nombre entier, souvent très grand, est converti en une


position possible de la table, en général en calculant le reste
modulo la taille de la table.

cours d’algo. et prog. par Y.Q. Song 147


Tables de hachage

[extrait du site openclassrooms]

cours d’algo. et prog. par Y.Q. Song 148


Fonction de hachage
h(k) = hc(hh(k))
Un exemple numérique: hh(k)=3k+14 = x
hc(x)=x mod M

Exercice: donner les “hashcode” de 0, 4, 7, 42; M=10

[Cette partie est construite selon un tutoriel du site openclassrooms]

cours d’algo. et prog. par Y.Q. Song 149


Gestion de collisions
Reprenons l’exemple précédent: hh(22)=80, hc(80)=0
La clé 22 se trouve à la même place que 42, donc collision!

Trois façons de gérer les collisions:


- le sondage ;
- le double hachage ;
- le chaînage linéaire.

cours d’algo. et prog. par Y.Q. Song 150


Sondage (probing)
Sondage linéaire: si on a une collision, à partir de l'indice, on
parcourt le tableau (en incrémentant i) jusqu'à trouver une case
libre.
Indice = (h(k)+i) mod M

cours d’algo. et prog. par Y.Q. Song 151


Sondage (probing)

Pour rechercher une clé :


on va calculer son indice,
puis on va descendre dans le tableau jusqu'à trouver la clé.
Si on tombe sur une case vide, c'est que la clé n'existe pas
(sinon on l'aurait rencontrée en chemin),
idem si on revient au point de départ.
Pour supprimer une clé:
la suppression est délicate et peut rendre inefficace la
recherche. Comme dit plus haut, on va descendre dans le
tableau jusqu'à trouver la clé ou une case vide...
Si la suppression rend une case vide sur le "chemin" à
parcourir, alors on perdra l'accès à certaines clés !

cours d’algo. et prog. par Y.Q. Song 152


Sondage (probing)
Par exemple, imaginons qu'on supprime purement et simplement
la clé 7 qui est à l'indice 5, après avoir inséré la clé 30.

Solution: lorsqu'on demande la suppression d'une clé, on la


garde mais marque la case comme libre.
Ainsi, lorsqu'on cherchera 30, on passera dessus sans problèmes.
Il faut juste penser, dans la méthode pour ajouter une paire "clé-
valeur", à chercher la première case vide ou marquée libre.

cours d’algo. et prog. par Y.Q. Song 153


Sondage (probing)

Quand le tableau est bien chargé, le sondage devient inefficace.


Exemple: insérer la clé 38

Le sondage linéaire est simple mais souffre d’un phénomène de


clustering, qui oblige de parcourir toute la grappe avant de
trouver une place vide.

cours d’algo. et prog. par Y.Q. Song 154


Sondage quadratique

l'intervalle entre les cases augmente linéairement


(les indices des cases augmentent donc quadratiquement)
indice = (h(k) + c*i2) mod M

Exemple: insertion de 22 et 30 (c=1)

Cette méthode évite dans une certaine mesure les grappes mais
forme des grappes secondaires
cours d’algo. et prog. par Y.Q. Song 155
Double hachage
Double hachage similaire à celui du sondage linéaire : on va chercher la
première case disponible en faisant varier un indice i, mais en plus de
l'incrémenter quand on rencontre une case occupée, on va aussi le
hacher ! Cela évitera mieux le « clustering » si la fonction de hachage est
bonne.
indice = (h(k) + i*h2(k)) mod M

Exemple: insertion des clés 22 et 30 avec h2(k)=2k+5


rappelons que hh(k)=3k+14 ; hc(x)=x mod M et h(k) = hc(hh(k))
h(22) = hc(hh(22)) = 0; h2(22)=49; l’indice est 0+0*49 mod 10 = 0
On incrémente i, et on recalcule indice=(0+1*49) mod 10 = 9

cours d’algo. et prog. par Y.Q. Song 156


Double hachage
Prenons l’exemple de 30
avec h(k)=3k+14 et h2(k)=2k+5
On a:
h(30)=4 et h2(30) = 65

i=0, l’indice est 4 (occupé)


i=1, l’indice est (4+1*65) mod 10 = 9 (occupé)
i=2, l’indice est (4+2*65) mod 10 = 4 (occupé)
i=3, l’indice est (4+3*65) mod 10 = 9 (occupé)

cours d’algo. et struct. par Y.Q. Song 157


Chaînage linéaire
Principe: utiliser une liste chaînée pour stocker les éléments en collision

cours d’algo. et prog. par Y.Q. Song 158


Facteur de charge
• Pas de méthode universelle pour gérer les collisions
(chacune a ses avantages et inconvénients, et peut
dégénérer)
– sondage linéaire: plus le tableau se remplit et plus des clusters se
formeront ;
– double hachage: idem que le sondage linéaire, mais sera plus
robuste ;
– chaînage linéaire: plus il y aura d'éléments et plus les listes seront
longues.
• Mais à cause souvent d’un facteur commun:
facteur de charge = (nb de clés insérées / taille du tableau)
• Solution: définir un facteur de charge maximum, et s'il est
dépassé on agrandira le tableau (redimensionnement
dynamique)
cours d’algo. et prog. par Y.Q. Song 159
Table associative (map) et dictionnaire
• Table associative et dictionnaire ont la même
structure: “clé-contenu”
• Les clés d’une table associative sont uniques
• Les clés d’un dictionnaire ne le sont pas
nécessairement !
• Type abstrait de tables associatives:
put(clé, valeur) : permet d'ajouter une paire "clé-valeur" ;
get(clé) : retourne la valeur associée à une clé ;
remove(clé) : supprime une paire ;
contains(clé) : retourne vrai si la clé se trouve dans la table, faux sinon ;
size() : retourne le nombre de paires entrées dans la table.

cours d’algo. et prog. par Y.Q. Song 160


Type abstrait de tables associatives
public interface SymbolTable
{ public void put(int key, Object value) throws
HashTableException;
public Object get(int key) throws HashTableException;
public void remove(int key) throws HashTableException;
public boolean contains(int key);
public int size();
}
public class HashTableException extends Exception
{
public HashTableException() { super() ; }
public HashTableException(String s) { super(s); }
}
cours d’algo. et prog. par Y.Q. Song 161
public class Entry
{
private int key;
private Object value;

public Entry(int key, Object value)


{
this.key = key;
this.value = value;
}

public int getKey() { return key; }


public Object getValue() { return value; }

public void setValue(Object value) { this.value = value; }


}
cours d’algo. et prog. par Y.Q. Song 162
public class Bucket
{
private Entry slot;
private boolean free = true;
public Bucket(Entry e)
{
this.slot = e;
this.free = false;
}
public void clean()
{
slot.setValue(null);
free = true;
}
public int getKey() { return slot.getKey(); }
public Object getValue() { return slot.getValue(); }
public boolean isFree() { return free; }

public void setValue(Object value) { slot.setValue(value) ; free = false; }


}

cours d’algo. et prog. par Y.Q. Song 163


public class HashTable implements SymbolTable
{
private Bucket[] bucketArray; // Tableau contenant les paires "clé-valeur”
private int nbrObject = 0; // Nombre d'éléments insérés
private CollisionManagement manager; // Gestionnaire de collision

public HashTable(int size) {//…}


public HashTable(int size, CollisionManagement manager) {//…}
public void put(int key, Object value) throws HashTableException{//…}
public Object get(int key) throws HashTableException{//…}
public void remove(int key) throws HashTableException{//…}
public boolean contains(int key) {//…}
public int size() {//…}
private int hash(String s) {//…}
private int getBucketIndex(int key) {//…}
}

public interface CollisionManagement


{
public int nextIndex(int h, int i);
}
cours d’algo. et prog. par Y.Q. Song 164
Constructeur avec spécification de “manager” de collision:
public HashTable(int size, CollisionManagement manager)
{
this.manager = manager;
bucketArray = new Bucket[size];
}

Constructeur avec sondage linéaire (LinearPobing) comme


manager par défaut :
public HashTable(int size)
{
this(size, new LinearProbing());
}
cours d’algo. et prog. par Y.Q. Song 165
La fonction de hachage

hh(k)=3k+14 nous a servi comme un exemple numérique


Mais il s’agit d’une très mauvaise fonction car trop de collisions

L’ideal serait d’avoir une fonction qui répartisse les clés


aléatoirement et uniformément, et elles sont toutes différentes.

Java fournit une fonction String.hashcode() qui est d’assez bonne


qualité.

Nous pouvons aussi concevoir d’autres fonctions de hachage

cours d’algo. et prog. par Y.Q. Song 166


Fonction simple
h(k) = somme de la valeur entière de chaque lettre de la clé k

private int hash(String s)


{
int h = 0;

for(int i = 0 ; i < s.length() ; i++)


h += (int) s.charAt(i);
return Math.abs(h) % bucketArray.length;
}
Voyez-vous un problème?
Quelle sera l’indice de “marie” et “maire”?
cours d’algo. et prog. par Y.Q. Song 167
Fonction polynomiale
On peut multiplier chaque caractère de la clé par un coefficient
qui varie selon la position (avec i comme exposant par exemple)
public int hash(String s) {
int h = 0;
int c = 42;
// Etape 1 - Hachage
for(int i = 0 ; i < s.length() ; i++) // parcourt tous les caractères
h += (int) s.charAt(i) * (int)(Math.pow(c, i));
// Etape 2 - Compression
return Math.abs(h) % bucketArray.length;
}
Le choix de la valeur de c influe la performance de la fonction (en
terme du nombre de collisions)
cours d’algo. et prog. par Y.Q. Song 168
Commentaire sur Compression
Imaginons que les valeurs de hachage de clés sont 15, 25 et 35 à
placer dans un tableau de 10 buckets.
On aura h = 15%10 = 25%10 = 35%10 =5

Soit p = 11 (un nombre premier)


Si h = (h % p) % 10, on aura: 4, 3, 2

Mais si p = 5 (un nombre premier aussi), quel problème voyez-vous?

En général, on prend p un nombre premier plus grand que la


taille du tableau.

cours d’algo. et prog. par Y.Q. Song 169


Implémentation utilisant hashCode du
java

private int hash(String cle) {


return Math.abs(cle.hashCode()) % bucketArray.length ;
}

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

Où s[i] est le code unicode du ième caractère

cours d’algo. et prog. par Y.Q. Song 170


Implémentation de getBucketIndex
Comment trouver le bucket qui contient une clé key ?
1. calculer l'indice de la clé avec la fonction de hachage ;
2. si la case est nulle (mais non libre « free ») ou si les clés
correspondent, retourner l'indice ;
3. sinon, passer à la case suivante en utilisant le gestionnaire de
collision (pour obtenir le prochain indice) et répéter 2.

BucketArray

Entry free
Bucket key val

cours d’algo. et prog. par Y.Q. Song 171


private int getBucketIndex(int key)
{
int h = hash(new Integer(key).toString()); // conversion de key vers
//String et calcul du hash code
int index = h; // index sera l'indice de la clé

for(int i = 0 ; bucketArray[index] != null &&


bucketArray[index].getKey() != key ; i++)
index = manager.nextIndex(h, i) % bucketArray.length;
// Obtention de la prochaine case
return index;
}

public class LinearProbing implements CollisionManagement


{
public int nextIndex(int h, int i)
{
return h + i;
}
}
cours d’algo. et prog. par Y.Q. Song 172
Implémentation de put

Tout d'abord, il faut vérifier que la table n'est pas pleine, et si


c'est le cas, renvoyer une exception.
Ensuite, il faut trouver la case dans laquelle devra s'insérer la
clé... avec notre méthode getBucketIndex qu’on vient de voir !
Deux cas se présenteront :
1.la case est vide (null) : on instancie la classe Bucket avec la
paire "clé-valeur" et on place la référence dans la case ;
2.la case n'est pas vide : on remplace l'élément

cours d’algo. et prog. par Y.Q. Song 173


Implémentation de put
public void put(int key, Object value) throws HashTableException
{
if (bucketArray.length = = nbrObject) // D'abord vérifier s'il reste de la place
throw new HashTableException("Table pleine.");
int index = getBucketIndex(key); // L'emplacement de la paire "clé-valeur”
boolean inc = true;

if (bucketArray[index] = = null) // Si l'emplacement est vide...


bucketArray[index] = new Bucket(new Entry(key, value));
// ... alors on y place la paire !
else // Si l'emplacement est déjà occupé ou libre (free)...
{
inc = bucketArray[index].isFree(); // On incrémente que dans le cas où la case est libre
bucketArray[index].setValue(value); // On remplace la valeur (choix d'implémentation)
}
if (inc) nbrObject++;
}
cours d’algo. et prog. par Y.Q. Song 174
Implémentation de get

On va d'abord chercher l'emplacement de la clé, avec


getBucketIndex, et (encore) deux cas se présenteront à nous :
1.la case est occupée : on peut retourner la valeur, car
getBucketIndex retourne toujours la case qui la contient ;
2.la case est vide ou libre, la clé n'est donc pas dans la table, et on
peut par exemple lancer une exception.

cours d’algo. et prog. par Y.Q. Song 175


public Object get(int key) throws HashTableException
{
if(nbrObject == 0) // Si la table est vide, cela ne sert à rien de continuer.
throw new HashTableException("Table vide.");

Bucket bucket = bucketArray[getBucketIndex(key)]; // Case dans laquelle


devrait se trouver la clé

if(bucket != null && !bucket.isFree()) // Si la case est occupée, on a trouvé


notre clé !
return bucket.getValue();
else
throw new HashTableException("Clé non trouvée");
}

cours d’algo. et prog. par Y.Q. Song 176


Implémentation de remove
- d'abord trouver la case dans laquelle se trouve la clé (toujours
grâce à getBucketIndex),
- et si elle existe, la "supprimer" avec la méthode clean()

public void remove(int key) throws HashTableException


{
if(nbrObject == 0) // Si la table est vide, cela ne sert à rien de continuer
throw new HashTableException("Table vide.");
Bucket delete = bucketArray[getBucketIndex(key)]; // La case à nettoyer
if(delete == null || delete.isFree()) // Si la case est vide ou déjà nettoyée, on
peut s'arrêter
throw new HashTableException("Clée non trouvée");
delete.clean();
nbrObject--;
}
cours d’algo. et prog. par Y.Q. Song 177
public boolean contains(int key)
{
Bucket bucket = bucketArray[getBucketIndex(key)];
return (bucket != null && !bucket.isFree());
}

public int size()


{
return nbrObject;
}

cours d’algo. et prog. par Y.Q. Song 178


Un exemple d’utilisation de HashTable
public class Test
{
public static void main(String[] argv) throws Exception
{
HashTable h = new HashTable(10, new LinearProbing());

for(int i = 0 ; i < 8 ; i++)


{
System.out.println("Ajout de " + i);
h.put(i, new Integer(i+2));
}
System.out.println("2 contains: "+h.contains(2));
System.out.println("0 contains: "+h.contains(0));
System.out.println("9 contains: "+h.contains(9));

System.out.println("clé 2: value="+h.get(2));
System.out.println("clé 3: value="+h.get(3));
}
}
cours d’algo. et prog. par Y.Q. Song 179
Le test donne…
Ajout de 0
Ajout de 1
Ajout de 2
Ajout de 3
Ajout de 4
Ajout de 5
Ajout de 6
Ajout de 7
2 contains: true
0 contains: true
9 contains: false
clé 2: value=4
clé 3: value=5

cours d’algo. et prog. par Y.Q. Song 180


Facteur de charge et
redimensionnement dynamique
- La taille des tableaux internes doit suivre une progression
géométrique au cours du temps.
- Le coût du redimensionnement doit être proportionnel au
nombre d’informations stockées dans la table au moment de
ce redimensionnement.

On fixe un facteur de charge alpha (=0,5 par exemple).


Si la charge dépasse alpha, on double la taille du tableau

Question: comment retrouver les paires clé-valeur si la taille du


tableau a changé (sachant que indice = h(k) % taille)?

cours d’algo. et prog. par Y.Q. Song 181


Redimensionnement dynamique
Créer un nouveau tableau
Transférer les données de l’ancien vers le nouveau
Modifier la méthode put() pour resize()

private void resize() {


int old_sz = bucketArray.length ;
int new_sz = 2*old_sz ;
Bucket [] oldT=bucketArray;
bucketArray= new Bucket[new_sz] ;
//copier les paires de l'ancien vers le nouveau en servant de
getBucketIndex(key)
for (int k=0;k<old_sz;k++){
Bucket p = oldT[k];
if (p != null)
bucketArray[getBucketIndex(p.getKey())] = p ;
}
} et prog. par Y.Q. Song
cours d’algo. 182
Implémentation de put avec resize
public void put(int key, Object value) throws HashTableException
{
if(bucketArray.length = = nbrObject) // D'abord vérifier s'il reste de la place
throw new HashTableException("Table pleine.");
int index = getBucketIndex(key); // L'emplacement de la paire "clé-valeur”
boolean inc = true;

if(bucketArray[index] = = null) // Si l'emplacement est vide...


bucketArray[index] = new Bucket(new Entry(key, value));
// ... alors on y place la paire !
else // Si l'emplacement est déjà occupé ou libre...
{
inc = bucketArray[index].isFree(); // On incrémente que dans le cas où la case est libre
bucketArray[index].setValue(value); // On remplace la valeur (choix d'implémentation)
}
if(inc) nbrObject++;
if (bucketArray.length*alpha < nbrObject) resize();
} cours d’algo. et prog. par Y.Q. Song 183
public class Test{
public static void main(String[] argv) throws Exception
{
HashTable h = new HashTable(10, new LinearProbing());

System.out.println("taille du tableau : "+h.bucketArray.length);

for(int i = 0 ; i < 8 ; i++)


{
System.out.println("Ajout de " + i);
h.put(i, new Integer(i+2));
}
System.out.println("nombre de paires: "+h.size());
System.out.println("2 contains: "+h.contains(2));
System.out.println("0 contains: "+h.contains(0));
System.out.println("9 contains: "+h.contains(9));
System.out.println("clé 2: value="+h.get(2));
System.out.println("clé 3: value="+h.get(3));
System.out.println("taille du tableau : "+h.bucketArray.length);
}
}
cours d’algo. et prog. par Y.Q. Song 184
taille du tableau : 10
Pour Ajout de 0
Alha=0,5 Ajout de 1
Ajout de 2
Le test Ajout de 3
donne… Ajout de 4
Ajout de 5
Ajout de 6
Ajout de 7
nombre de paires: 8
2 contains: true
0 contains: true
9 contains: false
clé 2: value=4
clé 3: value=5
taille du tableau : 20
cours d’algo. et prog. par Y.Q. Song 185
Table de hachage et fonction de
hachage dans java
• Il existe deux classes Hashtable<K,V> et
HashMap<K,V> dans java.util
• Java.lang.Object fournit une fonction de
hachage: public int hashCode()
• Il existe aussi une fonction de hachage
améliorée dans la classe String:
String.hashcode()

cours d’algo. et prog. par Y.Q. Song 186


Les objets Map en java: Hashtable et
HashMap
import java.util.Enumeration;
import java.util.Hashtable;
public class testHashtableJava {
public static void main(String[] args) {
Hashtable ht = new Hashtable();
ht.put(1, "printemps");
ht.put(10, "été");
ht.put(12, "automne");
ht.put(45, "hiver");
Enumeration e = ht.elements();
while(e.hasMoreElements())
System.out.println(e.nextElement());
}
}

cours d’algo. et prog. par Y.Q. Song 187


Hashtable (et HashMap) en java
Cette classe Hashtable nous offre tout un panel de méthodes
utiles :
•isEmpty() retourne « vrai » si l'objet est vide ;
•contains(Object value) retourne « vrai » si la valeur est
présente. Identique à containsValue(Object value) ;
•containsKey(Object key) retourne « vrai » si la clé passée en
paramètre est présente dans la Hashtable ;
•put(Object key, Object value) ajoute le couple key - value dans
l'objet ;
•elements() retourne une énumération des éléments de l'objet ;
•keys() retourne la liste des clés sous forme d'énumération.

HashMap est similaire, à la différence d’accepter la valeur null.


cours d’algo. et prog. par Y.Q. Song 188
Aspects pratiques: quelques
implémentations java
• Enumeration
• Collection
• Comparable
• Généricité en java

Cette partie s’inspire largement du tutoriel java de openclassrooms


Cf. le site de openclassrooms pour plus de détails

cours d’algo. et prog. par Y.Q. Song 189


Enumération

• Une énumération est une classe contenant une liste de


sous-objets.
• Elle permet de contenir une série de données constantes
ayant un type sûr (c.à.d., ni le type, ni la valeur réelle de
chaque constante n'est précisé).
• Une énumération se construit grâce au mot clé enum.
• Les enum héritent de la classe java.lang.Enum.
• Chaque élément d'une énumération est un objet à part
entière.
• Vous pouvez compléter les comportements des objets
d'une énumération en ajoutant des méthodes.
cours d’algo. et prog. par Y.Q. Song 190
Exemple d’énumération
public enum Langages {
JAVA, J'aime le : JAVA
C, C
CPlus, CPlus
Python; Python
}

public class testLangages {


public static void main(String[] args) {
for(Langages lang : Langages.values()){
if(Langages.JAVA.equals(lang))
System.out.println("J'aime le : " +
lang);
else
System.out.println(lang);
}
}
}
cours d’algo. et prog. par Y.Q. Song 191
Collection

cours d’algo. et prog. par Y.Q. Song 192


Implémentations en java

Table de Tableau de Arbre Liste chaînée


hachage taille variable
Set HashSet TreeSet
List ArrayList, LinkedList
Vector
Ma HashMap TreeMap
p

cours d’algo. et prog. par Y.Q. Song 193


Exemple de LinkedList et iterator
import java.util.LinkedList; Élément à l'index 0 = 12
Élément à l'index 1 = toto ! !
import java.util.List;
Élément à l'index 2 = 12.2
import java.util.ListIterator;
public class Test { Parcours avec un itérateur
public static void main(String[] args) { -----------------------------------
List l = new LinkedList(); 12
l.add(12); toto ! !
l.add("toto ! !"); 12.2
l.add(12.20f);
for(int i = 0; i < l.size(); i++)
System.out.println("Élément à l'index " + i + " = " + l.get(i));

System.out.println(" Parcours avec un itérateur ");


ListIterator li = l.listIterator();
while(li.hasNext()) System.out.println(li.next());
}
}cours d’algo. et prog. par Y.Q. Song 194
Collections
• Une collection permet de stocker un nombre variable
d'objets.
• Il y a principalement trois types de collection : les List, les
Set et les Map.
• Les Collection stockent des objets alors que les Map
stockent un couple clé - valeur.
• Si vous insérez fréquemment des données en milieu de
liste, utilisez une LinkedList.
• Si vous voulez rechercher ou accéder à une valeur via une
clé de recherche, optez pour une collection de type Map.
• Si vous avez une grande quantité de données à traiter,
tournez-vous vers une liste de type Set.
cours d’algo. et prog. par Y.Q. Song 195
Comparable et Collections.sort()

• Afin de pouvoir comparer des objets d’une collection, la


classe de ces objets doit implémenter l'interface
java.lang.Comparable en concrétisant la seule méthode de
l’interface :
– int compareTo(Object o)
– Ou depuis Java 5, interface Comparable<T> :
int compareTo(T o)
Qui compare this à o (this – o) et retourne <0, =0 et >0
• Une fois les objets sont comparables, nous pouvons aussi
utiliser la méthode Collections.sort() pour trier une
collection d’objets (par exemple dans une liste)

cours d’algo. et prog. par Y.Q. Song 196


public class Point implements Comparable<Point> {
public int x, y;
public Point(int abs, int ord) {
x = abs;
y = ord;
}
public boolean isAdjacent(Point p) {
return Math.abs(p.x - x) <= 1 && Math.abs(p.y - y) <= 1;
}
@Override
public int compareTo(Point p) {
if (y = = p.y)
return x-p.x;
else
return y-p.y;
}
}

cours d’algo. et prog. par Y.Q. Song 197


Généricité

• La généricité est de faire des classes qui


acceptent plusieurs types d'objets de façon
dynamique

Passer d’un type à Object ne résout pas le problème car


toujours un seul type d’instanciation
cours d’algo. et prog. par Y.Q. Song 198
généricité
public class Solo<T> {
//Variable d'instance
private T valeur;
//Constructeur par défaut
public Solo(){
this.valeur = null;
}
//Constructeur avec paramètre inconnu pour l'instant
public Solo(T val){
this.valeur = val;
}
//Définit la valeur avec le paramètre
public void setValeur(T val){
this.valeur = val;
}
//Retourne la valeur déjà « castée » par la signature de la méthode !
public T getValeur(){
return this.valeur;
} cours d’algo. et prog. par Y.Q. Song 199
}
import java.util.ArrayList;
import java.util.List;

public class testSolo {


public static void main(String[] args) {
Solo<Integer> val = new Solo<Integer>(123);
Solo<String> valS = new Solo<String>("TOTOTOTO");
Solo<Float> valF = new Solo<Float>(12.2f);
Solo<Double> valD = new Solo<Double>(12.202568);

List<Solo> al= new ArrayList<Solo>();


al.add(val);
al.add(valS); 123
al.add(valF);
al.add(valD);
TOTOTOTO
12.2
for(Solo s : al) 12.202568
System.out.println(s.getValeur());
}
}
cours d’algo. et prog. par Y.Q. Song 200
Synthèse sur la partie structures de
données et leurs algorithmes
• Structures de données dynamiques: Pour organiser des
données afin de permettre un traitement de ces dernières
plus efficace et rapide (e.g. diminuer la complexité)
• Structures récursives
– Liste chaînée (pile, file), graphe (tableau de listes chaînées, exemple
de Dijkstra), arbre (ABR, Tas, algorithmes de tri par ABR et par Tas,
complexité liée à la hauteur h proche de log2n)
• Structure indexée
– Table de hachage : tableaux associatifs avec clé d’accès (recherche à
O(1), problème de collision, fonctions de hachage, redimensionnement
dynamique)
• Type abstrait et conception descendante è génie logiciel
(2A)
cours d’algo. et prog. par Y.Q. Song 201

Vous aimerez peut-être aussi