Vous êtes sur la page 1sur 22

Algorithmiques

H. Soudé

16 janvier 2014
Table des matières

1 Complexité des algorithmes 2

2 Les structures de données élémentaires 3


2.1 Les enregistrements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2.1 Les opérations sur les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.2 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Les listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.1 Les listes chaı̂nées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.2 Les listes circulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3.3 Les listes symétriques ou doublement chaı̂nées . . . . . . . . . . . . . . . . . . 9
2.3.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4 Les listes : les variantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.1 Les piles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.2 Les files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.3 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3 Les algorithmes de tris et de recherche 13


3.1 Les algorithmes de tris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.1 Tri par sélection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.2 Le tri par insertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.3 Le tri à bulles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1.4 Le tri Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.5 Le tri rapide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.6 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2 Les algorithmes élémentaires de recherche . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.1 La recherche séquentielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.2 la recherche dichotomique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.3 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

1
Chapitre 1

Complexité des algorithmes

À faire

2
Chapitre 2

Les structures de données


élémentaires

2.1 Les enregistrements


L’enregistrement est une méthode d’organisation permettant de regrouper un certain nombre
de données de types différents dans le même espace. Les données sont liées selon une thématique et
peuvent être du même type.

enregistrement nom
champ1 : type1
..
.
champn : typen
fin

Figure 2.1 – Description d’un enregistrement.

Notation. La figure 2.1 présente la notation que nous adoptons pour la définition d’un enreg-
istrement. Les données sont stockées dans des variables qui sont appelées des champs, par conven-
tion. Les types des champs sont liés aux données. Pour désigner le ieme champ d’un enregistrement
Record on utilise la notation Record.champi

Représentation en mémoire. La figure 2.2 présente l’organisation en mémoire d’un enreg-


istrement permettant de stocker le point (3.5, 100) dans un repère orthogonale. Les coordonnées du
point sont placées dans un espace de 8 octets à l’adresse 0x720.

Exercice 2.1.1 — Comment peut-on représenter un cercle ? Proposer un algorithme permettant de calculer
le périmètre d’un cercle.

3
VARIABLE ADRESSE CONTENU

Enregistrement Point
absc : entier 720h
Point.absc 3.5
ordn : entier
724h 8 octets
Fin
Point.ordn 100
728h

Figure 2.2 – Représentation du point (3.5, 100) dans une mémoire organisée en mots de 32 bits.

Correction. Via l’enregistrement décrit à la figure 2.3

enregistrement Cercle
centre : Point
rayon : entier
fin

Figure 2.3 – Description de l’enregistrement Cercle.

Exercice 2.1.2 — Étant donné deux cercles, proposer un algorithme permettant de determiner lequel des
cercles est inscrit dans l’autre. Détailler la structure de données à utiliser pour le stockage des résultats.

Exercice 2.1.3 — Étant donné n cercles, proposer un algorithme permettant de déterminer le(s) cercle(s)
le(s) plus proche(s) du centre d’un repère orthogonal.

2.2 Les tableaux


Un tableau est une primitive présente dans la plupart des langages de programmation et permet
de regrouper un ensemble d’éléments de même type dans un même espace de la mémoire centrale.
Les éléments sont mémorisés dans un espace contigüe et accessible par un indice. La taille d’un
tableau doit être défini par l’utilisateur lors de sa création du tableau.

Notation. Dans le reste de ce document nous adoptons les notations suivantes : Array[1..N ]
désigne un tableau Array de N éléments et Array[j] désigne le j eme élément du tableau Array.

Représentation en mémoire. La figure 2.4 représente l’organisation en mémoire de cinq nom-


bres premiers présentés sous forme de tableau. La taille du tableau est déterminée par la taille du
type d’entier utilisé. Le tableau de la figure 2.4(a) est donc quatre fois plus grand que celui de la
figure 2.4(b) ; les données sont codées sur quatre octets d’un côté et un octet de l’autre.

4
ADRESSE CONTENU VARIABLE ADRESSE CONTENU

5000h 5000h
1 array[1] 1
5004h 5001h
2 array[2] 2
5008h 5002h
3 array[3] 3
500Ch 5003h
5 array[4] 5
5010h 5004h
7 array[5] 7

(a) (b)

Figure 2.4 – L’organisation en mémoire de cinq entiers codés sur un et quatre octets.

2.2.1 Les opérations sur les tableaux


