Vous êtes sur la page 1sur 15

1ère année – 1er semestre

Spécialité Informatique
Filière par apprentissage

TD « Bases de l’algorithmique »

Sujets :

• Drapeau hollandais
• Construction automatique d’un labyrinthe – Algorithme de la main droite pour en sortir
• Tris internes : tri insertion et Shellsort
• Tri externe : natural mergesort
• Récursion (factorielle, Fibonacci, coef. du binôme, tours de Hanoï)
• Implantation d’une pile dans un tableau – application à la mise sous forme postfixée
d’expressions arithmétiques infixées non complètement parenthésées et à l’évaluation
d’expressions arithmétiques postfixées.
• Implantation d’une file dans un tableau – réussite de l’horloge
• Tri par distribution : implantation des fonctions sur les files chaînées avec pointeurs sur la tête et
la queue – fonction de concaténation de deux files).
• Fusion de fichiers à l’aide d’un tas

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 1


Le drapeau hollandais

On dispose de cailloux rouges, bleus et blancs alignés dans un ordre quelconque.


Par échanges successifs de cailloux (et non par constitution de paquets séparés à un autre endroit),
atteindre la situation finale :
Cailloux bleus Cailloux blancs Cailloux rouges

Contraintes supplémentaires :
• Ne tester qu’une seule fois la couleur de chaque caillou (en cela, l’algorithme est optimal).
• Doit pouvoir fonctionner quels que soient le nombre de cailloux de chaque couleur (y compris
s’il n’y a aucun caillou d’une certaine couleur).

Idée :
On examine les cailloux de gauche à droite en faisant en sorte d’avoir toujours l’une derrière
l’autre :
• une suite de cailloux bleus (S1)
• une suite de cailloux blancs (S2)
• une suite de cailloux non encore examinés (S3)
• une suite de cailloux rouges (S4).
bleu blanc ??? rouge
S1 S2 S3 S4

• Au départ, S1, S2, S4 sont vides, S3 est la suite initiale de tous les cailloux,
• A la fin, S3 est vide.

Analyse :
• Définir une situation
• Définir le passage d’une situation à la suivante.

Algorithme :
• Définir la situation de départ
• Tant que tous les cailloux ne sont pas rangés
Passer de la situation présente à la suivante.

Une situation :
nb_cailloux = nombre total de cailloux
nb_bleu є [0..nb_cailloux]
nb_blanc є [0..nb_cailloux]
nb_rouge є [0..nb_cailloux]
inconnus є [1..nb_cailloux]

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 2


nb_bleu nb_blanc inconnus nb_rouge

le prochain caillou
à examiner

Passer d’une situation à la suivante :


Selon la couleur du caillou inspecté :
BLEU

échange avec le premier caillou blanc

nb_bleu = nb_bleu + 1 ;

BLANC

on ne fait rien

nb_blanc = nb_blanc + 1 ;

ROUGE

échange avec le dernier caillou inconnu

nb_rouge = nb_rouge + 1 ;

Représentation des objets :


− les cailloux : caractérisés uniquement par leur couleur
− la rangée de cailloux : un tableau.

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 3


Génération automatique d’un labyrinthe
Le but de ce TD est d'écrire un programme générant un labyrinthe. Notre labyrinthe est défini par
une grille rectangulaire dont les cases peuvent être pleines (mur) ou vides (couloir).

Pour générer le labyrinthe on essaie d'étendre les murs déjà existants. On définit pour cela des cases
dites « constructibles ». Une case X est constructible si elle se trouve dans une des situations
suivantes :
vide vide ?
vide X mur
vide vide ?

? mur ?
vide X vide
vide vide vide

? vide vide
mur X vide
? vide vide

vide vide vide


vide X vide
? mur ?

On commence par une grille initialisée avec des murs aux bords puis, tant qu'il reste des cases
constructibles, on en construit une au hasard. On peut aussi ajouter des îlots pour que la
construction ne se fasse pas uniquement à partir du bord.

1. Écrire une fonction estConstructible() qui teste si une case du labyrinthe est constructible ou
non.
2. Écrire ensuite le programme dont les principales étapes sont :
• déclarer le tableau
• initialiser avec des murs aux bords, et n îlots placés au hasard (n entré par l'utilisateur)
• marquer les cases constructibles et les compter (ncons)
• tant que ncons > 0
− choisir n tq 1 <= n <= ncons
− trouver les coordonnées de la nième case constructible (suivant un ordre à définir)
− construire cette case, décrémenter ncons
− vérifier l'état (constructible ou non) des 8 cases autour de celle qu'on vient de construire
et ajuster le cas échéant.
• afficher le labyrinthe.

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 4


Algorithme de la main droite pour trouver la sortie d’un labyrinthe

Analyse :
• Définir une situation
• Définir le passage d’une situation à la suivante.

Une situation :
• Le labyrinthe qui ne change pas
• La personne dans la labyrinthe, caractérisée par sa position et son orientation, avec comme
invariant : sa main droite ne quitte pas le mur.
Algorithme :
• Définir la situation de départ : On place la personne à l’entrée du labyrinthe, sa main droite
sur le mur.
• Tant que la personne n’a pas trouvé la sortie
Passer de la situation présente à la suivante.

Passer d’une situation à la situation suivante : 3 cas


1. La personne peut avancer ; quand elle a avancé, sa main droite est sur un mur.

2. La personne peut avancer ; quand elle a avancé, sa main droite n’est plus sur un mur. Alors,
elle tourne à droite, puis elle avance et, là, sa main droite est sur un mur.

3. La personne ne peut pas avancer ; elle tourne à gauche et sa main droite est sur un mur.

S’il n’y a pas de mur devant (cas 1 et 2)


Alors Avancer
S’il n’y a pas de mur à droite (cas 2)
Alors Tourner à droite
Avancer
Sinon (cas 3) Tourner à gauche

Les mouvements autorisés : Avancer, Tourner à droite, Tourner à gauche.


Tester l’environnement : Mur devant ? Mur à droite ? Sortie ?

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 5


Tri sélection et variante

1/ Tri sélection

void tri_selection(element *tab, int n)


{int i,j,imin;
element inter;

for (i=0; i<n-1; i++)


{imin=i;
for (j=i+1; j<n; j++)
if (tab[j]<tab[imin]) imin=j;
if (i!=imin)
{inter=tab[imin]; tab[imin]= tab[i]; tab[i]=inter;}
}
}

2/ Variante

L'idée et de chercher simultanément le minimum et le maximum, et d'échanger le minimum avec le


premier élément et le maximum avec le dernier.

2-1/ Ecrire une fonction min_et_max qui détermine simultanément l'indice du minimum et l'indice
du maximum du morceau de tableau compris entre les indices i et j.

2-2/ Recenser et étudier les divers cas possibles concernant les 4 indices i, j, imin, et imax.

il y a 7 cas :
1. i, j, imin et imax tous distincts
2. i = imin, j et imax distincs
3. i = imax, imin et j distincts
4. j = imin, i et imax distincts
5. j = imax, i et imin distincts
6. i = imin et j = imax
7. i = imax et j = imin.

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 6


Tri insertion & Tri Shell

1/ Tri insertion
On considère que la partie gauche du tableau est déjà ordonnée et on cherche à insérer le prochain
élément de la partie droite du tableau à la bonne place parmi les éléments déjà ordonnés.

Attention, les éléments à trier sont compris entre les indices 1 et n du tableau car on fait jouer à la
case 0 le rôle de sentinelle : on y place en effet l'élément à insérer; cela permet de simplifier la
condition d'arrêt du while (c'est dans cette boucle qu'on détermine la bonne position d'insertion).
void tri_insertion(element *tab, int n)
{int i, j;
/* attention! on utilise la case tab[0] du tableau comme sentinelle */
for (i = 2; i <= n; i++)
{tab[0] = tab[i]; j = i-1;
while (tab[0] < tab[j])
{tab[j+1] = tab[j]; j--; }
tab[j+1] =tab[0];
}
}