La principale opération effectuée sur les tableaux est l’opération de parcours qui peut être
utilisée pour implémenter d’autres opérations telles que l’initialisation, la recherche d’un élément
et l’affichage des éléments du tableau.
Le pseudo code de l’algorithme 1 présente le squelette d’une fonction de parcours. Le parcours
consiste à explorer tous les éléments du tableau (indice par indice) en leur appliquant le traitement
voulu.
Input : tab[1..N ] : entier
for i ← 1 to N do
traitement de tab[i];
end
;
Algorithme 1 : L’algorithme de parcours d’un tableau.

2.2.2 Exercises
Exercice 2.2.1 — Proposer une sturcture de données pour mémoriser la liste d’entiers suivante (1, 10, 257, 15).
Présenter l’organisation interne de votre structure en supposant que la mémoire soit organisée en mots de
16 bits et que votre structure soit à l’adresse 0x400.

Exercice 2.2.2 — Présenter l’organisation en mémoire de la chaı̂ne de caractères un tableau.

Exercice 2.2.3 — Proposer une structure de données pour stocker quatre chaı̂nes de caractères dont les
tailles varient de quatre à six octets. Quelle est la taille totale de votre structure ?

Exercice 2.2.4 — Même question que précédemment en utilisation des pointeurs.

Correction.
– utilsation d’un tableau pour représenter chaque chaı̂ne de caractères.

5
– utilisation d’un tableau de quatre liens (ou pointeurs) vers les structures mémorisant les
chaı̂nes de caractères.
La figure 2.5 montre une représentation graphique de notre solution.

ADRESSE CONTENU

5000h
5004h BC06h
5008h 78004h
500Ch 7800Ah
A004h

voir
valse
A004h
texte1 t e s t
BCO6h
test v o i r

78004h
v a l s
78008h
e t e
7800Ch
x t e 1

Figure 2.5 – Manipulation de chaı̂nes de caractères avec des pointeurs.

Exercice 2.2.5 — En vous aidant du pseudo code 1 proposer un algorithme permettant de calculer la
somme des éléments d’un tableau.

Correction. Voir algorithme 2

Input : tab[1..N ] : entier


Output : S : entier
S←0;
for i ← 1 to N do
S ← S + tab[i];
end
;
Algorithme 2 : L’algorithme d’addition des éléments d’un tableau.

Exercice 2.2.6 — En vous aidant du pseudo code 1 proposer un algorithme permettant de calculer la
moyenne des éléments d’un tableau.

6
Exercice 2.2.7 — En vous aidant du pseudo code 1 proposer un algorithme permettant de déterminer
le maximum des éléments d’un tableau.

Exercice 2.2.8 — Proposer un algorithme permettant de déterminer le nombre d’entiers impairs dans un
tableau de taille n.

Exercice 2.2.9 — Proposer une structure pour stocker les éléments d’un rectangle. Proposer un algo-
rithme pour calculer la surface d’un rectangle.

Exercice 2.2.10 — Proposer un algorithme permettant de multiplier deux matrices.

2.3 Les listes


Définition. Un type abstrait de donnée (TDA) est une spécification algébrique d’un ensemble
d’éléments muni d’opérateurs. Le terme abstrait fait référence au fait que l’implémentation du type
n’est pas précisée dans sa spécification.
Une liste est un ensemble de zéro ou plusieurs éléments de même type comme un tableau.
Contrairement à un tableau, la taille d’une liste peut varier en cours d’utilisation.

Opérations. Comme tout les types abstraits, il existe un certain nombre d’opérations permettant
de manipuler les listes :
– insertion(L, pos, item) ; insérer l’élément item à la position pos de la liste L.
– position(L, item) ; rechercher la position de l’élément item dans la liste L.
– rechercher(L, pos) ; rechercher l’élément se trouvant à la position pos.
– suppression(L, item) ; supprimer l’élément item dans la liste L.
– compter(L) ; compter le nombre d’éléments dans la liste L.
– vide(L) ; teste si la liste L est vide ou non.
Les étudiants intéressés peuvent compléter la liste des opérations et les implémenter en guise
d’exercises.

2.3.1 Les listes chaı̂nées


Une liste chaı̂née est une liste dans laquelle les éléments sont liés selon une relation d’ordre
comme le montre la figure 2.6. La liste de la figure 2.6 définit ainsi l’ordre suivant e1 , e2 , e3 dans
laquelle e1 précède e2 et e2 précède e3 . De la même on peut dire que e1 suit e2 et e2 suit e3 .
L