2/ Tri Shell
Imaginé par D. L. Shell (« A high-speed sorting procedure », Communications of the ACM, 2:30,
1959.) ce tri est une accélération du tri par insertion. Dans le tri par insertion, un élément va à sa
place en progressant lentement, case par case. L'accélération consiste à le faire aller à sa place en
commençant par faire des grands pas, puis des pas de plus en plus petits, jusqu'à, évidemment, des
pas de 1 pour que le tableau soit trié.
• L'étape de base de l'algorithme considère le tableau initial constitué de h sous-tableaux, dont les
éléments sont distants de h cases. ces h tableaux sont triés par l'algorithme de tri par insertion.
On dit alors que le tableau initial est h-trié.
• On répète cette opération de base pour des valeurs de h qui vont en diminuant jusqu'à une valeur
finale 1.
La qualité du tri Shell va dépendre de la suite des valeurs de h. Une « bonne » suite est donnée par :
h1 = 1
hn = 3 * hn-1 + 1

void shellsort(element *tab, int nb)


{int i, j, h;
element x ;
/* calcul de la valeur initiale de h */
h= 1;
while( h <= nb) h = 3*h + 1;
while ( h > 1)
{h = h / 3;
/* tri par insertion des h tableaux */
for (i = h; i < nb; i++)
{x= tab[i], j = i;
while (j >= h && tab[j-h] > x)
{tab[j] = tab[j-h]; j = j - h; };
tab[j] = x;
}

}
}

On peut imaginer d'autres suites pour h : hn = 2n –1 ou encore un h tel que h = 2p * 3q

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 7


Tri externe : natural mergesort

On présente ici un tri externe appelé "natural mergesort", qui effectue des suites de
fusion/séparation de fichiers.
L'intérêt est double:
- rappels sur les fichiers binaires en C, manipulés de manière strictement séquentielle
(sans utilise la fonction fseek),
- exemple d'application d'une démarche d'analyse descendante.

Exemple:
Supposons que le fichier de départ f contienne: 15 | 7 8 11 29 | 13 | 5 58 | 22
On ne fait figurer ici que les clés.
Le signe | sert à visualiser les périodes de clés c-à-d. les suites de clés déjà ordonnées.

On sépare f en 2 fichiers f1 et f2 en répartissant alternativement une période sur f1, une période sur
f2… On obtient:
f1 15 | 13 22
f2 7 8 11 29 | 5 58
On fusionne les périodes de f1 et f2 dans f.
f 7 8 11 15 29 | 5 13 22 58
On recommence une phase de séparation:
f1 7 8 11 15 29
f2 5 13 22 58
Et on termine par une phase de fusion:
f 5 7 8 11 13 15 22 29 58 f est trié puisque composé d'une unique période.

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 8


Récursion

1) L’objectif est de programmer de façon récursive, de valider et d’évaluer le coût de cette


approche. On pourra choisir 1 de calculer par exemple :

• factorielle(n) = n * factorielle(n-1) avec factorielle(0) = 1 :


• l’un des éléments de la suite de Fibonacci :
Un = Un-1 + Un-2 avec U1 = 1 et U0 = 0.
• l’un des coefficients du binôme
Cnp = Cnp−−11 + Cnp−1 avec Cn0 = 1 et Cnp = 0 si p > n

1. Programmer de façon récursive l’élément demandé.

2. Valider et évaluer (en traçant les entrées/sorties des fonctions, en comptant les appels).

3. Diminuer le coût en réalisant une mémo-fonction qui garde les valeurs déjà calculées (on
utilisera tableau static plutôt qu’une variable globale)

4. On pourra éventuellement comparer les coûts (exécution et développement) avec une


approche itérative.

2) Les tours de Hanoi (aussi appelées Tours de Brahma ou Puzzle de la fin du monde) ont été
inventées par un mathématicien Français, Edouard Lucas, en 1883. Il a été inspiré par une
légende. Dans un temple Hindou, les prêtres reçurent une pile de 64 disques d'or, chacun un peu
plus petit que celui d'en-dessous, empilés sur un poteau, et deux poteaux vides. Ils devaient
transférer les 64 disques d'un poteau à un autre, avec une seule règle : Un disque ne peut pas
être placé sur un autre disque plus petit. La fin du monde arrivera lorqu'ils finiront leur travail.

Récapitulons les règles :


- Le terrain est constitué de trois tours.
- nb_disques disques de tailles toutes différentes sont empilés sur l'une des tours, par taille
décroissante avec le plus grand en bas.
- Chaque disque est forcément sur une des trois tours.
- Un disque ne peut jamais être posé sur un autre disque plus petit. Par contre, il peut être
posé sur un disque plus grand.
- Un seul disque peut être déplacé à la fois.