e1 e2 e3

Figure 2.6 – Représentation d’une liste chaı̂née.

7
ADRESSE CONTENU ADRESSE CONTENU

720h
e2
6020h

720h
e1 5004h
724h e1
e2
728h 720h
e3

6020h
e3
−1

(a) (b)

Figure 2.7 – Différentes représentation mémoire d’une liste chaı̂née.

Représentation en mémoire. Une liste peut être mémorisée sous une forme contigüe ou de
manière dispersée dans la mémoire centrale.
Dans le cas le premier, les éléments de la liste sont stockés dans un tableau (cf. figure 2.7(a)).
L’ordre des indices du tableau définit l’ordre des éléments de la liste ainsi le premier élément de la
liste va se retrouver à l’indice 0, le suivant à l’indice 1 ainsi de suite.
Dans le second cas, chaque élément de la liste est stocké en utilisant un enregistrement permet-
tant non seulement de mémoriser l’élément en question mais aussi le lien vers le prochain élément(cf.
figure 2.7(b)).
Les deux méthodes présentent chacune des avantages et des inconvénients ; listez les.

Insertion – implémentation. L’algorithme d’insertion (cf. algorithme 4) consiste à, dans un


premier temps, chercher l’élément se trouvant à la position pos − 1 (cf. algorithme 3) et ensuite à
connecter l’élément trouvé au nouvel élément qui à son tour sera connecté au précédent successeur
de l’élément trouvé à la position pos − 1. Pour détecter la fin de la liste nous utilisons une sentinelle
qui sera placée à la fin de la liste.

8
Input : L : liste, p : entier
Output : n : un élément de la liste
Data : q : entier
n ← first(L) ;
q←1;
while ¬fin(L) do
if p = q then
return n ;
else
n ← next(L);
q ←q+1 ;
end
end
;
return ∅;
Algorithme 3 : L’algorithme de la fonction rechercher.
Input : L : liste, p : entier, n : élement de la liste
Data : q : élément de la liste
q ← rechercher(L, p-1) ;
n.next ← q.next ;
q.next ← n ;
Algorithme 4 : L’algorithme de la fonction insertion.
Input : L : liste, n : élement de la liste
Data : q : élément de la liste
q ← precedent(L, n) ;
q.next ← n.next ;
Algorithme 5 : L’algorithme de la fonction suppression.

Suppression – implémentation. L’algorithme de suppression (cf . algorithme 5) consiste à


déterminer le prédécesseur et le successeur de l’élément à supprimer. Le seul moyen de déterminer
le prédecesseur d’un élément est de parcourir la liste.

2.3.2 Les listes circulaires


Les listes circulaires sont, comme le montre la figure 2.8, des listes dans lesquelles le dernier
élément de la liste est lié au premier élément (la tête de liste). Cette particularité nous permet de
ne plus chercher une sentinelle pour détecter la fin de la liste.

2.3.3 Les listes symétriques ou doublement chaı̂nées


Les listes doublement chaı̂nées, comme le montre la figure 2.9, sont des listes dans lesquelles
chaque élément est lié non seulement à son successeur mais aussi à son prédécesseur. Cette par-
ticularité nous permet d’améliorer les opérations d’insertion et de suppression. La recherche du
prédécesseur d’un élément n’a plus lieu d’être.

9
head
e1 e2 e3

Figure 2.8 – Représentation d’une liste circulaire.

head
e1 e2 e3

Figure 2.9 – Représentation d’une liste doublement chaı̂née.

2.3.4 Exercices
Exercice 2.3.1 — Gestion de polynômes.
– Proposer une structure de données permettant de mémoriser des polynômes de degré quelconque.
Faire la représentation en mémoire d’un exemple de polynôme.
– Proposer des algorithmes permettant d’additionner de multiplier et de déterminer le degré d’un
polynôme.

Exercice 2.3.2 — Proposer un algorithme permettant de résoudre le problème de Josephus.


N personnes décident de se suicider de manière collective. Pour être sûr que personne ne changera
d’avis à la dernière minute, ils se mettent en cercle et décident, à chaque tour, de la personne à mourrir (la
meme personne). Le problème de Josephus consiste à trouver la dernière personne à se suicider et l’ordre
de suicide.

2.4 Les listes : les variantes


2.4.1 Les piles
Une pile est une liste dans laquelle les opérations se font à la fin de la liste (cf. figure 2.10). Elle
peut être désignée dans la littérature avec le terme ≪ LIFO (last in first out) ≫.
Les opérations sur les piles se limitent donc aux opérations suivantes :
– initialisation.
– videp ; teste si une pile est vide ou non .
– empiler ; ajout d’un élément sur la pile.
– depiler ; suppression d’un élément sur la pile.

2.4.2 Les files


Une file est une liste dans laquelle les opérations se font à la fin de liste sauf l’insertion qui se
fait en fin de liste (cf. figure 2.11). Elle peut être désignée dans la littérature avec le terme ≪ FIFO

10
OUT

IN

e3 e3
e3
e2 e2 e2 e2
e1 e1 e1 e1

empiler depiler

Figure 2.10 – Représentation d’une pile.

(first in first out) ≫.

OUT

e1 e1

e2 e2
e1 e2
e3 e3
e2 e3
e3

IN
enfiler defiler

Figure 2.11 – Représentation d’une file.

Les opérations sur les files se limitent donc aux opérations suivantes :
– initialisation.
– videp ; teste si une file est vide ou non .
– enfiler ; ajout d’un élément sur la file.
– defiler ; suppression d’un élément sur la file.

2.4.3 Exercices
Exercice 2.4.1 — Implémenter une pile à base de tableaux.

Exercice 2.4.2 — Implémenter une file à base de tableaux.

Exercice 2.4.3 — Soient six cars numerotés 123456 et placés à l’entrée d’une pile. Supposons que les
seules opérations permises soient empiler(E) et dépiler(D) un car. Donnez les séquences d’opérations
permettant d’avoir les permutations suivantes 325641 et 154623.
À titre d’exemple, la séquence EDEEDD permet de passer de 123 à 132.

11
Exercice 2.4.4 — Proposer un algorithme permettant l’évaluation d’une expression arithmétique en
notation postfixée ou notation polonaise inversée. L’expression , en notation postfixée, 45+3∗5+ correspond
à l’expression (4 + 5) ∗ 3 + 5, en notation infixée.

Exercice 2.4.5 — Proposer un algorithme de réécriture d’une expression infixée en une expression post-
fixée.

Exercice 2.4.6 — Proposer et analyser différentes structures pour manipuler des matrices (pleines,
creuses et triangulaires).

Astuce : les listes orthogonales.

12
Chapitre 3

Les algorithmes de tris et de


recherche

3.1 Les algorithmes de tris


Dans cette sections, nous présentons quelques algorithmes standards et leurs propriétés afin de
permettre aux étudiants de bien choisir pour une application donnée, l’algorithme de tri approprié.

3.1.1 Tri par sélection


Le tri par selection est l’un des algorithmes les plus simples et les plus intuitifs. Il commence par
rechercher l’élément le plus petit de l’ensemble à trier pour le remplacer avec l’élément se trouvant à
la première position. On recherche ensuite le deuxième élément plus petit pour l’échanger avec celui
en deuxième position et l’on continue jusqu’à ce que tout l’ensemble soit trié. À chaque itération,
l’ensemble des éléments considéré est celui des éléments restants 1 . L’algorithme 6 présente une
implémentation en pseudo code du tri par sélection.
La figure 3.1 présente un ensemble d’entier ( 9 8 1 4 5 ) trié avec le tri par sélection. Lors de la
première passe (troisième ligne du tableau), le plus petit élément 1 en troisième position est échangé
avec 9 en tête. Ensuite l’élément 4 en position 4 est échangé avec l’élément 8 en deuxième position.
L’élément 5 en cinquième position est échangé avec l’élément 9 en troisième position et ainsi de
suite.

Analyse du tri par sélection Le nombre de comparaisons éffectuées par ce tri est de l’ordre de
N 2 /2 dans le pire des cas alors que le nombre de d’échanges est de l’ordre de N , N représentant la
taille des données ou l’ensemble à trier.

3.1.2 Le tri par insertion


Le tri par insertion repose sur une méthode de tri utilisé par les joueurs de ¡¡bridge¿¿ : avant
d’examiner ou traiter un élément j, on s’assure que les éléments qui lui précède ont déjà été triés
1. Les éléments qui ne trouve pas encore à leur place définitive.

13
9 8 1 4 5
9 8 1 4 5
1 8 9 4 5
1 4 9 8 5
1 4 5 8 9
1 4 5 8 9