cf. http://ilotresor.com/jeux/jeux_hanoi.html pour une démonstration.

Le nombre de déplacements répond à la loi géométrique suivante :


nb_déplacements = 2^nb_disques - 1

2^64 = 18446744073709551616

1 On pourra éventuellement « user avec modération » de la fonction d’Ackermann qui se définit de la façon suivante :
Ackermann(m,n) =
si m=0 alors n+1
sinon si n=0 alors Ackermann(m-1,n)
sinon Ackermann(m-1, Ackermann(m,n-1))

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 9


Mise sous forme postfixée et évaluation d’expressions arithmétiques

1/ Mise sous forme postfixée d’expressions arithmétiques infixées non complètement parenthésées

On suppose que les expressions arithmétiques à analyser comprennent :


− des opérandes élémentaires, représentés par une seule lettre dans l’intervalle [‘a’..’z’]
− des opérateurs binaires '+', '-', '*', '/', '^'
− des parenthèses '(' et ')'.

Les opérateurs sont hiérarchisés par priorité d’exécution, de sorte que les expressions n’ont pas
besoin d’être totalement parenthésées :
− + et – ont la priorité la plus faible (1)
− + et / la priorité 2,
− ^ la priorité 3.
A l’intérieur d’un même niveau de priorité, les opérations sont effectuées de gauche à droite, à
moins qu’un parenthésage n’indique le contraire.

Exemple d’expression arithmétique infixée non complètement parenthésée :


a – (b + c * d / e – f ) * g^h
Sa forme postfixée est : abcd*e/+f–gh^*-

L’algorithme de transformation utilise deux chaînes de caractères et une pile p. La première chaîne,
expr_infixe, est l’expression à transformer. La caractère courant est dénoté car. Au début, car
est le premier caractère à gauche. La seconde chaîne, expr_postfixe, qui se constitue
progressivement de gauche à droite, est la forme postfixée cherchée.

Les opérandes transitent directement de expr_infixe vers expr_posfixe, tandis que les opérateurs
passent de expr_infixe à p et de p à expr_postfixe. Les parenthèses ouvrantes passent de
expr_infixe à p, mais ne vont pas dans expr_postfixe. Les parenthèses fermantes ne passent ni
dans p, ni dans expr_posfixe.

Algorithme :
car = premier caractère à gauche de expr_infixe
p = vide
expr_postfixe = vide
erreur := faux

tant que (car non vide ou p non vide) et (non erreur)


selon car et p :

car est opérande :


ajouter car à expr_postfixe
avancer dans expr_infixe

car est '(' :


empiler car
avancer dans expr_infixe

car est opérateur et (p est vide ou sommet de p est '(' ) :


empiler car
avancer dans expr_infixe

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 10


car et sommet de p sont opérateurs :
selon priorités :

car plus prioritaire que sommet de p :


empiler car
avancer dans expr_infixe

car même priorité


ou moins prioritaire que sommet de p :
ajouter à expr_postfixe l’opérateur qui
est au sommet de p
dépiler
/* on n’avance pas dans expr_infixe */

(car est vide ou ')') et sommet de p est opérateur :


ajouter à expr_postfixe l’opérateur qui
est au sommet de p
dépiler
/* on n’avance pas dans expr_infixe */

car est ‘)’ et sommet de p est '(' :


dépiler
avancer dans expr_infixe

autres cas : erreur dans expr_infixe ;

2/ Evaluation d’expressions arithmétiques postfixées.

L’évaluation d’une expression postfixée se fait à l’aide d’une pile au fur et à mesure qu’on lit
l’expression de la gauche vers la droite. Lorsqu’un opérande se présente, sa valeur est mise au
sommet de la pile. Lorsqu’un opérateur binaire se présente, ses opérandes sont les deux valeurs au
sommet de la pile : on effectue l’opération et le résultat remplace ces deux valeurs au sommet. La
valeur finale de l’expression est la seule valeur restant dans la pile quand l’expression a été
entièrement lue.

Exemple d’exécution :
expr_postfixe = a b + c d * e + * avec a = 9, b = 8, c = 7, d = 4, e = 2.

Etats successifs de la pile :


9
9 8
17
17 7
17 7 4
17 28
17 28 2
17 30
510

Représentation des piles : représentation contiguë


La pile est stockée dans un tableau. On a besoin d'un entier pour indiquer le nombre d'éléments
contenus dans la pile et en déduire l'indice du sommet de la pile.

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 11


Réussite de l’horloge
Règle du jeu:
La réussite de l'horloge se joue avec un jeu ordinaire de 52 cartes. Elle doit son nom au fait que les
cartes sont disposées suivant les douze positions des heures sur une horloge.

Au départ, les cartes sont placées non retournées en 13 paquets de 4 cartes, un paquet correspondant
à chacune des heures, le 13ième paquet se trouvant au centre de l'horloge.

Le joueur commence la réussite en prenant la première carte du paquet central et en la glissant,


retournée, sous le paquet correspondant à la hauteur de la carte. Il prend alors la première carte de
ce paquet, et ainsi de suite.

Par exemple, il place un 6 sous le paquet de 6 heures et prend pour continuer la première carte de ce
paquet. Un valet est placé sous le paquet de 11 heures, une dame sous le paquet de 12 heures et un
roi sous le paquet central.

La réussite se poursuit ainsi jusqu'à ce que toutes les cartes soient retournées. Elle échoue quand on
place une carte sous un paquet dont toutes les cartes sont déjà retournées puisqu'il n'y a plus alors de
cartes au sommet de ce paquet pour continuer.

Représentation des paquets de carte : Files d’attente en représentation contiguë

La file est stockée dans un tableau. On utilise deux entiers pour repérer la position de la tête de file
et la position de la queue de file. Attention ! la queue de file repère en fait la position du prochain
ajout. En effet, c'est la seule manière possible pour différencier une file vide d'une file réduite à un
élément.
0 1 2 3 4 5 6 7 8 9
10 20 30 40
4
8
la queue indique la position du prochain ajout

File vide
0 1 2 3 4 5 6 7 8 9

4
4

File pleine
0 1 2 3 4 5 6 7 8 9
70 80 90 10 20 30 40 50 60
4
3

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 12


Tri par distribution

Cette méthode s'applique aux tris de nombres entiers et aux tris alphabétiques. Si nous considérons
une suite de nombres de nbc chiffres (ou une suite de mots de nbc caractères), le tri s'effectue par
distributions successives en considérant d'abord les chiffres des unités puis celui des dizaines, des
centaines, etc.... A chaque passage nous formons des groupes de nombres suivant ce critère, puis
nous reconstituons à partir de ces groupes une nouvelle suite qui sera utilisée pour la distribution
suivante. Le nombre de distributions est égal au nombre de chiffres du plus grand nombre.

Application sur une suite de nombres:


Soit une suite de 12 nombres (d'au plus 3 chiffres) :
3 127 37 51 18 172 25 45 7 33 11 131

Pour la première distribution, nous considérons le chiffre des unités et nous obtenons les groupes
suivants:

0 1 2 3 4 5 6 7 8 9
51 172 3 25 127 18
11 33 45 37
131 7

Pour recréer la suite, nous prenons successivement les groupes formés dans l'ordre croissant des
chiffres (car nous faisons un tri par ordre croissant), soit:
51 11 131 172 3 33 25 45 127 37 7 18

En faisant maintenant la distribution suivant le chiffre des dizaines, nous obtenons les groupes
suivants:

0 1 2 3 4 5 6 7 8 9
03 11 25 131 45 51 172
07 18 127 33
37

La nouvelle suite a alors la configuration ci-dessous :


03 07 11 18 25 127 131 33 37 45 51 172

Nous faisons la dernière distribution sur le chiffre des centaines :

0 1 2 3 4 5 6 7 8 9
003 127
007 131
011 172
018
025
033
037
045
051

Et nous obtenons finalement les nombres triés :


003 007 011 018 025 033 037 045 051 127 131 172

Représentation des suites de nombres : Files d’attente en représentation chaînée

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 13


Fusion de fichiers triés à l’aide d’un tas
Définition:
Un tas (heap en anglais) est un arbre binaire parfait (tous les niveaux sont complètement remplis,
sauf peut-être le dernier, où tous les nœuds sont le plus à gauche possible) qui est de plus
partiellement ordonné: en tout nœud de l'arbre, la valeur du nœud père est supérieure (resp.
inférieure) à la valeur de chacun de ses nœuds fils. De ce fait, la valeur maximale (resp. minimale)
est située à la racine.