Figure 3.1 – Tri par sélection. Les éléments encerclés représentent les plus petits éléments à
chaque itération alors que les éléments doublement encadrés sont ceux ayant déjà été mis à leur
place définitive.

Input : tab[1..N ] : entier


Output : tab[1..N ]
Data : k, t : entier
for i ← 1 to N do
k←i;
for j ← i + 1 to N do
if T [j] < T [k] then
k←j ;
end
end
;
t ← T [k] ;
T [k] ← T [i];
T [i] ← t;
end
;
Algorithme 6 : Tri par sélection.

14
9 8 1 4 5
9 8 1 4 5
8 9 1 4 5
1 8 9 4 5
1 4 8 9 5
1 4 5 8 9

Figure 3.2 – Tri par insertion. Les éléments encerclés représentent les éléments à traiter alors que
les éléments doublement encadrés sont ceux ayant déjà été triés.

ensuite on recherche l’emplacement de j parmi ces éléments déjà triés. L’algorithme 7 présente une
implémentation en pseudo code du tri par insertion.
Comme nous pouvons le constater sur la figure 3.2, lors de la première passe (deuxième ligne),
l’élément 8 suppose que les éléments de gauche dans ce cas bien précis il n’existe qu’un seul élément
qui est l’élément 9 ensuite les deux éléments sont permutés. Lors de la deuxième passe, étant donné
que les éléments 8 et 9 sont déjà triés et que l’élément 1 leur est inférieur, les deux éléments 8 et
9 sont décalés vers la droite afin qu’on puisse insérer l’élément 1 à la première place. Lors de la
troisième passe l’élément 4 est inséré entre les éléments 1 et 8 en décalant une fois encore les élément
8 et 9 vers la droite et ainsi de suite.

Input : tab[1..N ] : entier


Output : tab[1..N ]
Data : i,j,k : entier
for i ← 2 to N do
k ← T [i] ;
while T [j − 1] > k do
T [j] ← T [j − 1] ;
j ←j−1 ;
end
T [j] ← k ;
end
Algorithme 7 : Tri par insertion.

Analyse du tri par insertion Le nombre de comparaisons éffectuées par ce tri est de l’ordre de
N 2 /4 en moyenne alors que le nombre de d’échanges est de l’ordre de N 2 , N représentant la taille
des données ou l’ensemble à trier. Dans le pire des cas ces valeurs sont doublées. Néanmoins le tri
par insertion est assez efficace pour trier des éléments ¡¡presque triés¿¿.

15
9 8 1 4 5
8 1 4 5 9
1 4 5 8 9

Figure 3.3 – Tri à bulles.

3.1.3 Le tri à bulles


Ce tri consiste à comparer les éléments adjacents un à un en leur changeant de place si nécessaire.
soit un ensemble de N éléments, les éléments en position 1 et 2 sont d’abord comparés ensuite ceux
en position 2 et 3 sont comparés et ainsi de suite. Ainsi les éléments les plus grands sont tous
décalés vers la droite. L’opération de comparaison des éléments adjacents est répétée jusqu’à ce que
l’ensemble soit trié.
L’algorithme 8 présente une implémentation en pseudo code du tri à bulles. Lors de chaque
passe, l’élément le plus grand de l’ensemble est décalé le plus à droite possible, la passe suivante n’a
donc plus besoin de comparer l’élément en cours avec tous les éléments du tableau. Cela explique
le faite que la deuxième boucle de notre algorithme soit bornée par la valeur de i.
La figure 3.3 présente un ensemble d’entier ( 9 8 1 4 5 ) trié avec le tri par sélection. Lors de la
première passe ( deuxième ligne), les éléments sont comparés une à une et on obtient l’ensemble de
la ligne 2. Dans un premier temps, on permute l’élément 8 et 9, les éléments 9 et 1, les éléments 9
et 4 et enfin les éléments 9 et 5. Lors de la seconde passe l’ensemble est trié.

Input : tab[1..N ] : entier


Output : tab[1..N ]
Data : i,j,k : entier
for i ← N to 1 do
for j ← 2 to i do
if T [j − 1] > t[j] then
k ← T [j − 1] ;
T [j − 1] ← T [j] ;
T [j] ← k ;
end
end
end
Algorithme 8 : Tri à bulles.