Dans un arbre binaire parfait, l’ordre hiérarchique des nœuds est obtenu en effectuant un parcours
de l’arbre niveau par niveau et de la gauche vers la droite, à partir de la racine.

Voici deux exemples de tas: dans celui de gauche, c'est le plus petit élément qui se trouve au
sommet du tas; dans celui de droite, c'est le plus grand élément.
14 85

20 17 71 36

49 32 26 27 55 49 26 27

71 55 36 20 14 32 17

Du fait qu'un tas est un arbre "assez compact", on peut le représenter simplement dans un tableau
dont les indices sont les numéros hiérarchiques des nœuds.

Pour l'arbre de gauche, on obtient :


1 2 3 4 5 6 7 8 9 10
14 20 17 49 32 26 27 71 55 36

Avec cette représentation, les fils du nœud d'indice i se trouvent aux indices 2*i et 2*i+1 et le père
du nœud d'indice i se trouve à l'indice i/2.

Fusion de fichiers à l'aide d'un tas:


La structure de tas a de multiples utilisations. Nous allons l'utiliser pour fusionner N fichiers triés en
ordre croissant en un seul fichier trié. Ces fichiers sont des fichiers binaires d'éléments possédant
une clé entière qui définit la relation d'ordre.

On commencera par supposer que N est de la forme 2k.

Le principe de l'algorithme est de gérer un tas de la façon suivante:


- le fichier résultat est rempli en prenant des éléments sur la racine du tas.
- le tas est alimenté par les N fichiers d'entrée, chacun étant associé à une feuille de celui-ci.

On suppose que l'on dispose d'une fonction lecture(i) qui lit dans le ième fichier la première valeur
non encore lue. Quand tous les éléments du fichier ont été lus, lecture(i) retourne +∞ (un nombre
très grand).

Plus précisément, l'algorithme comprend deux phases:

1ère phase: initialisation


On constitue un tas avec les plus petits éléments des N fichiers en procédant comme suit:
Les nœuds de l'arbre sont initialisés avec -∞ (un nombre très petit), puis l'arbre est peu à peu rempli
de la manière suivante:
1- L'élément situé à la racine est "enlevé" de l'arbre.
Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 14
2- On réorganise l'arbre en faisant "monter" les éléments de manière à retrouver la propriété
de tas.
-Quand un élément est déplacé d'un nœud ND au père de ND, un autre élément doit
être immédiatement monté en ND.
-Quand c'est un élément d'une feuille qui est déplacé vers le haut, la fonction lecture
est appelée avec le numéro du fichier associé à cette feuille de l'arbre pour placer une
nouvelle valeur dans cette feuille.
3- On réitère jusqu'à ce que le tas soit rempli.

2ème phase: constitution du fichier résultat


Le processus est rigoureusement identique à celui de l'initialisation sauf en ce qui concerne le
traitement de la racine. L'élément "enlevé" de la racine est placé dans le fichier résultat.
On réitère jusqu'à ce que tous les éléments des N fichiers d'entrée aient été lus et placés dans
le fichier résultat. On s'arrête alors car la racine de l'arbre contient +∞.


Fichier résultat
• •

• • • •

• •

• • Lecture (i) • •

Fn
F1 F2

L'opération fondamentale est donc la "montée" d'éléments pour "boucher le trou" laissé quand on a
enlevé l'élément situé à la racine du tas. Cette montée d'éléments doit respecter la propriété de tas. A
la fin de l'opération, il n'y a plus de "trou" et on a à nouveau à la racine du tas le plus petit élément.

La figure suivante montre ce qui se passe pendant une opération de "montée" (on n'a représenté que
les clés des éléments).
14 17

20 17 20 17 20
49 32 26 27 49 32 26 27 49 32 26 27
17 17

20 26 20 26

49 32 27 49 32 36 27

lecture de l'élément suivant


dans le 3ème fichier

Pour comprendre, faire tourner l'algorithme à la main dans le cas où N=4, avec des fichiers
contenant quelques éléments.
Que suggérez-vous si le nombre de fichiers à fusionner n’est pas une puissance de 2 ?

Christine PORQUET- ENSICAEN - - TD « Bases de l’algorithmique » - 26 octobre 2007 - 15

Vous aimerez peut-être aussi