Analyse du tri à bulles Le nombre de comparaisons éffectuées par ce tri est de l’ordre de N 2 /2
en moyenne alors que le nombre de d’échanges est de l’ordre de N 2 /2, N représentant la taille des
données ou l’ensemble à trier. Ces valeurs restent inchangées dans le pire des cas. L’algorithme peut
être amélioré en arrêtant notre programme dès que l’ensemble est trié.

16
9 8 1 4 5
5 8 1 4 9
5 8 1 4 9
1 5 8 4 9
1 4 5 8 9

Figure 3.4 – Tri à shell.

3.1.4 Le tri Shell


Ce tri est une amélioration du tri par insertion. Le tri par insertion nécessite un temps moyen
proportionnel à N 2 car les opérations portent sur des éléments adjacents. Lorsque le plus petit
élément se trouve en fin de tableau, N − 1 étapes sont nécessaires pour le replacer. L’idée de base
est de réordonner l’ensemble en le subdivisant en petits groupes triés indépandemment.
L’algorithme 9 présente une implémentation en pseudo code du tri shell. À chaque passe, on
détermine la tailles de sous ensembles à trier. Nous obtenons de meilleurs résultats lorsque nous
utilisons des tailles Tn telles que Tn = 3Tn−1 + 1 où T0 = 1.
Dans l’exemple de la figure 9, notre est divisé d’abord en un sous ensemble de 4 ensuite en un
sous d’un élément. Les iemes éléments sont comparés aux (i + T n)emes éléments. Ainsi l’élément 5
en cinquième position est comparé à l’élément 1 en première position. Vue la taille de l’ensemble
à trier, l’ensemble a été subdiviser en 2 sous ensemble de 4 éléments. Lors de la seconde passe, la
taille des sous ensemble est de 1 et on retombe dans le configuration d’un tri par insertion.

Input : tab[1..N ] : entier


Output : tab[1..N ]
Data : i,j,h,v : entier
Déterminer Tn |Tn < N ;
for h ← Tn to 0 do
for i ← h + 1 to N do
v ← T [i] ;
j←i;
while j > h and T [j − h] > V do
T [j] ← T [j − h] ;
j ←j−h ;
end
T [j] ← v ;
end
end
Algorithme 9 : Tri shell.

17
ensemble de départ : 9 8 1 4 5
première passe : 4 8 1 9 5
deuxième passe : 4 1 8 9 5
passe finale : 4 1 5 9 8

Figure 3.5 – Un processus de partitionnement.

Analyse du tri shell Ce tri n’effectue jamais plus de N 3/2 comparaisons pour la suite Tn =
3Tn−1 + 1 où T0 = 1. Nous pouvons trouver la démonstration de cette propriété dans [?].

3.1.5 Le tri rapide


Cet algorithme utilise la méthode ¡¡diviser pour résoudre¿¿. L’idée de base est prendre ou de
choisir un élément pivot Ep et de trouver sa place définitive, 2 en réarrangeant l’ensemble tel que
les éléments se trouvant à gauche de Ep soient plus petit que Ep et que les éléments à droite soient
plus grands. Il faut ensuite trier les deux sous ensembles obtenus après le partionnement avec le
même procédé. L’algorithme 10 présente une implémentation en pseudo code du tri rapide.
afin de trouver l’emplacement définitif d’un élément dans un ensemble donné, nous utilisons
deux pointeurs ou marque i et j que nous initialisons avec l’extrémité de notre ensemble. Nous
recherchons les éléments Ei et Ej tels que tous les élément Ei soient dans le sous ensemble de
gauche et les élément Ej dans celui de droite. Nous parcourons donc le tableau depuis la gauche
jusqu’à rencontrer un élément supérieur à notre élément pivot ensuite nous parcourons le tableau
de la droite vers la gauche jusqu’à rencontrer un élément inférieur au pivot. Lorsque le pointeur de
gauche reste inférieur à celui de droite alors nous nous permutons les éléments Ei et Ej , dans le
cas contraire nous permutons les éléments Ep et Ei . La figure 3.5 montre le partionnement sur un
ensemble de cinq entiers où le dernier élément est choisi comme pivot. Le programme ?? donne une
implémentation du tri rapide.

Input : tab[1..N ] : entier ; g,d : entier


Output : tab[1..N ]
Data : i : entier
if d > g then
i ← pivot(T, g, d) ;
trirapide(T, g, i-1);
trirapide(T, i+1, d);
end
Algorithme 10 : Tri rapide.

L’analyse du tri rapide Ce tri effectue en moyenne 2N ln N comparaisons. Pour plus de détails,
les étudiants sont invités à consulter la littérature.
2. La place qu’elle devrait occuper dans l’ensemble trié

18
3.1.6 Exercices
Exercice 3.1.1 — Analyser les trois premiers algorithmes de tri.
– Appliquer les sur un tableau de 50 entiers, généré aléatoirement.
– Présenter le contenu du tableau après 0, N/2, N/4 et 3N/4 exécution de la boucle extérieure, en vous
servant de gnuplot. Représenter chaque élément du tableau par un point (x, y)|y = tab[x]
– Commenter et comparer les courbes.

Exercice 3.1.2 — Comparaison du tri par insertion et le tri rapide.


– Tracer la courbe d’execution des deux fonctions de tri en fonction de la taille du tableau à trier.
– Concluer

Exercice 3.1.3 — Proposer une implémentation non récursive du tri rapide. Refaire l’exercice précédent
et concluer.

3.2 Les algorithmes élémentaires de recherche


Le but de ces algorithmes est de retrouver un élément quelconque dans un ensemble donné.
Nous présentons les méthodes élémentaires que sont : la recherche séquentielle et dichotomique.

3.2.1 La recherche séquentielle


Elle représente la méthode la plus simple de recherche et consiste à parcourir un ensemble à
partir du début jusqu’ à rencontrer l’élément recherché.
L’algorithme 11 présente une implémentation en pseudo code de la recherche séquentielle.
Lorsque l’élément est trouvé la fonctionne retourne l’indice de l’élément dans le tableau et -1 dans
le cas contraire.

Input : tab[1..N ] : entier ; e, N : entier


Output : i : entier
for i ← 0 to N do
if T [i] = e then
return i
end
end
return-1;
Algorithme 11 : Recherche séquentielle.

L’analyse de la recherche séquentielle utilise en moyenne N/2 comparaisons en moyenne et


N dans le pire des cas.

3.2.2 la recherche dichotomique


La recherche dichotomique ou recherche binaire est basée sur le concept ¡¡diviser pour résoudre¿¿ :
nous divisons l’ensemble à trier en deux sous ensembles ensuite on détermine le sous ensemble dans

19
9 8 1 4 5
9 8 1 4 9
9 8 2 2 2
9 2 2 2 2

Figure 3.6 – La recherche dichotomique.

lequel l’élément à rechercher peut se trouver. Le procédé est répété avec le sous ensemble choisi et
ainsi de suite. Cette méthode ne marche que lorsque l’ensemble est trié ou ordonné. La figure 3.6
montre la recherche dichotomique de l’élément 9 en première position. Le programme 12 est une
implémentation de la recherche dichotomique.
L’algorithme 12 présente une implémentation en pseudo code de la recherche séquentielle.
Lorsque l’élément est trouvé la fonctionne retourne l’indice de l’élément dans le tableau et -1 dans
le cas contraire.

Input : tab[1..N ] : entier ; e,d,f : entier


Output : i : entier
Data : m : entier
m ← (d + f )/2 if e < T [m] then
i ← dicho(T, e, d, m − 1)
else if e > T [m] then
i ← dicho(T, e, m + 1, f )
else if e = T [m] then
return i
else
return-1
end
Algorithme 12 : Recherche séquentielle.

L’analyse de la recherche dichotomique Une recherche dichotomique nécessite au plus log N +


1 comparaisons pour trouver la donnée.

3.2.3 Exercices
Exercice 3.2.1 — Soit l’ensemble S de n ≥ 2 entiers.
– Proposer un algorithme pour trouver deux éléments (x, y) ∈ S 2 tels que |x − y| ≥ |u − v|∀(u, v) ∈ S 2 .
Déterminer la complexité de votre algorithme.
– Proposer un algorithme pour trouver deux éléments (x, y) ∈ S 2 tels que x 6= y et |x − y| ≤ |u −
v|∀(u, v) ∈ S 2 , u 6= v. Déterminer la complexité de votre algorithme. Proposer éventuellement une
amélioration.
– Soit m un entier abitraire proposer un algorithme en O(n log n) pour déterminer s’il existe (x, y) tels
que x + y = m.

20
Exercice 3.2.2 — Déterminer simultanément le minimum et le maximum de n entiers.
– Proposer une algorithme et déterminer sa complexité.
– Proposer une amélioration de votre algorithme.

Astuce : regrouper les éléments par paires.

21

Vous aimerez peut-être aussi