Vous êtes sur la page 1sur 191

Structures de donnes et algorithmes

INTRODUCTION
Les performances d'un programme dpendent,
gnralement, de deux importantes caractristiques:
a) la structure de donnes utilise
b) la qualit des algorithmes.
C'est pour a que la structure de donnes et les techniques
d'laboration des algorithmes sont tudis sparment, aprs la
connaissance des principaux lments d'un language de
programmation.
L'utilisation des structures de donnes appropries un
certain programme permet un grand dgr de flexibilit et peut
apporter un important gain de temps dans le droulement du
programme.
L'laboration d'un algorithme optimal pour une
application peut aussi diminuer la dure de droulement du
programme. Usuellement, on labore un algorithme par les
suivantes tapes:
- on crit un algorithme,
- on le traduit dans un adequat language,
- on corrige les erreurs de syntaxe et de logique du
programme,
- on essaye d'estimer le temps moyen de droulement du
programme.
Si les temps de droulement sont trop grands, on cherche
optimiser l'algorithme. Ici intervient l'exprience du
programmeur et surtout la modalit dont il sait concevoir un
algorithme. Quand on ne russit pas optimiser le temps
d'excution, il y a une autre mthode: on passe l'algorithme dans
un langage ASSEMBLER. Mais cette mthode ncessite un long
3
Structures de donnes et algorithmes
travail et, la fin, la diminuation du temps d'excution est
insignifiante. Une seule possibilit reste: l'laboration d'un
nouveau algorithme optimal. Pour atteindre ce but on doit
connaitre bien les structures de donnes et les techniques de
programation qui correspondent parfaitement l'application en
cause.
Cet ouvrage se propose de prsenter les principaux
structures de donnes existentes actuellement et d'aborder les
mthodes de concevoir un algorithme. On a choisi pour cela le
language C usuel. On a accentu l'aspect didactique des
applications, surtout dans les problmes d'implmentation. Pour
chaque structure de donnes et pour chaque mthode de
programmation il-y-a une application implante qui peut servir
comme modle pour tous les exercices proposs.
Ce livre s'adresse spcialement aux tudiants de
l'UNIVERSIT POLITECHNIQUE BUCAREST, section
GENIE LECTRIQUE ET ORDINATEURS, qui ont dans leur
programme annalitique la discipline Structures de donnes et
algorithmes. Les applications prsentes et les exercices
proposs peuvent tre drouls dans les heures de laboratoire de
ces tudiants.
4
Structures de donnes et algorithmes
1. STRUCTURES DE DONNES
Un algorithme signifie une suite de raisonnements ou
d'oprations qui fournit la solution des certains problmes. Il
reoit des donnes d'entre, les traite et obtient des donnes de
sortie. Dans un certain cas les donnes d'entre, les donnes
intrmediaires (celles cres pendant le traitement), et les
donnes de sortie sont structures dans un certain mode qui
correspond l'entre, aux ncssits du traitement ou celles de
l'utilisation ultrieure.
En gnral, les langages de programmation offrent aux
programmeurs la possibilit d'organiser les donnes en certains
modles connus, dnomms types de donnes.
Un type de donnes signifie:
-un ensemble de valeurs,
-une rgle de codification pour ces valeurs,
-un ensemble d'oprations dfinies sur l'ensemble de
donnes.
Les types de donnes peuvent tre simples ou structurs.
Les types simples dcrivent des donnes qui ne sont pas
des produits cartsiens des autres ensembles. Ex.:int, float, chart.
Les types structurs dcrivent des donnes qui
appartiennent aux ensembles results comme produits cartsiens
des autres ensembles. Ex.: struct, rationel {int a b;}
Une structure de donnes est un ensemble de donnes
caractris par les relations qui existent entr'elles et par les
oprations qu' on peut effctuer avec ces donnes.
5
Structures de donnes et algorithmes
La plupart des structures de donnes utilisent comme
lment caracteristique le noeud. Un noeud est une variable d'un
certain type. En gnral, ce type est structur. Le terme noeud
peut tre remplac par article, enregistrement ou entit. Une
structure peut avoir un nombre variable de noeuds.
On doit faire quelques obsrvations:
- le type de la variable qui forme le noeud ne caractrise
pas la structure de donnes;
- la structure de donnes est un concept abstrait qui ne
prcise pas le lieu o la structure sera mmorise ni les
dtails d'implmentation qui dpendent du programme
utilis.
Lensemble de donnes associ une structure peut tre
form dun type ou de plusieurs types dentits. Les composantes
de la structure peuvent tre individualises et identifies par nom
ou par la position occupe dans la structure.
Si la localisation dune composante est faite par le
parcours de toutes les composantes qui se trouvent avant elle,
dans lordre spcifie, on dit que la structure a un accs
squentiel.
Si une composante peut tre slecte sans tenir compte
des autres composantes, alors on dit que la structure a un accs
direct.
Sur une structure de donnes on peut effectuer beaucoup
doprations qui se rfrent aux valeurs et/ou la structure. Les
plus utilises sont:
-La cration de la structure (la mmorisation des donnes
sur le suport de mmoire).
-La consultation (laccs aux composantes pour le
traitement des valeurs)
-Lactualisation (le changement de ltat de la structure
par adjonction, effacement, modification des valeurs des
lments etc.)
-Le tri des elments.
6
Structures de donnes et algorithmes
-La division dune structure en deux ou plusieurs
structures.
-La fusion de deux ou plusieurs structures.
Bien dautres oprations existent encore.
Les oprations sur une structure de donnes et lefficience
de leurs ralisations dpendent des relations dentre les donnes
matrialises sur le support de mmoire.
On peut classifier les structures de donnes daprs des
divers critres:
a)-Daprs le type des composantes, les structures
peuvent tre:
-structures homognes, dans lesquelles les composantes
sont de mme type;
-structures hterognes, dans lesquelles les composantes
apartiennent aux diffrents types.
Si une structure peut tre dcompose en structures
homognes, alors la structure est rcursive.
b)-Daprs la possibilit de modifier les valeurs et/ou de la
structure, il y a:
- des structures statiques , qui pendant leur entire
existance ont le mme nombre de composantes dans la
mme ordre;
- des structures dynamiques , qui permettent la
modification des valeurs et/ou des structures par
lapplication des oprateurs.
c)-Daprs le niveau de structuration des donnes, nous
avons:
- des structures logiques , qui se rfrent au mode
dordoner les donnes ;
7
Structures de donnes et algorithmes
- des structures physiques , qui se rfrent au mode
dimplmentation, de reprsentation effective sur des
supports informationels.
Dans lorganisation des donnes, il faut dfinir aussi la
structure logique que la structure physique.
Les principaux types de structures logiques sont :
- la structure ponctuelle ;
- la structure linaire ;
- la structure arborescente ;
- la structure en rseau ;
- la structure relationelle .
a)-La structure ponctuelle est reprsente par une entit
isole.
b)-La structure linaire. Si entre les lments dune
collection de donnes il y a une relation dordre totale, la
structure est linaire. Ce type de structure a les suivante
proprits :
-Le cardinal de lensemble des lments initiaux (maximales) est
gal 1.
-Le cardinal de lensemble des lments terminaux (minimals) est
gal 1.
-Tout lment non-terminal a un successeur immdiat unique.
-Le premier lment na pas de prdcesseurs.
-Le dernier lment na pas de successeurs.
-Sil y a un couple en relation (u,p) form entre le dernier lment u
et le premier lment p , la structure linaire est circulaire.
-Les relations tablies entre les nuds sont de type 1 1.
Les lments dune structure linaire peuvent tre elles mmes
structurs en rseau ou en arborescence.
8
Structures de donnes et algorithmes
c)La structure arborescente (hirarchique ou
descendante) est une structure dans laquelle les lments sont
dans une relation dordre. Ce type de structure a les suivantes
proprits :
-Il y a un lment unique, la racine de larbre.
-Tout nud differant de la racine a un prdcesseur imdiat.
-Tout nud non-terminal a un nombre fini de succeseurs.
-Les relations tablies entre les nuds sont de type 1 m.
9
Structures de donnes et algorithmes
d)La structure en rseau. Si entre les lments dune
collection de donnes existe une relation de pre-ordre, on dit
quil sagit d une structure en rseau. Ce type de structure a les
suivantes proprits :
-Une rseau est un graphe dans lequel entre les nuds existent des
liaisons bidirectionnelles.
-Un nud a plusieurs prdcesseurs et lui mme peut tre son propre
prdcesseur. Ainsi apparaissent des cycles. Un cycle est un chemin
dans lequel le nud initial est aussi noeud final.
-Le cardinal de lensemble de nuds initiaux est plus grand ou gal
1.
-Le cardinal de lensemble de nuds finals est plus grand ou gal
1.
10
Structures de donnes et algorithmes
e)La structure relationnelle est forme de plusieurs tables
(tableaux, relations) de donnes lmentaires, sans une
liaison apparente entrelles, comme dans lexemple
suivant :
PERSONNES
MARQUE NOM PRENOM AGE SEXE PROFESSION
Plusieurs structures de donnes se sont imposes, parce
que beaucoup d'algorithmes les utilisent. Nous allons prsenter
les plus importantes.
1.1. LISTES LINAIRES
Une liste linaire est une suite de noeuds, x
1
, x
2
, x
3
.x
n
situs dans une relation d'ordre.
Les plus utilises oprations sur une liste sont:
- l'accs chaque noeud de la liste pour lire ou modifier
l'information contenue;
- l'adjonction d'un noeud dans la liste; on peut faire
l'adjonction dans une position fixe, avant ou aprs un
noeud d'une valeur connue;
- l'effacement d'un noeud de la liste qui peut tre realis
dans les mmes conditions que l'adjonction;
- le listage des noeuds de la liste.
On connait deux mthodes d'allocation d'une liste linaire:
- l'allocation squentielle et
- l'allocation chaine.
11
Structures de donnes et algorithmes
1.1.1.Listes linairs avec allocation sequentielle
Dans ce type d'allocation les noeuds occupent des
positions successives dans la mmoire. C'est le cas typique des
vecteurs. On peut considerer donc une liste avec n noeuds
comme un vecteur n composantes, v[n]. Toutes les
oprations sur la liste sont, en effet, des oprations sur des
vecteurs.
Par exemple, voila un programme qui travaille avec les
principaux oprations sur les vecteurs.
PROGRAMME LISTE SQUENTIELLE
#include<stdio.h>
#include<conio.h>
typedef int vecteur[100];
void lirevect(int n,vecteur v)
{int i;
for(i=1;i<=n;i++)
{printf(v[%d]=i);scanf(%d,&v[i]);}}
effacernoeud(int n, vecteur v, int k)
{int i ;
for(i=k ;i<=n-1;i++)
v[i]=v[i+1];}
void ecrirevect(int n,vecteur v)
{int i;
for(i=1;i<=n-1;i++)
printf(v[%d]=%d\n,i,v[i]);}
adjoindrenoeud(int n,vecteur v,int k,int n1)
{int i ;
for(i=n ;i>k ;i--)
v[i+1]=v[i];
v[k]=n1;}
main()
{int n,n1,k;
vecteur v;
printf(n=);scanf(%d,&n);
printf(n1=);scanf(%d,&n1);
12
info adr
1 2
info adr
2 3
info adr
3 4
info
n 0
Structures de donnes et algorithmes
printf(k=);scanf(%d,&k);
lirevect(n,v);
adjoindrenoeud(n,v,k,n1);
ecrirevect(n+1,v);
effacernoeud(n,v,k);
ecrirevect(n,v);}
Ce programme est compos de quatre fonctions :
-lirevect(int n,vecteur v)- la fonction de lecture des
valeurs des composantes pour chaque nud ;
-ecrirevect(int n,vecteur v) la fonction de listage des
valeurs des composantes pour chaque nud ;
-effacernoeud(int n, vecteur v, int k) la fonction
qui efface le nud situ sur la position k ;
-adjoindrenoeud(int n, vecteur v, int k, int n1)
la fonction qui adjoint un nouveau nud sur la position k, un
nud avec la valeur n1.
Nous allons expliquer comment sont formes les
fonctions effacernoeud et adjoidrenoeud.
La fonction effacernud(int n, vecteur v, int
k) efface le nud situ sur la position k. Pour efacer ce nud on
procde de la manire suivante : on dplace de droite gauche,
avec une position, toutes le composantes du vecteur, de la
composante v[k] jusqu' la composante v[n].
La fonction adjoindrenoeud(int n,vecteur v, int
k, int n1) joue le rle de mettre dans la position k une
nouvelle composante de valeur n1. On ralise cette chose par le
mouvement de gauche droite des composantes des vecteurs, en
commenant avec la dernire position jusqu' la position k. Dans
la position rest libre on met la valeur n1.
Observons que, dans le listes squentielles, l'adjonction et
l'effacement d'un nud ncsitent beaucoup de temps, parce-que
on doit dplacer toutes les composantes de la liste avec une
position droite o gauche. Pour une valeur n suffisament
grande, ces mouvements exigent une grande dure. C'est le
13
info adr
1 2
info adr
2 3
info adr
3 4
info
n 0
Structures de donnes et algorithmes
principal dsavantage des listes squentielles. Pour viter ce
dfaut, on a introduit les listes chaines.
1.1.2.Listes linaires avec allocation chaine
Dans une liste chaine chaque nud a deux composantes:
- une composante qui contient l'information utile au
nud ;
- une composante qui contient l'adresse du nud et le
pointeur aux noeuds prcedant ou suivant, d'aprs le
type de la liste.
En fonction de ces adresses, on peut classifier les listes :
- listes linaires simplement chaines ;
- listes linaires doublement chaines ;
- listes circulaires.
1.1.2.1. Listes linaires simplement chaines
Une liste simplement chain peut tre reprsente par le
schma :
ADR1 ADR 2 ADR 3 ADR n
o:
- les champs info i sont celles qui contiennent les informations
d'un noeud;
- les champs adr i contiennent les adresses d'un noeud et celles
du suivant noeud;
On observe que:
- l'accs un certain noeud est possible seulement en passant par
tous les noeuds prcedents; c'est un dsavantage de la liste;
14
info adr
1 2
info adr
2 3
info adr
3 4
info
n 0
Structures de donnes et algorithmes
- chaque noeud a une composante d'adresse seulement pour le
noeud suivant; c'est pour a que la liste ne peut pas tre
parcourue que de gauche droite.
Nous allons implmenter un programme qui contient des
fonctions qui ralisent les principaux oprations faites dans les
listes linaires.
PROGRAMME LISTES LINAIRES
SIMPLEMENT CHAINES
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef struct tnoeud
{int info;
struct tnoeud *adrsuiv;} noeud;
noeud v,fin;
void adjoindre(nud * & v, int val)
{nud * c ;
if( !v)
{v=new nud ; vinfo=val; vadrsuiv=0;
fin=v;}
else
{c=new noeud; finadrsuiv=c; cinfo=val;
cadrsuiv=0; fin=c;}}
void afficher(nud*v)
{int t=1 ;nud *c=v)
while (c)
{printf(le nud%d a la valeur %d\n ,t,
cinfo);c=cadrsuiv ;t++}}
void insererapres(nud*v,int val,int val1)
{nud*c,*d ;
c=v ;
while(cinfo!=val)c=cadrsuiv;
d=new nud;
dinfo=val1;dadrsuiv=cadrsuiv;cadrsuiv=d ;
if(dadrsuiv) fin=d ;}
void insereravant(nud*&v,intval,int val1)
{nud*c,*d ;
15
val adr
1 suiv
val adr
2 suiv
val adr
3 suiv
val
n 0
Structures de donnes et algorithmes
if(vinfo= =val)
{d=new noeud;dinfo=val1;dadrsuiv=v;v=d}
else
{c=v;
while(cadrsuivinfo!=val) c=cadrsuiv;
d=newnoeud;
dinfo=val1;
dadrsuiv=cadrsuiv;cadrsuiv=d;}}
void effacer(noeud*&v,int val)
{noeud*c,*man;
if(vinfo= =val)
{man=v;v=vadrsuiv;}
else
{c=v;
while(cadrsuivinfo!=val) c=cadrsuiv;
man=cadrsuiv;cadrsuiv=manadrsuiv;
if(man= =fin) fin=c;}
delete man ;}
main( )
{int i,n,j,m,k,h,p;
clrscr();
printf(n=);scanf(%d,n):
scanf(%d,&n) ;
for(i=1;i<=n ;i++)
{printf(la valeur du noeud %d est ,i) ;
scanf(%d ,&j);adjoindre(v,j);}
afficher(v) ;
printf(effacer le nud avec la valeur);
scanf(%d,&i);effacement (v,i);
aficher (v);
printf(inserez apres le noeud choisi un
nouveau nud avec une nouvelle valeur);
scanf(%d %d,&m,&k) ;inserer apres(v,m,n) ;
afficher(v);
printf(inserer en avant du noeud choisi un
nouveau noeud);
scanf(%d %d,&m,&k);
inserer avant(v,m,n) ;
afficher(v) ;}
16
val adr
1 suiv
val adr
2 suiv
val adr
3 suiv
val
n 0
val
val 0
val 0
Structures de donnes et algorithmes
Ce programme contient la cration d'une liste simplement
chaine avec n nuds. On a ralis des fonctions qui peuvent
adjoindre un nouveau nud la fin de la liste (adjoindre),
afficher les informations de tous les nuds de la
liste(afficher), situer un nouveau nud avant un nud d'une
valeur donne (insereravant) et inserer un nouveau nud
aprs un nud d'une valeur donne (insererapres). De plus,
on a cr une fonction qui efface un nud d'une certaine valeur
(effacer).
Pour implmenter cette liste, nous avons choisi une
variante non-rcursive parce qu'elle est plus facile et plus simple
comprendre. Dans cette implmentation le premier nud de la
liste 'est v et le dernier 'est fin. Les nuds de traitement sont
nots c et d.Une structure dnomme tnoeud a deux
composantes : une composante entire dnomme info et une
composante de type adresse qui pointe vers l'adresse suivante
(adrsuiv).
Telle liste peut tre reprsente par le schma :
v fin


le premier le dernier
nud noeud
Le dernier nud a adrsuiv de valeur 0.
Voyons maintenant le rle et l'implmentation de chaque
fonction.
-La fonction adjoindre(nud*&v.int val) joue le rle
d'adjoindre un nud aprs le dernier nud de la liste. Le
nouveau nud aura la valeur val .
Les paramtres de cette fonction sont : le paramtre de
rfrence v et le paramtre valeur val. Le premier est de type
pointer, le second de type entier. On a utilis un paramtre
de rfrence pour la situation dans laquelle la liste est vide et le
17
val adr
1 suiv
val adr
2 suiv
val adr
3 suiv
val
n 0
val
val 0
val 0
val
val 0
val
Structures de donnes et algorithmes
nud v est introduit pour la premire fois et il doit tre retenu
aussi en dehors de la fonction. Dans la construction de la
fonction on distingue deux cas :
a) quand la liste est vide ;
b) quand la liste n'est pas vide.
a) La partie de la fonction qui rsout le premier cas, quand
la liste est vide, donc v=0, est :
{v=newnoeud ; vinfo=val; vadrsuiv=0; fin=0;}
v=newnoeud v
On forme un premier
et unique noeud de la
liste, v. Ce noeud est
dynamiquement cr,
en employant
l'instrument new.
vinfo=val v
On met dans la partie
d'information du
noeud la valeur val.
v=adrsuiv=o v
Ce noeud, le premier
mais en mme temps
le dernier de la liste,
n'aura pas une adresse
suivante.
fin=v fin
Il sera not, comme
dernier noeud dela
liste, fin.
b)Dans le second cas, la liste n'est pas vide, donc le
nouveau noeud sera ajout sur la dernire position de la liste.
-La partie de la fonction qui rsout ce problme est:
{c=newnoeud;finadrsuiv=c;cinfo=val;cadrsuiv=0;
fin=c;}
18
val
val 0
val 0
val
val 0
val
val val1
Structures de donnes et algorithmes
c=newnoeud
c
On cre
dynamiquement un
nouveau noeud c.
fin=adrsuiv=c
fin c
Le dernier noeud
fin ne sera plus
point vers 0 mais
vers le noeud c.
cinfo=val
c
On met dans la
partie
d'information du
noeud c la valeur
val.
cadrsuiv=0
c
Parce que ce
noeud est le
dernier de la liste,
il va pointer vers
zero .
fin=c
fin
Le noeud de travail
c sera dnomm
fin , parcequ'il est
le dernier de la
liste.
- La fonction afficher(noeud*v) est positione sur un
noeud et affiche la valeur du noeud qui est dans le champ info.
On balaye l'entire liste, du premier au dernier noeud. Le
paramtre v est de type valeur, parce que, dans cette
fonction, on ne fait pas des modifications d'un noeud de la liste.
-La fonction insererapres(noeud*v,int val, int
val1) joue le rle d'insrer un noeud de valeur val1 aprs un
noeud de valeur val . Si dans la liste existent plusieurs noeuds
de valeur val, le nouveau noeud s'insre aprs le premier noeud
de valeur val.
19
val
val 0
val
val val1
val
val
val
Structures de donnes et algorithmes
Cette fonction commence par chercher le noeud de valeur
val, en partant du premier noeud.
c=v; while(cinfo!=val) c=cadrsuiv;
Puis, elle commence insrer aprs ce nud, par les suivants
pas :
d=newnoeud
d
On cre
dynamiquement
un nouveau
nud d.
dinfo=val1
dadrsuiv=
cadrsuiv
d
c d c+1
On met dans la
partie
d'information du
noeud la valeur
val1.
cadrsuiv=d

c d

L'adresse
suivante du
noeud d insr
est l'adresse
suivante du
noeud c.
if(!dadrsuiv
fin=d
d
L'adresse
suivante du
noeud c est le
noeud d ; au cas
o d est le
dernier noeud de
la liste, il est
dclar fin .
Remarquez que le paramtre v est valeur, parce que on
ne peut jamais modifier l'insertion aprs le premier noeud.
20
val1
val val1
val val1
val1 0
val
val
val



Structures de donnes et algorithmes
-La fonction insereravant(noeud*&v,int val,int
val1) joue le rle d'insrer un nouveau noeud de valeur val 1
avant un noeud de valeur val. Elle ressemble la fonction
dcrite antrieurement, insererapres. La seule majeure
diffrence est que, dans le cas de la fonction insereravant, on
peut faire une insertion mme avant le premier noeud et ce
nouveau noeud devient le premier noeud de la liste. C'est pour a
que le paramtre v est un paramtre rfrence.
-La fonction efacer(noeud*&v,int val), bienentendu,
efface un noeud de valeur val de la liste. cette fonction aussi
on distingue dex cas:
a) quand on efface le premier noeud de la liste;
b) quand on efface un autre noeud de la liste.
a)Pour effacer le premier noeud, on passe par les suivantes
tapes:
man=v
man
On positionne sur
le premier noeud
de la liste .
v=vadrsuiv
v
On copie le noeud
v dans le noeud
man qui a le rle
de manoevrer. Le
second noeud
devient le premier
noeud v .
b)Si le noeud effacer diffre du premier noeud, on fait
les suivants pas:
while(cadrsuivinfo!=val) c=cadrsuiv;
c c
Position ici
On positionne sur
un noeud anterieur
celui qui a la
valeur val et qui
doit tre effac.
21
0
adr2
adr1
Info2
adr3
Info3
adr4
adr(n-2)
info(n-1)
adr n
adr(n-1)
info n
adr(n-1)
adr2
2
val
val
val



Structures de donnes et algorithmes
man=
cadrsuiv
man



Le nom du noeud
effacer est man.
cadrsuiv=
manadrsui
v

c man
On met l'adresse
suivante du noeud
anterieur celui
qu'on doit effacer,
gale avec celle du
noeud posterieur
au noeud effacer,
en liminant ainsi,
pratiquemant, le
noeud effacer.
if(man=fin)
fin=c
fin man


Si le noeud
effacer tait le
dernier,c, il
deviendrait fin .
1.1.2.2 Listes circulaires
Dans une liste circulaire, l'adresse du dernier noeud n'est
plus 0 mais elle pointe vers le premier noeud de la liste:

adr 1 adr 2 adr 3 adr n

Une liste linaire simplement chaine est caractrise par
le premier nud, mais une liste circulaire peut tre caractrise
par n'importe quel nud de la liste.
22
I info1 adr2 I info2 adr3 I info3 adr4 I info n adr1
0
adr2
adr1
Info2
adr3
Info3
adr4
adr(n-2)
info(n-1)
adr n
adr(n-1)
info n
adr(n-1)
adr2
2
val

val

Structures de donnes et algorithmes
On peut conserver pour les listes circulaires la mme
implmentation que celle des listes simplement chaines, avec les
suivants modifications :
- on renonce au nom de nud final, fin ;
- l'adresse du dernier nud va pointer vers le premier
nud.
Toutes les autres fonctions restent inchanges.
1.1.2.3 Listes linaires doublement chaines
Une liste linaire doublement chaine est une structure de
donnes dans laquelle chaque nud a la suivante structure :
- un champ de donnes ;
- une adresse qui pointe vers le nud prcedent ;
- une adresse qui pointe vers le nud suivant.

adr1 adr2 adr3 adr(n-1) adr n
L'avantage de la liste avec allocation doublement chaine
est le fait qu'elle peut tre parcourue en double sens.
Les oprations qu'on fait avec une telle liste sont :
- cration ;
- adjonction droite
- adjonction gauche ;
- adjonction dans l'intrieur de la liste ;
- effacement dans l'intrieur de la liste ;
- effacement la gauche de la liste;
- effacement la droite de la liste ;
- listage de gauche droite ;
- listage de droite gauche.
23
0
Iinfo1
adr2
adr1
Info2
adr3
Info3
adr4
adr(n-2)
info(n-1)
adr n
adr(n-1)
info n
adr(n-1)
adr2
2
val
Structures de donnes et algorithmes
De mme qu'aux listes simplement chaines, nous allons
crire une application des listes doublement chaines.
PROGRAMME LISTES DOUBLEMENT CHAINES
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef struct tnoeud
{int info;
struct tnoeud*adrdr,*adrg;} noeud;
noeud*g,*dr,*c;
void creer(noeud*&g,noeud*&dr,int val)
{g=new noeud; ginfo=val;
gadrg=gadrdr=0;
dr=g;}
void affichergd(noeud*&g)
{noeud*d=g;
while(d)
{printf(%d\n,dinfo);d=dadrdr;}}
void include(int val, int val1, noeud*g)
{noeud*d=g,*e;
while(dinfo!=val) d=dadrdr;
e=new noeud; einfo=val1; eadrg=d;
dadrdradrg=e; eadrdr=dadrdr;
dadrdr=e;}
void effacer (int val, noeud*g)
{noeud*d=g;
while(dinfo!=val) d=dadrdr;
dadrgadrdr=dadrdr;
dadrdradrg=dadrd;
delete d;}
main( )
{int n,val ;
printf(creation dune liste avec un seul
nud ) ;
crer(g,dr,1) ;
printf(nombre des noeuds);
scanf(%d,&val) ;
for(i=1 ;i<=n ;i++)
24
0
0
val
0
0
val
0

val

g

val
0
val
Structures de donnes et algorithmes
{printf(la valeur dinformation);
scanf(%d,&n);
adjoindre(dr,val) ;
printf(lister de gauche droite);
afficherd(g);
printf(inclusion a droite d'un noeud)
printf(apres le noeud ou on
fait l'inclusion);
scanf(%d,&val);
print f(la valeur du nouveau noeud);
scanf(%d,&val1);
include(val,val1,g);}
printf(lister de gauche a droite);
afficher gd(g);
printf(effacer le noeud avec la valeur);
scanf(%d,&val); effacer(val,g);
printf(lister de gauche a droite)
affichergd(g);}
Essayons d'expliquer chaque fonction de ce programme.
-La fonction creer(noeud*&g,noeud*&dr,int val)
joue le rle de crer un seul noeud. Elle ralise les suivantes
oprations: cre dynamiquement un nouveau noeud, crit
l'information dans le noeud, crit les adresses droite et gauche
avec 0, les variables de rfrence g et dr,val et reoit l'adresse
de ce premier enregistrement.
Les tapes sont:
g=newnoeud
g
On fait
dynamiquement
l'allocation d'un
noeud.
ginfo=val
g




On crit
l'information
val dans le
noeud.
25
0
0
val
0
0
val
0

val

g

val
0



d
g

val
0
g

val
0
val
Structures de donnes et algorithmes
gadrg=
gadrdr=0
g

L'adresse gauche
et l'adresse
droite sont
compltes avec
0.
dr=g
dr
On note l'adresse
du nud avec
dr.
-La fonction adjoindre dr (nud*&dr, int val)
joue le rle d'ajouter un nouveau nud la fin de la liste, 'est--
dire droite. Elle ralise les suivantes oprations : cre
dynamiquement un nouveau nud, crit l'nformation dans le
nud, complte l'adresse gauche avec l'adresse du plus la
droite enregistrement (retenu dans le nud g), modifie le champ
d'adresse droite avec l'adresse du nouveau enregistrement et
prend la valeur du nouvel enregistrement.
nud*d=
newnoeud
d
On cre
dynamiquement
un nouveau
nud d.
dinfo=val
d
On crit
l'information
val dans le
nud.
dadrg=g
dadrdr=0
d
On crit les
adresses du
nouveau nud,
gauche (g) et
droite.
26
0
0
val
0
0
val
0

val

g

val
0



d
g

val
0
g

val
0
val
val1


val


val1
d

val


val1
d

dadr
dr



val


val1
d

val1
e

Structures de donnes et algorithmes
dradrdr=d
dr d
L'adresse droite
du dernier noeud
avant
l'adjonction
(dr) devient le
nouveau nud
d.
dr=d
dr
On crit
l'adresse du
dernier nud,
dr,
conformment
aux notations
adoptes.
- La fonction affichergd(nud*&g) joue le rle de
lister les valeurs des nuds de la liste, de gauche droite. On
ralise cette chose-l dans le suivant mode : on part du premier
nud gauche vers la fin de la liste, droite, on imprime
l'information et on passe au suivant nud.
- La fonction include(int val, int val1, nud*g)
ajoute un nouveau nud avec l'information val1 aprs le nud
avec l'information val. ce but on excute les suivantes
oprations: on parcourt la liste de gauche droite et on cherche le
nud avec l'information val , on cre un nouveau nud
l'information val1 et on complte les adresses du nouveau nud
gauche et droite.
nud*d=g
d=g
On note le premier
noeud de la liste, g,
avec d; d est le
nud de travail de
la fonction.
27



d
g

val
0
g

val
0
val
val



dddadrd
r
val



dadrdr

val1


val


val1
d

val


val1
d

dadr
dr



e



val1
d

dadr
dr

e


val




val


val1
d

val1
e

Structures de donnes et algorithmes
while(din
fo!=val)
d=dadrdr
d
On parcourt la liste
de gauche droite
jusqu'on rencontre
le nud avec
l'information val et
on positionne sur
ce nud
e=newnoeud ;
einfo
val1
e
On cre
dynamiquement un
nouveau nud e
et on met dans ce
nouveau nud
l'information val1
eadrg=d
d e
L'adresse gauche
du nud inser e
est d
dadrdr
adrg=e
d e


adrdr

Le nud d'aprs e
a l'adresse
dadrdr. Dans ce
nud on met
l'adresse de
gauche, le nud e
eadrdr=
dadrdr
d e
L'adresse droite
du nud e est, en
effet, dadrdr

28


val


val



dddadrd
r
val



dadrdr

val1


val


val1
d

val


val1
d

dadr
dr



e



val1
d

dadr
dr

e


val




val


val1
d

val1
e

Structures de donnes et algorithmes
dadrdr=e
d e
L'adresse droite du
nud d est, en fait,
le nud e
-La fonction effacer(int val, nud*g) efface le nud
avec l'information val par les suivantes oprations : on parcourt
la liste de gauche droite, on positionne sur le nud avec
l'information val et on cre les nouvelle adresses pour les nuds
droite et gauche du nud effac.
nud*d=g
while(d
info!=val)
d=dadrdr
d
On parcourt la
liste de gauche
droite jusqu'on
arrive au nud
avec
l'information val.
On positionne sur
ce nud.
dadrg
adrdr=
dadrdr
d






L'adresse
droite du nud
qui se trouve la
gauche du d est
dadrdr.
dadrdr
adrg=
dadrg
d
L'adresse gauche
du nud qui se
trouve la droite
du d est
dadrg.

29
val



dddadrd
r
val



dadrdr

dadrdr
e



val1
d

dadr
dr

e


dadrdr
val


l

Structures de donnes et algorithmes
Il faut crer encore les suivantes fonctions spcifiques aux
listes doublement chaines:
-adjoindre (nud*&g,val) qui ajoutera, la gauche du
premier nud de la liste, un autre nud d'information val ;
-afficher dg(nud*&dr)qui va lister les informations
des nuds de la liste de droite gauche.
L'implmentation de ces deux fonctions resemble celle
prsente pour les autres ci-dessus.

1.1.3 Problmes avec des listes
1.crivez une fonction, pour des listes simplement
chaines, qui doit insrer un nouveau nud aprs le n-ime de la
liste.
Indications : Cette fois-ci on demande d'insrer un nouveau nud,
pas aprs un nud d'une valeur donne, mais aprs le n-ime nud, n
etant donn. Pour rsoudre ce problme, on doit faire les suivantes
oprations:
-on parcourt la liste de droite gauche, en comptant avec un comptoir
n nuds et on positionne sur le nud n ;
-puis, comme aux fonctions dcrites antrieurement, on cre
dynamiquement un nouveau nud et on refait aussi les liaisons
d'adresse.
2.Crez, pour les listes simplement chaines, une fonction
qui doit effacer le n-ime nud.
Indications : On positionne sur le n-ime nud et on efface le nud
avec la fonction effacement, dcrite antrieuement.
3.Crez une fonction pour diviser une liste simplement
chaine en deux listes disjointes. La liste initiale a n nuds
nombres naturels. La premire liste aura des nombres pairs et la
seconde nombres impairs.
30
Structures de donnes et algorithmes
Indications : On cre deux listes d'aprs les modles antrieures.
Chaque nud nouveau dans une liste aura l'infformation obtenue de la
liste initiale : si le nud a l'information nombre pair , on la
transfre vers un nud de la premire liste si le nud a l'information
nombre impair , on la transfre vers un nud de la seconde liste.
4.crivez une fonction qui ordonne de manire croissante
les nuds d'une liste simplement chaine, ayant l'information
dans n nuds nombres naturels.
Indications: On applique la plus simple mthode d'ordonner (la
mthode des boulles). On n'effectura pas des modifications dans les
composantes d'adresse des nuds. On fera des permutations de deux
nuds , sur les champs d'information.
5.Soit une liste linaire simplement chaine dans laquelle
le champ d'information de chaque nud esr de type struct . Ce
nud aura les suivantes composantes :
-nom tudiant char[20]
-prnom tudiant char[20]
-note examen 1 int v[1]
-note examen 2 int v[2]
-note examen 3 int v[3]
On demande les suivantes :
-la moyenne arithmtique des notes d'examens pour chaque
tudiant;
-la liste des tudiants qui ont pass tous les examens;
-la liste des tudiants en ordre alphabtique du nom.
Indications : L' information des nuds sera faite de type struct .
-Pour la premire question, on va calculer l'information
(v(1)+v(2)+v(3))/3, information de type float qui sera liste pour
chaque nud individuellement.
-Pour la seconde question, on va calculer pour chaque nud
l'expression
v(1)>=5&& v(2)>5&&v(3)>=5 et si elle est vraie, on listera les noms
et les prnoms qui se trouvent dans le nud.
31
27
27
27
4
5
5
2
27
27
27
27
272
27
27
8
4
5
55
2
10
10
27
27
4
5
5
2
10
10
10
41

441

27
4

5
2
27
27
4
44
5
5
27
27
4
4

27
4

5
2
10

41

27
4 5 8

10

41
100
1100
100
001
00
27
27
4
5
5
2
10
10
10
41

441
27
27
4
5
5
2
10
10
10
41

441
27
27
27
4
5
5
2
27
27
272
27
27
8
4
5
55
2
10
10
27
27
272
27
27
8
4
5
55
2
10
10
27
27
4
5
5
2
10
10
10
7
441
Structures de donnes et algorithmes
-Pour la troisime question on ordonne en ascendant les nom
tudiant .
6.Pour une liste circulaire, dans laquelle on connat un
nud, on demande l'affichage du nombre des nuds.
Indications : Une liste circulaire est caractrise seulement par un
nud. On fait un compteur qui compte les nuds en commenant
avec le nud donn jusqu'on arrive de nouveau au nud donn.
7.Pour une liste circulaire dans laquelle on connat un
nud, changez le sens des flches.
Indications : On refait les liaisons d'adresse pour chaque nud .
L'adresse suivante ne sera plus le nud de droite mais celui de
gauche.
8.Ordonnez une liste linaire doublement chaine, en
utilisant la mthode SHAKER.
Indications : La mthode SHAKER consiste dans le balayage de la
liste dans les deux sens. chaque parcours, on permute deux
lments voisines. La liste doublement chaine se prte fort bien la
mthode SHAKER, parce qu'on peut parcourire la liste dans les dux
sens (la mthode sera tudie dans le chpitre algorithmes de tri )

1.2. PILES
1.2.1. Dfinitions, proprits, programmes
La pile est une structure de donnes, ressemblante une
liste, qui fonctionne d'aprs le principe LIFO (Last Inpout First
Aut), le dernier entr, le premier sorti. Une pile est oprable
32
18 12 7 5
27
27
27
4
5
5
2
27
27
27
27
272
27
27
8
4
5
55
2
10
10
27
27
4
5
5
2
10
10
10
41

441

27
4

5
2
27
27
4
44
5
5
27
27
4
4

27
4

5
2
10

41

27
4 5 8

10

41
100
1100
100
001
00
27
27
4
5
5
2
10
10
10
41

441
27
27
4
5
5
2
10
10
10
41

441
27
27
27
4
5
5
2
27
27
272
27
27
8
4
5
55
2
10
10
27
27
272
27
27
8
4
5
55
2
10
10
27
27
4
5
5
2
10
10
10
7
441
Structures de donnes et algorithmes
seulement un but. L'autre but est inoprable. Dans une pile on
permet seulement deux oprations :
- l'adjonction d'un lment, opration nomme PUSH
- l'extraction d'un lment, opration nomme POP

Un exemple :
Soit la pile initiale avec quatre lments :

PUSH(10)

PUSH(41)
PUSH(100)
POP

POP
PUSH(7)
POP

POP.
POP.

POP


POP

Obsrvations:
D'habitude, pour l'exploitation du fonctionnement d'une
pile, existe un paramtre qui indique le pic de la pile, ou son
niveau ; gnralement ce paramtre concide avec le nombre
d'lments de la pile (pour cent lments, l'indicateur este 100).
Une opration PUSH incrmente l'indicateur de la pile
avec une unit et une opration POP le dcrmente avec une
unit.
L'accs un lment de la pile est ralis en effaant tous
les lments qui se trouvent avant lui, par des instructions POP.
Par exemple, soit la pile :
33
18 12 7 5
27
27
27
4
5
5
2
27
27
27
27
272
27
27
8
4
5
55
2
10
10
27
27
4
5
5
2
10
10
10
41

441

27
4

5
2
27
27
4
44
5
5
27
27
4
4

27
4

5
2
10

41

27
4 5 8

10

41
100
1100
100
001
00
27
27
4
5
5
2
10
10
10
41

441
27
27
4
5
5
2
10
10
10
41

441
27
27
27
4
5
5
2
27
27
272
27
27
8
4
5
55
2
10
10
27
27
272
27
27
8
4
5
55
2
10
10
27
27
4
5
5
2
10
10
10
7
441
Structures de donnes et algorithmes
p(1) p(2) p(3) p(4) p(5) p(6)
Si nous voulons un accs l'lment p(5), il faut excuter
quatre oprations POP. la cinquime opration nous avons
accs l'lment p(5) . Un accs l'lment n signifie la perte
des premiers n-1 nuds.
En ce qui concerne l'implmentation d'une pile, l'allocation
squentielle ne prsente pas des grands inconvnients comme
dans le cas des listes, parce qu'on ne fait pas des oprations
d'insrtion ou d'effacement dans l'interieur de la pile. Le seul
dsavantage este le petit nombre de nuds qui peuvent tre
mmoriss un moment donn. Ce nombre dpend du dgr
d'occupation du segment de donnes.
Dans le prsent ouvrage, pour conserver un caractre
unitaire, nous avons implment les piles de la mme manire
que les listes dynamiquement enchaines.
Le suivant programme traite la structure de donnes de
type pile. On fait l'adjonction d'un lment avec la fonction
PUSH et l'limination d'un lment avec la fonction POP.
PROGRAMME PILES
#include<stdio.h>
#include<conio.h>
typedef struct tnoeud
{int info;
struct tnoeud*adrsuiv;}noeud;
noeud*v;int n;
void push(noeud*&v,int n)
{noeud*c;
if(!v)
{v=newnoeud; vinfo=n; vadrsuiv=0;}
else
{c=newnoeud; cadrsuiv=v; v=c}}
34
18 100 200 12 7 5
n v
n v
n
n 0
n
Structures de donnes et algorithmes
void pop(noeud*&v)
{noeud*c;
if(!v) printf(la pile est vide\n);
else
{c=v;printf(ellimine information %d\n,c-
>info);
v=vadrsuiv;delete c;}}
main( )
{int taste,t;
clrscr( );
do{
printf(presser 1 oter de la pile,
2 metre dans la pile,
3 afficher nud);
scanf(%d, taste);
switch(taste)
{case 1 : pop(v);break;
case2:printf(introduire la valeur du noeud)
scanf(%d,&n);ush(v,n);break;
case3:printf(le noeud a la valeur%d\n,vinfo)
printf(continuer 4,finir 0
scanf(%d,&t);}
while(t);}
Voyons maintenant comment sont construites les fonctions
PUSH.
La fonction push(noeud*&v,int n) joue le rle
d'ajouter un nouveau noeud au pic de la pile. Il y a deux
solutions:
a) quand la pile est vide
b) quand la pile n'est pas vide.
a) Dans ce premier cas, quand la pile est vide, (v=0), on
fait les suivantes oprations:
v=newnoeud
v
On cre
dynamiquement un
nouveau noeud.
35
n v
n v
n
n 0

n
Structures de donnes et algorithmes
vinfo=n
v
On met
l'nformation n
dans le nud.
vadrsuiv=0
v
L'adresse suivante
est 0 , etant en
mme temps le
dernier nud de la
pile.
b)Quand la pile n'est pas vide, on fait les suivantes
oprations :
c=newnoeud
c
On cre
dynamiquement le
nud de manoevre
c.
cinfo=n
c
On met
l'information n
dans le nud.
cadrsuiv=v
c
L'adresse suivante
est le nud v , le
premier de la pile .
v=c v
On nomme le
nud c comme
nud v, le premier
de la pile.
La fonction pop(nud*&v) joue le rle d'enlever un
lment du pic de la pile. Si la pile est vide, on ne peut pas
effectuer l'opration POP et, alors, on donne un msage
d'attention la pile est vide . Si la pile n'est pas vide, on lit
l'information du nud et puis on limine le premier nud et on
refait les liaisons.
36
25 42 13
10
101
010
100
18 19
25 42 13
10
101
00
18 19
25 42 13
10
101
00
18 19
25 42 13
10
101
00
18 19
25 42 13
10
100
19
25 42 13 19
42 13 19
42 13 19
500
505
00
500
500
500
500
500
500
500
500
100
0
100
0
2
500
500
500
500
500
500
500
500
500
500
500
500
500
2
2
2
2 5
n v
n v
n

n 0
n
Structures de donnes et algorithmes
1.2.2. Problmes avec des piles
1.On lit les nombres naturels du clavier. On demande
dintroduire dans la pile seulement les nombres ronds. Un
nombre rond est le nombre qui, crit en base 2 , a le nombre des
chiffres 0 gal celui des chiffres 1, en commenant du
premier chiffre significatif, 1.
Indications: On cre une fonction qui teste si un nombre est rond. Si
cela est vrai, la fonction va retourner 1, si non, elle va retourner 0.
Lalgorithme est simple. On divide le nombre par deux et puis les quotients,
de nouveau, par deux. On rpte lopration jusque le rsultat sera zero. Les
restes successifs seront mis dans un compteur pour 1 et dans un compteur
pour 0. Si, la fin, les deux compteurs sont gaux, le nombre est rond. Si le
nombre est rond, il sera introduit dans la pile par la fonction PUSH.
2.On demande de lire les lments dune pile et de les
introduire dans une autre pile en ordre de la lecture.
Indications: On va excuter des oprations POP sur la premire pile,
suivies de PUSH sur la deuxime pile. Certainement, la seconde pile
contiendra les nombres de la premire pile en ordre invers.
1. 3. QUEUES
1.2.2. Dfinitions, proprits, programmes
La queue est une structure de donnes, ressemblante
une liste, qui fonctionne d'aprs le principe FIFO (First In First
Out), c'est--dire le premier venu, le premier sorti . Ses deux
extrmits sont oprables. Par l'extrmit droite on introduit les
donnes dans la queue et par l'extrmit gauche on enlve les
donnes de la queue.
37
25 42 13
10
101
010
100
18 19
25 42 13
10
101
00
18 19
25 42 13
10
101
00
18 19
25 42 13
10
101
00
18 19
25 42 13
10
100
19
25 42 13 19
42 13 19
42 13 19
500
505
00
500
500
500
500
500
500
500
500
100
0
100
0
2
500
500
500
500
500
500
500
500
500
500
500
500
500
2
2
2
2 5
Structures de donnes et algorithmes
Par analogie avec les pile, on va dnommer la fonction qui
introduit un nud PUSH et une fonction qui enlve un nud
POP.
Un exemple :
Soit la queue initiale :

PUSH(500)
PUSH(100)
PUSH(2)
POP
POP
POP
PUSH(5)
En ce qui concerne l'implmentation de la queue,
l'allocation dynamique chaine est prfre. L'allocation
sequentielle n'est pas recommandable, parce que, dans cette
situation, apparat un phnomne de migration des donnes vers
les dernires composantes du vecteur ( celles avec un grand
indice).
PROGRAMME QUEUES

#include<stdio.h.>
#include<conio.h>
typedef struct tnoeud
{int info;
struct tnoeud *adrsuiv;}noeud;
noeud*v,*fin;int n;
void push (noeud*&v,noeud*&fin,int n)
{noeud*c;
38
25 42 13
10
101
010
100
18 19
25 42 13
10
101
00
18 19
25 42 13
10
101
00
18 19
25 42 13
10
101
00
18 19
25 42 13
10
100
19
25 42 13 19
42 13 19
42 13 19
500
505
00
500
500
500
500
100
000
000
011
000
500
500
500
500
100
0
100
0
2
500
500
500
500
500
500
500
500
500
500
500
500
500
100
001
100
0
100
001
100
0
100
001
100
0
100
001
100
0
2
2
2
2 5
c
Structures de donnes et algorithmes
if(!v)
{v=newnoeud;vinfo=n;vadrsuiv=0;fin=v;}
else
{c=newnoeud;finadrsuiv=c;cinfo=n;cadrsuiv=0;
fin=c}}
void pop(noeud*&v)
{noeud*c;
if(!v) printf(queue vide);
else
{printf(enleveinformation%d\n,vinfo) ;c=v ;
v=vadrsuiv ;delete c ;}
main( )
{int taste,t ;
clrscr( ) ;
do{
printf(presser 1 enlever de la queue,
2 metre dans la queue)
scanf(%d,& taste);
switch(taste)
{case 1 : pop(v);break;
case 2 : printf(introduire valeur noeud);

scanf(%d,&n);push(v,fin,n)
break;}
printf(continuer 4, finir 0);
scanf(%d,&t);}
while(t);}
Les fonctions PUSH et POP sont formes comme aux
piles.
La fonction push(noeud*&&v,nud*&fin,int n) introduit un
nouveau nud l'extremit droite de la queue, extrmit note
avec fin. Nous avons deux situations :
a) quand la queue este vide ;
b) quand la queue n'est pas vide.
a) Quand la queue est vide, on fait les suivantes oprations :
39
c
n
Structures de donnes et algorithmes
v=newnoeud
v
On cre
dynamiquement un
nouveau nud, v .
vinfo=n
v
On met
l'information n
dans le nud .
vadrsuiv=0
v
Parce qu'il est le
dernier nud de la
queue l'adresse
suivante sera 0 .
fin=v
fin
On va dnommer
ce nud fin, le
dernier de la
queue .
b) Quand la queue n'est pas vide :
c=newnoeud
c
On cre
dynamiquement un
nouveau nud c.
finadrsuiv=c
fin c
Le dernier noueud
de la queue va
pointer vers le
nouveau nud c.
cinfo=n
c
On introduit
l'information n
dans le nud c.
cadrsuiv=0
c
L'adresse suivante
est 0, parce qu'il est
le dernier nud de
la queue .
fin=c fin
On dnomme le
noueud c comme
noeud fin, le
dernier de la queue .
40
n

n 0
n 0

c
n
n 0
n 0
n
Structures de donnes et algorithmes
-La fonction pop(nud*&v). Si la queue est vide, on ne
peut pas effectuer cette fonction et on donne un msage
d'attention. Si la queue n'est pas vide, on fait les suivantes
oprations :
On lit l'information du premier nud v :
printf(enlever information %d\n, vinfo)
c=v
c=v
Le premier nud
est dnomm c.
v=vadrsuiv
c v
On dnomme le
suivant nud de
la queue , v , en
liaison avec le
noeud qui tait le
premier .
delete c
c
On efface
dynamiquement
le nud c.
1.3.2. Problmes avec des queues
1.On demande de crer une structure en queue circulaire,
ainsi que tout lment t de la queue soit introduit dans la
queue sur la premire position.
Indications : La fonction PUSH reste inchange. La fonction POP
sera modifie. La nouvelle fonction, que nous allons la dnommer
POPCIRCULAIRE, aura toujours la fonction de ter de la queue,
mais elle contiendra, de plus, la fonction PUSH pour lintroduction
dans la queue au bout d criture.
41

n

Structures de donnes et algorithmes
2.On lit les lments dune queue qui sont des caractres
(signes dont on se sert dans lcriture). On demande dintroduire
un caractre de la queue dans une pile, la condition quil ne
soit pas le mme caractre lu prcdemment dans la queue.
Indications : On lira avec POP un lment de la queue qui sera
mmoris dans une variable auxiliaire. Puis, une nouvelle POP lira
un autre caractre de la queue. Il sera compar avec celui de la
variable auxiliaire. Sils sont diffrents, le caractre sera introduit
dans la pile par une instruction PUSH . Ensuite, le nouvel caractre
lu sera mmoris dans la variable auxiliaire.
3.Calculez le plus grand commun diviseur des nombes
naturels dune queue.
Indications : On va crer une fonction qui calcule le plus grand
commun diviseur de deux nombres. On appliquera cette fonction
pour les deux premiers nombres de la queue, extraits par deux
instructions POP. Puis, cette fonction sera applique au plus grand
commun diviseur calcul et un nouveau nombre extrait par une
instruction POP. Le procd sera continu jusquon puisera tous les
nombre de la queue. la fin, la fonction indiquera le plus grand
commun diviseur des nombres de la queue.
Obs. La lecture dune queue (ou dune pile) est faite avec
linstruction POP. Quand la lecture est finie, la queue (ou la pile) est
vide.
42
Structures de donnes et algorithmes
1.4 GRAPHES
1.4.1. Graphes orients
1.4.1.1. Dfinitions
Un graphe G est la structure de donnes forme dun
couple G=(V,A) o V est un ensemble fini et A un sous-
ensemble dont chaque lment est une paire dlments ( non
ncessairement distincts) de A ; A

V*V. Les lments de


lensemble V sont dnoms sommets ou nuds de G. Les
lments de lensemble A sont appels artes ou arcs de G. Un
arc de la forme (v
i
, v
i
) sappelle boucle . Lordre de G est, par
dfinition, le nombre des sommets de G. Si entre deux sommets
existent plusieurs artes, on les appelle artes multiples.
Un graphe simple est un graphe qui ne possde ni boucle
ni artes multiples.
Le degr dun sommet est le nombre dartes dont il est
une extrmit.
Thorme : La somme des degrs des sommets dun
graphe est un nombre pair. La somme des degrs est le nombre
dextrmits des artes.
Deux sommets sont adjacents sils sont joints par au
moins une arte (arc).
Deux artes sont adjacentes si elles ont une extrmit
commune.
Une chane (chemin) est une suite (non vide) finie
dartes adjacentes.
Un cycle (circuit) est une chane dont les deux extrmits
sont confondues.
Un graphe est dit connexe si, quels que soient les
sommets i et j distincts, il existe un chane (chemin), joignant i
j.
43
Structures de donnes et algorithmes
Un graphe simple est dit planaire si on peut le reprsenter
dans un plan sans aucun croisement des artes ( hors de leurs
extrmits).
Tout polydre convexe peut tre reprsent par un graphe
planaire.
Dans les graphes orients les arcs sont des paires
ordonnes de nuds, (v
i
,v
j
) o v
i
est la base de larc et v
j
est le
sommet de larc. On dit que v
j
est adjacent au v
i
. Donc , dans les
graphes orients chaque arte a un sens. On prfre, pour les
graphes orients, le terme arc au lieu darte.
Les graphes non-orients sont forms de paires non-
ordons de sommets. Dans ce cas, une arte ralise une double
liaison entre les nuds.
Termes utiliss dans ces deux genres de graphes :
Graphes orients Graphes non orients
Arc Arte
Chemin Chane
Circuit Cycle
Forte connexit Connexit
Graphes orients :
44
Structures de donnes et algorithmes
Graphes non-orients :
Dhabitude, on figure dans un plan les lments de
lensemble V par des cercles ou des cars et les lments de
lensemble A par des lignes ou des flches. On ne doit pas
confondre un graphe avec sa reprsentation.
Un graphe orient est donn dans lexemple suivant :
1.4.1.2. Modes de reprsenter les graphes
Les plus souvent utiliss modes de reprsenter les graphes
sont:
a) la matrice dadjacences ;
b) les listes dadjacences.
Dans toutes les applications du chapitre Graphes on
lira le graphe, par une de ces deux mthodes, dun fichier texte
dans lequel, sur la premire ligne est le nombre de nuds et sur
chaque ligne suivante est retenu un arc. Ce fichier sera dnomm
graphe.txt.
Pour le graphe prsent antrieurement, ce fichier texte
aura la suivante forme:
45
Structures de donnes et algorithmes
6
1 2
1 4
1 5
2 3
2 5
3 2
3 6
4 5
5 2
6 5
a) Le premier mode de reprsenter ce graphe utilise une
matrice, matrice dadjacences, avec n lignes et n colonnes, une
matrice boolenne avec des lments 0 et 1. Cette matrice, note
a[n][n], peut tre dfinie comme :

'

A j i si
A j i si
j i a
) , ( 0
) , ( 1
] ][ [
Autrement dit, un lment a[i][j] est 1 sil y a un arc
orient de i j. Pour notre exemple, la matrice dadjacences
est la suivante :
a=
1
1
1
1
1
1
1
1
]
1

0 1 0 0 0 0
0 0 0 0 1 0
0 1 0 0 0 0
1 0 0 0 1 0
0 1 0 1 0 0
0 1 1 0 1 0
Le principal dsavantage de la mmorisation dun graphe
par la matrice dadjacences est que cette matrice a beaucoup
dlments zro et on consume inutilement la mmoire.
Le principal avantage est laccs rapide aux arcs du
graphes. La matrice dadjacences est utile dans les algorithmes
dans lesquels on teste frquemment la prsence ou labsence dun
arc.
46
Structures de donnes et algorithmes
La lecture du fichier et de sa mmoire sous la forme de
matrice dadjacences est ralise avec la fonction lire.
#include < fstream.h>
void lire(char nomfis[20],inta[50][50],int&n)
{fstream f(nom fis,ios:: in);
int i,j;
f>>n;
while(f>>i>>j) a[i][j]=1;
f.close( );}
La fonction lire est trs utilise dans le chapitre
GRAPHES et cest pour a quelle est mmorise dans un
module nomm graphes.cpp
Voici un programme qui utilise cette fonction retenue
dans le module graphes.cpp .
Ce programme va afficher la matrice dadjacences
daprs linformation lue dans le fichier graphe.txt
PROGRAMME LIRE MATRICE DADJACENCES
#include graphes.cpp
int a[50][50],n,i,j;
main( )
{lire(graphe.txt,a,n);
for i=1;i<=n;i++)
{printf(\n);
for(j=1;j<=n;j++)
printf(%d,a[i][j];}}
c) Un autre mode de reprsenter un graphe est par des
listes dadjacences. Pour chaque nud i, il y a une liste linaire
simplement enchaine dans laquelle sont inclus tous les nuds j
pour lesquels (i,j) est un arc.
Pour lexemple ci-dessu les listes dadjacences sont :
1 5 4 2
2 5 3
47
Structures de donnes et algorithmes
3 6 2
4 5
5 2
6 5
7
La reprsentation par les listes dadjacences utilise mieux
la mmoire mais dtermine une plus difficile recherche des arcs.
La fonction lire1 joue le rle de lire le graphe du
fichier graphe.txt et de le mmoriser sous la forme de listes
dadjacences.
Si on veut afficher les listes dadjacences, on utilise le
suivant programme :
PROGRAMME LIRE LISTES DADJACENCES
struct noeud
{int nr;
noeud*adrsuiv;};
void lire {(char nomfis[20],
noeud liste[100],int &n)
{noeud*p;
int i,j;
fstream f(nomfis,ios::in);
f>>n;
for(i=1;i<=n; i++) liste[i]=0;
while(f>>i>>j)
{p=new noeud;padrsuiv=liste[i];
pnr=j; liste[i]=p;}
f.close();}
1.4.1.3. Le parcours des graphes orients
Plusieurs problmes de graphes ncessitent lainsi
nomme visite, cest--dire lexploration du graphe, en partant
dun nud et en passant par tous les nuds. Chaque visite dans
un nud est accompagne par le traitement de linformation
48
Structures de donnes et algorithmes
trouve dans ce nud. On peut faire le passage dun nud
lautre seulement par un arc direct.
Les algorithmes de parcours divident le graphe en deux
ensembles de noeuds :
- visits ( lensemble des nuds visits)
- non-explors (un sous-ensemble de lensemble visit
qui a des noeuds avec des voisins partiellement visits).
On commence lexploration des nuds accessibles par un
certain nud. Si des nuds non-explors restent, on choisi un
dentre eux et on excute de nouveau le programme. Le procd
peut tre rpt jusquon visite tous les nuds.
Il y a deux modalits gnraux de parcours :
a) parcours en largeur, BF (BREADTH FIRST)
b) parcours en profondeur, DF (DEPTH FIRST).
1.4.1.3.1 Le parcous en largeur, BF (BREADTH FIRST)
Le parcours en largeur commence dun certain nud i .
Puis, on parcourt tous les descendents du nud, cest--dire tous
les nuds j pour lesquels existe un arc (i,j). On continue
avec tous les descendents des nuds parcourus. On parcourt un
nuds une seule fois.
Soit le graphe :
Il y a plusieurs solution pour ce problme, parce que
lordre du parcours des descendents nest pas impose.
Une solution serais :
49
Structures de donnes et algorithmes
1 3 6 2 7 5 4
Une autre solution peut tre :
1 2 6 3 4 5 7
Observations :
a)- Il y a plusieurs solutions pour ce genre de parcours,
parce que lordre du parcours nest pas impose. Souvent cette
ordre dpend de la manire de mmoriser le graphe.
b)- La condition obligatoire de parcourir le graphe est
quon visite un noeud une seule fois.
c)- Dhabitude, il faut effectuer le parcours BF en
utilisant la structure de donnes queue. Dans nos exemples,
nous allons implmenter la queue par un vecteur.
Dans limplmentation de lalgorithme de parcours BF
nous utiliserons les suivantes notations :
iq lindice composante de la queue ;
dq la dernire composante de la queue ;
queue le vecteur qui mmorise la queue ;
v le vecteur boolen qui retient les nuds introduits
dans la queue, ainsi :
v[i] =

'

queue la dans mis ete a i noeud le si


queue la dans mis ete pas a n i noeud le si
1
' 0
Nous allons expliquer lalgoritme de parcours BF, pour
lexemple : 1 2 6 3 4 5 7
On introduit le nud
1 dans la queue. 1
iq
dq
On introduit dans la
queue tous les nuds
qui appartient au
1 2 6 3
50
Structures de donnes et algorithmes
nud 1. iq
dq
On introduit dans la
queue tous les nuds
qui appartient au
nud 2.
1 2 6 3 4 5
iq
dq
Il ny a pas des
nuds qui appartient
au nud 6.
1 2 6 3 4 5
iq
dq
On introduit dans la
queue le nud 7. 1 2 6 3 4 5 7
iq
dq
Lalgorithme finit quand iq>dq , donc quand on a trait tous les
nuds de la queue.
PROGRAMME BF-RCURSIF-LISTES DADJACENCES
#includegraphes.cpp
noeud *liste[100];
int queue[100],s[100],iq,dq,i,n;
main()
{lire 1 (graphe.txt),liste,n);
iq=1;dq=1 queue[iq]=1;s[1]=1;
bfr()
51
Structures de donnes et algorithmes
for(i=1;i<=dq;i++) printf(%d/n,queue[i]);}
void bfr() || fonction recoursive
{noeud p;
if(iq<=dq)
{p=liste[queue[iq]];
while(p)
{if(s[pnr]= =0)
{dq++; queue[dq]=pnr;s[pnr]=1;}
p=padrsuiv;}
bfr();}}
PROGRAMME BF NON-RCURSIF LISTES DADJACENCES
void bfn()
{noeud*p;
while(iq<=dq)
{p=liste[queue[iq]];
while(p)
{if(s{pnr]==0)
{dq++;queue[dq]=pnr;
s[pnr]=1;} p=padrsuiv;}
iq++;}}
PROGRAMME BF-RCURSIF-MATRICES DADJACENCES
#include graphes.cpp
int queue[100],s[100],a[100][100],iq,dq,c,i,
n;
void bfma()
{int j;
if(iq<=dq)
{for(j=1;j<=n;j++)
if((a[queue[iq]][j]==1) &&(s[j]==0))
{dq++;queue[dq]=j;s[j]=1;}iq++;
bfma();}}
main()
{lire(graphe.txt,a,n);
iq=dq=1;
queue[iq]=s[1]=1;bfma();
for(i=1;i<=dq;i++)
52
Structures de donnes et algorithmes
printf(%d, queue[i]));}
1.4.1.3.2. Le parcours en profondeur
(DF-DEPHT FIRST)
La rgle de parcours DF est:
-on commence dun certain noeud;
-aprs le parcours dun noeud, on parcourt le premier de
ses descendents encore non-parcouru .
Pour le mme exemple :
Il y a plusieurs posibilits dont les deux suivantes:
1 2 4 5 3 6 7
1 3 7 6 2 5 4
La ralisation DF utilise les piles.
PROGRAMME DF-RCURSIF- MATRICE DAJACENCES
#include graphes.cpp
int a[100][100],s[100],n;
void dfma (int noeud)
{int i;
printf(%d\n,noeud);s[noeud]=1;
for(i=1;i<=n;i++)
53
Structures de donnes et algorithmes
if((a[noeud][i]==1) && (s[i]==0))s[i]=1;
dfma(i);}
main()
{lire(graphe.txt),a,n);
dfma(1);}
PROGRAMME BF-RCURSIF-LISTE DAJACENCES
#include graphes.cpp
int pile{100],n;
noeud*listeadi[100];
void dfla(int noeud)
{noeud*p;
printf(%d\n,noeud); p=listeadi(noeud);
pile[noeud]=1;
while(p)
{if(pile[pnr]==0)
dfla(pnr);
p=padrsuiv;}}
main()
{lire1(graphes.txt,listeadi,n);
dfla(1);}
1.4.1.4. Composantes fortement connexes
Une composante fortement connexe dun graphe orient
G est un sous-graphe G
1
qui a les propriets: a)pour quels que
soient deux noeuds x
i
etx
j
, il y a du chemin de x
i
x
j
et de x
j

x
i
; b)il-ny-a pas dautre sous-graphe G
2
, G
1

G
2
, avec la
proprit a).
Si le graphe G est une composante connexe, G sapelle
graphe connexe. Dans le graphe ci-dessus, il-y-a deux
composantes fortement connexes:
54
Structures de donnes et algorithmes
1 , 2 , 6 ,5 et 3 , 7
En effet, pour quels que soient deux noeuds de chaque
composante fortement connexe il y a chemin dans tous les deux
sens. Par exemple, pour les noeuds 1 et 6, nous avons les
chemins:
16 1,2,6
16 6,5,1
Dtermination de la composante fortement connexe dun
noeud.
ce but, nous allons dfinir les notions de successeur et
prdecesseur dun noeud:
-un successeur dun certain noeud est un noeud
pour lequel il y a un chemin noeud-successeur;
-un prdcesseur dn certain noeud est un noeud
pour lequel il y a un chemin prdcesseur-noeud.
Lintersection dentre lensemble des succeseurs dun
noeud et lensemble de ses prdcesseurs est justement la
composante fortement conexe du noeud.
Par exemple, pour le prcdent graphe, les composantes
fortement connexes des noeuds 7 et 6 sont:
- le noeud 7
successeurs: 8, 3
prdcesseurs: 1, 2, 5, 6,
intersection: 3
composante fortement conexe: 3, 7
- le noeud 6
successeurs: 5, 1, 2, 3, 4, 7, 8
prdcesseurs: 1, 2, 5
intersection: 1, 2, 5
composante fortement conexe: 1, 2, 5, 6
Voici ci-desous un programme qui dtermine la
composante fortement connexe dun noeud donn. Dans ce
programme nous avons dtermin les successeurs et les
55
Structures de donnes et algorithmes
prdcesseurs du noeud i dans les vecteurs succ[i] et
pred[i]. La mthode de dtermination est obtenue par le
parcours en profondeur.
PROGRAMME COMPOSANTES FORTEMENT CONNEXES
#includegraphes.cpp
int succ[100],pred[100],a[100][100],n,i,j;
void successeur(int noeud)
{int k;
succ[noeud]=i;
for(k=1;k<=n;k++)
if((a[noeud][k]==1) && (succ[k]==0))
successeur(k);}
Void predecesseur (int noeud)
{int k;
pred[noeud]=i;
for(k=1;k<=n;k++)
if((a[k][noeud]==1) && (pred[k]==0))
predecesseur(k);}
main()
{lire(graphes.txt,a,n);
printf(introduire noeud de depart);
scanf(%d,&i);
for(j=1;j<=n;j++)
if((succ[j]==pred[j])) &&(succ[j]==i))
printf(%d),j);}
Dcomposition dun graphe en composantes fortement
connexes.
Le graphe est mmoris par une matrice dadjacence. Le
programme pour la dcomposition dun graphe en composantes
fortement connexes est bas sur le progamme antrieur. De plus,
ce programme va retenir, par lintermde de la variable
compteur, le nombre courant de la composante fortement
connexe.
PROGRAMME DECOMPOSITION EN COMPOSANTES
FORTEMENT CONNEXES
56
Structures de donnes et algorithmes
#includegraphes.cpp
int succ[100],pred[100],a[100][100],n,compteur,j)
void succeseur(int noeud)
{int k;
succ[noeud]=compteur;
for(k=1;k<=n;k++)
if((a[noeud][k]==1) && (succ[k]==0))
succeseur(k);}
void predecesseur(int noeud)
{int k;
pred[noeud]=compteur;
for(k=1;k<=n;k++)
if((a[noeud][k]==1) && (pred[k]==0))
predecesseur(k);}
main()
{lire(graphe.txt,a,n);
compteur=1;
for(i=1;i,=n;i++)
if(succ[i]==0)
{succ[i]=compteur;
successeur(i) ;predecesseur(i);
for(j=1;j<=n;j++)
if(succ[j]!=pred[j]) succ[j]=pred[j]=0;
compteur++;}
for(i=1;i<compteur;i++)
{printf(composante%d\n,i);
for(j=1;j<=n;j++)
if(succ[j]==i) printf(%d,j);}}
Pour notre exemple le programme va afficher :
Composante 1 1 2 5 6
Composante 2 3 7
1.4.1.5. Graphes pondrs
Dans ce sous-chapitre nous allons aborder les types de
problmes de graphes dans lesquels chaque arc on associe un
57
Structures de donnes et algorithmes
nombre rel positif, appel poids, qui reprsente une distance, un
temps, un cot, une rsistance etc.
1.4.1.5.1. La matrice des poids
Dans un graphe, on attache chaque arc x
1
x
2
un poids
(cot) nomm c
x1x2
>0.
La matrice des poids (cots) est dfinie en deux modes :
Le mode 1 :
m
ij
=

'

j i
pas existe n ij arc l et j i
existe ij arc l et j i c
ij
0
' '
'
Le mode 2:
m
il
=

'

j i
pas existe n ij arc l et j i
existe ij arc l et j i c
ij
0
' '
'
Soit le graphe:
58
Structures de donnes et algorithmes
m
1
[6][6]=
1
1
1
1
1
1
1
1
]
1







0 50
300 0 100 30
400 40 0 1500
60 200 0 500
2500 15 0
10 20 0
m
2
[6][6]=
1
1
1
1
1
1
1
1
]
1







0 50
300 0 100 30
400 40 0 1500
60 200 0 500
2500 15 0
10 20 0
Le programme qui lit la matrice des poids sous la forme
(mode) 1 est le suivant:
Void lirematricepoids(char nomfis[100],
float[100][100],int &n)
{int i,j;
float k;
fstream f(nomfis,ios:: in)
f>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j) a[i][j]=0;
else a[i][j]= infini;
while(f>>i>>j>>k) a[i][j]=k;
f.close();
O infini = 1.e
20
. Pour notre exemple le fichier sera:
6
1 2 20
1 3 500
1 4 10
2 3 15
59
Structures de donnes et algorithmes
2 4 2500
3 1 500
3 5 200
3 6 60
4 2 1500
4 5 40
4 6 400
5 2 30
5 3 100
5 6 300
6 3 50
La matrice des poids est utilis surtout dans les
algorithmes qui dterminent la longueur minimale ou maximale
dans un graphe. Par la longueur dans un graphe on comprend la
somme des poids de ses arcs.
1.4.1.5.2. Lalgorithme Roy-Floyd
Soit un graphe mmoris par la matrice des poids (mode
1). On demande de dterminer la longueur minimale du chemin
entre deux noeuds du graphe.
Lalgorithme Roy-Floyd trouve le chemin minimal entre
deux noeuds i et j , en cherchant tous les chemins qui
passent par le noeud intermdiaire k, o k= n 1 (k i, kj).
Chaque fois, pour un nouveau noeud, on compare m[i][j] avec
m[i][k]+m[k]j] et on retient la longueur minimale.
Exemple:
Nous verrons comment est apliqu cet algorithme pour
chaque pas, dans notre exemple.
Pas 1
m[3][2]=m[3][1]+m[1][2]=500+20=520< , on retient
m[3][4]=m[3][1]+m[1][4]=500+10=510< , on retient
60
Structures de donnes et algorithmes
m[6][6]=
[ ] [ ]
1
1
1
1
1
1
1
1
]
1






0 50
300 0 100 30
400 40 0 1500
60 200 510 0 520 500
2500 15 0
10 20 0
Pas 2
m[1][3]=m[1][2]+m[2][3]=20+15=35< , on retient
m[4][3]=m[4][2]+m[2][3]=1500+15=1515<,on retient
m[5][4]=m[5][2]+m[2][4]=30+2500=2530<, on retient
m[6][6]=
1
1
1
1
1
1
1
1
]
1



0 50
300 0 2530 100 30
400 40 0 1515 1500
60 200 510 0 520 500
2500 15 0
10 35 20 0
Pas 3
m[1][5]=m[1][3]+m[3][5]=35+200=235<, on retient
m[1][6]=m[1][3]+m[3][6]=35+60=95<, on retient
m[2][1]=m[2][3]+m[3][1]=15+500=515<, on retient
m[2][4]=m[2][3]+m[3][4]= 15+510=525<2500, on retient
m[2][5]=m[2][3]+m[3][5]=15+200=215<, on retient
m[2][6]=m[2][3]+m[3][6]=15+60=75< on retient
m[4][1]=m[4][3]+m[3][1]=1515+500=2015< on retient
m[4][2]=m[4][3]+m[3][2]=1515+520=2035>1500on ne retient pas
m[4][5]=m[4][3]+m[3][5]=1515+20=1715>40 on ne retient pas
m[4][6]=m[4][3]+m[3][6]=1515+60=2025>400 on ne retient pas
m[5][1]=m[5][3]+m[3][1]=100+500=600< on retient
m[5][2]=m[5][3]+m[3][2]=100+200=300>30 on ne retient pas
m[5][4]=m[5][3]+m[3][4]=100+510=610<2530 on retient
m[5][6]=m[5][3]+m[3][6]=100+200=300=300 on ne retient pas
61
Structures de donnes et algorithmes
m[6][1]=m[6][3]+m[3][1]=50+500=550< on retient
m[6][2]=m[6][3]+m[3][2]=50+520=570< on retient
m[6][4]=m[6][3]+m[3][4]=50+510=560< on retient
m[6][5]=m[6][3]+m[3][5]=50+200=250< on retient
m[6][6]=
1
1
1
1
1
1
1
1
]
1

0 250 560 50 570 550


300 0 610 100 30 600
400 40 0 1515 1500 2015
60 200 510 0 520 500
75 215 525 15 0 515
95 235 10 35 20 0
Le pas 4
m[1][2]=m[1][4]+m[4][2]=10+1500=1510>20 on ne retient pas
m[1][3]=m[1][4]+m[4][3]=10+1515=1525>31 on ne retient pas
m[1][5]=m[1][4]+m[4][5]=10+40=50<235 on retient
m[1][6]=m[1][4]+m[4][6]=10+410=410>95 on ne retient pas
m[2][1]=m[2][4]+m[4][1]=525+2015=2540>515on ne retient pas
m[2][5]=m[2][4]+m[4][5]=525+40=565>215 on ne retient pas
m[3][1]=m[3][4]+m[4][1]=510+2015=2525>500onneretient pas
m[5][1]=m[5][4]+m[4][1]=610+2015=2625>600on ne retient pas
m[6][1]=m[6][4]+m[4][1]=560+2015=2575>550on ne retient pas
m[6][6]=
1
1
1
1
1
1
1
1
]
1

0 250 560 50 570 550


300 0 610 100 30 600
400 40 0 1515 1500 2015
60 200 510 0 520 500
75 215 525 15 0 515
95 50 10 35 20 0
On fait de la mme manire les pas 5 et 6. On obtient une
matrice dans laquelle llment m[i][j] reprsente le cot
minimal entre les noeuds i et j.
62
Structures de donnes et algorithmes
La stratgie gnrale de cet algorithme est de type DIVIDE
ET IMPERA , stratgie qui sera tudi dans le chapitre suivant.
PROGRAMME ROY-FLOYD
#define pinfini 1e20
#includegraphes.cpp
float m[100][100];
int n;
void chemin(int i,int j)
{int t=1, trouve=0;
while((t<=n)&& trouve){
if((i!=t)&&(j!=t)&&(m[i][j]==m[i][k]+m[k][j]))
{chemin(i,t);chemin(t,j);
trouve=1;}t++;}
if(!trouve) printf(%d),j);}
void afficherchemin(int noeudinitial,
int noeudfinal)
{if(m[noeudinitial][noeudfinal]<pinfini
{printf(chemininitial de %d a %d a
la longueur%d,noeudinitial,noeudfinal,
m[noeudinitial]
[noeudfinal]);printf{noeudinitial);chemin(no
eudinitial, noeudfinal);
else
printf(pas de chemin de %d a %d,
noeudinitial,noeudfinal);}
void longueur chemin()
{int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(m[i][j]>m[i][t]+m[t][j])
m[i][j]=m[i]t]+m[t][j]);}
main()
{lirematricepoids(graphes.txt,m,n);
longueurchemin();
afficherchemin(4,2);}
1.4.1.5.3.-Lalgorithme DIJKSTRA
63
Structures de donnes et algorithmes
Soit un graphe mmoris par la matrice des poids (mode
1). On demande de dterminer la longueur minimale du chemin
pour quels que soient deux noeuds du graphe.
Cest le mme problme comme lalgorithme Roy-
Floyd. Si dans lalgorithme Roy-Floyd on applique une technique
dlaboration de type DIVIDE ET IMPERA, pour lalgorithme
DIJKSTRA on utilise une technique de programmation de type
GREEDY. Lalgorithme slecte les noeuds du graphe, un par un,
en ordre croissante du poids du chemin.
Pour limplmentation on utilise trois vecteurs, v1, v2,
v3.
-Le vecteur v1 est le vecteur des longueurs des chemins
entre le noeud de dpart np et les autres noeuds du graphe. Une
composante v1[i], avec n ... 1 , signifie le poids du chemin, un
moment donn, entre le noeud initial np et le noeud i.
-Le vecteur v2 contient les chemins trouvs entre le
nud initial np et les autres nuds du graphe. La composante
v2[i] sera le nud qui prcde le nud i dans le chemin de np
i.
-Le vecteur v3 indique les nuds slects ; si v3[i]=0, le
nud i est non-slect ; si v3[i]=1, le nud est slect.
Lalgorithme a les suivants pas :
Pas 1 Au commencement, le vecteur v2 est un ensemble
vide. On choisi le nud initial np et on lajoute lensemble v2 ;
v2[np]=1.On prend de la matrice des poids, m , les poids des
chemins entre le nud initial np et chaque nud du graphe
(situs sur la ligne np) et on les transfre dans le vecteur v1.
Pour tous les nuds i qui ont un poids du chemin entre
np et le noeud i, on met v3[i]= np.
Pas 2
On excute la squence n-1 fois. On slecte un nud
situ une distance minimale de np et on le met dans le vecteur
v2.
64
Structures de donnes et algorithmes
Pour les nuds non-slects, on actualise en v1 le poids
des chemins dentre np et ces nuds, en utilisant comme nud
intermdiaire le nud slect, de la suivante manire : on
compare la distance existante dans le vecteur v1

avec la somme
dentre la distance existante dans le vecteur v1 pour le nud
slect et la distance dentre le noeud slect et le nud pour
lequel on fait lactualsation de la distance. Si cette somme est
plus petite, llment de v1, correspondant au nud pour lequel
on fait lactualisation, retiendra la somme . Llment de v3,
correspondant au mme nud, prend la valeur du nud slect.
if(v1[j]>v1[pos]+m[pos][j]
{v1[j]=v1[pos]+m[[pos][j] ;
v3[j]=pos ;}
Pas 3
On trace le chemin dentre np et chaque nud.
Soit le graphe :
La matrice des poids est :
m=

,
_

0 10 2 8
7 0 5 20
4 0
3 0
6 9 1 0
65
Structures de donnes et algorithmes
On choisi le nud 1 comme nud initial.
noeuds
vecteurs
1 2 3 4 5
V1 0 1

9 6
V2 1 0 0 0 0
V3 0 1 0 1 1
Le noeud le plus approch du noeud 1 est le noeud 2.
v1[3]

=v1[2]+m[2][3]=1+3=4<v1[3]= v1[3]=4,
v3[3]=2
v1[4]=v1[2]+m[2][4]=1+=>v1[4]=9
v1[5]=v1[2]+m[2][5]=1==>v1[5]=6
Le tableau devient:
noeuds
vecteurs
1 2 3 4 5
V1 0 1 4 9 6
V2 1 1 0 0 0
V3 0 1 2 1 1
Puis, on choisi le noeud 3.
v1[2]=v1[3]+a[3][2]=4+=
v1[4]=v1[3]+a[3][4]=4+=
v1[5]=v1[3]+a[3][5]=4+4=8>v1[5]=6
Donc, le noeud 3 napporte aucun changement.
On choisi le noeud 5.
v1[2]=v1[5]+a[5][2]=6+8=14>v1[2]=1
v1[3]=v1[5]+a[5][3]=6+2=8>v1[3]=4
v1[4]=v1[5]+a[5][4]=6+10=16>v1[4]=9
Le noeud 5 napporte aucun changement.
Le noeud 4 ,aussi, napporte aucune amlioration.
Le tableau final est:
noeuds
vecteurs
1 2 3 4 5
V1 0 1 4 9 6
V2 1 1 1 1 1
V3 0 1 2 1 1
66
Structures de donnes et algorithmes
Interprter ce tableau signifie dterminer la distance
minmale entre le noeud initialement choisi (dans notre cas 1) et
les autres noeuds du graphe (2,3,4,5).
En observant les valeurs de v3, on voit que les distances
minimales entre 1-2, 1-4, 1-5 sont les liaisons directes, cest--
dire:
distance minimale (1,2)=1
distance minimale (1,4)=9
distance minimale (1,5)=6
La distance minmale 1-3 passe par le noeud 2 et sera:
distance minimale (1,2,3)=4
Voici le programme qui implmente lalgorithme
DIJKSTRA:
PROGRAMME DIJKSTRA
#includegraphes.cpp
float m[100][100],v1[100],min;
int v2[100],v3[100],n,i,j,np,pos;
void chemin(int i)
{if(v3[i]) chemin(v3[i]);
printf(%d,i);}
main()
{lirematricepoids(graphe.txt,m,n);
printf(np=);
scanf(%d%,&np);
v2[np]=1;
for(i=1;i<=n;i++)
{v1[i]=m[np][i];
if(i!=np)
if(v1[i]<infini)v3[i]=np;}
for(i=1;i<=n-1;i++)
{min=infini;
for(j=1;j<=n;j++)
if(v2[j]==0)
if(v1[j]<min)
67
Structures de donnes et algorithmes
{min=v1[j];pos=j;}
v2[pos]=1;
for9j=1;j,=n;j++)
if(v2[j]==0)
if(v1[j]>v1[pos]+m[pos][j])
{v1[j]=v1[pos]+m[pos][j];v3[j]=pos;}}
for(i=1;i<=n;i++)
if(i!=np) if(v3[i])
{printf(distance de %d a %d est %d,
np,i,v1[i]);
chemin(i);}
else
printf(il ny a pas chemin de%d a%d,np,i);}
1.4.2. Graphes non-orients
Dans les graphes avec les artes non-orientes, une arte
ralise une double liaison entre deux noeuds.
Tous les problmes tudies pour les graphes orients
sont valables aussi pour les graphes non-orients.
Les graphes hamiltoniens et les graphes eulriens, qui
prsentent beaucoup dapplications prattiques, sont des cas
particulier de graphes. Nous allons les tudier comme graphes
non-orients.
1.4.2.1. Graphes hamiltoniens
Un cycle hamiltonien est un cycle lmentaire qui visite,
une fois et une seule, chacun des noeuds du graphe. Un graphe
qui possde un cycle hamiltonien est dnomm graphe
hamiltonien.
Soit, par exemple, le graphe suivant qui contient un
chemin hamiltonien 1 2 8 7 5 4 3 9 10.
68
Structures de donnes et algorithmes

Parce quil contient un chemin hamiltonien, le graphe est
hamiltonien. Un important problme cest la dtermination des
cycles hamiltoniens dun graphe. Cest regrettable quil ny a pas
un algorithme polynmial pour rsoudre ce problme.
Dhabitude on utilise la mthode backtracking ou les algorithmes
gntiques. Lorigine du terme hamiltonien se trouve dans un jeu
invent, en 1857, par le mathmaticien William Hamilton. Le jeu
contient un polydre avec 12 faces, toutes pentagones reguliers;
chaque sommet du polydre est le point de rencontre de trois
artes. Les 20 sommets de ce dodcadre sont marqus avec des
noms de villes. Le jeu demande de trouver un chemin le long des
artes du polidre, chemin qui doit passer par chaque ville une
seule fois, et finir au point de dpart. Le problme demande donc
de trouver un cycle hamiltonien dans le graphe form avec les
sommets et les artes du dodcadre.
Un problme plus gnral, est le problme du commis
voyageur qui doit prsenter, dans n villes, les produits de la
fabrique quil reprsente et puis retouner dans la ville de dpart.
En connaissant le cot de dplacement entre deux villes, on
demande de dterminer un chemin qui passe une seule fois par
chaque ville et qui soit le moin cher. Le problme revient la
dtermination dun cycle hamiltonien dans le graphe ainsi form.
Ce problme sera rsolu dans le chpitre ALGORITHMES par la
mthode backtracking.
Un autre problme classique de recherche dun cycle
hamiltonien est le problme du cheval sur un echiquier. Le
cheval doit parcourir lentier echiquier en passant une seule fois
par chaque carr. Ce problme aussi sera trait par la mthode
backtracking non-standard.
69
Structures de donnes et algorithmes
Sil ny a pas dalgorithme polynmial pour rsoudre ces
problmes, il y a pourtant un thorme qui assure la condition
sufisante pour lexistence dun cycle hamiltonien.
Thorme: Si G est un graphe simple avec n3 sommets,
tel que tout sommet de G soit de degr strictement suprieur
n/2, alors G est est hamiltonien.
Le degr dun sommet x , not d(x), est le nombre des
artes dont il est une extrmit.
1.4.2.2. Graphes eulriens
Un cycle dun graphe est dit eulrien sil en contient
toutes les artes une fois et une seule. Un graphe qui admet un tel
cycle est un graphe eulrien.
Le nom a t donn daprs le mathmaticien Leonhard
Euler qui, en 1736, a crit le premier ouvrage sur la thorie des
graphes en liaison avec le problme des ponts de Knigsberg,
alors en Prusie orientale, maintenant Kaliningrad en Rusie. Dans
Knigsberg existaient sept ponts sur le delta du fleuve Pregel
situs comme dans le dessin suivant:

Il y avaient sept ponts (a,b,c,d,e,f,g) et quatre rgions
(A,B,C,D).
La question est si on peut faire une promenade sur tous
les sept ponts, en passant une seule fois sur chacun et en arrivant
la fin au point de dpart. Euler a dmontr que cette chose est
impossible.
70
Structures de donnes et algorithmes
Les quatre rgions (les ou rives) A,B,C,D et les sept
ponts a,b,c,d,e,f,g ont t reprsents comme noeuds dun
graphe; les arcs sont les possibilits de passage dune rive (le)
lautre sur un pont.

Le problme des sept ponts a une solution sil y a un cycle
eulerien dans le graphe ci dessus. Mais il ny existe pas, en vertu
du thorme suivant:
Thorme. Un graphe G, sans sommets isols, est eulrien
si et seulement si il est connexe et les degrs de tous ses sommets
sont des nombres pairs.
Comme tous les sommets du graphe ci dessus sont impairs,
le graphe nest pas eulrien.
Voici un exemple de graphe dans lequel il y a un cycle
eulerien, donc cest un graphe eulerien.
Le cycle eulrien est: 1,2,4,5,7,8,9,5,1
En partant du thorme prcdent, on peut crer un
programme qui vrifie si un graphe est connexe et a tous les
sommets avec des degrs pairs. Les tapes du programme sont:
71
Structures de donnes et algorithmes
On vrifie la connexit.
On parcourt le graphe, par exemple en profondeur. Si la
fin du parcours restent des sommets (noeuds) non touchs, alors
le graphe nest pas convexe. La fonction connex appele la
fonction dfma, aprs quoi on explore le vecteeur s des noeuds
touchs.
On vrifie si tous les sommets ont des degrs pairs.
Cette opration est ralis par la fonction boolenne
grad.pair . Cette fonction vrifie si chaque ligne de la matrice
adjacente a la somme de ses lments un nombre pair.
On trouve le cycle eulrien.
Si les deux conditions prcdentes sont accomplies, on
cherche un chemin eulrien. Le cycle eulrien sera retenu par une
liste linaire simplement enchaine, dans laquelle chaque lment
est un noeud du graphe. Le vecteur aliste retient ladresse de
son premier lment.
La fonction boolenne ajoute explore la liste, en partant
de son premier lment , soit v , et applle la fonction cycle
qui identifie un cycle qui commence et fini par ce noeud. En
commenant par lui, on slecte une de ses artes incidentes qui
est incidente aussi pour un autre noeud, soit v1. Puis, on slecte
une autre arte incidente pour v1 qui est incidente aussi pour
autre noeud, v2. La slection continue jusquon arrive, de
nouveau, au v. On introduit chaque noeud incident pour les
artes trouves dans la liste linaire simplement enchaine.
Chaque arte slecte est efface de la matrice dadjacence.
Lalgorithme fini quand il ny a plus des noeuds avec des artes
incidentes.
PROGRAMME GRAPHES EULERIENS
#includegraphes.cpp
int a[100][100],s[50],n,nd;
noeud*aliste,*indice;
void cycle(noeud*v)
72
Structures de donnes et algorithmes
[int noeud;
noeud*anoeudbase,*anoeudtrouve,*anoeudsuiv;
anoeudsuiv=vadrsuiv;
anoeudbase=v;
do{noeud=1;
while(a[anoeudbasend][noeud]==0)noeud++;
a[anoeudbasend][noeud]=0;
a[noeud][anoeudbasend]=0;
anoeudtrouve=newnoeud;anoeudtrouvend=module;
anoeudtrouveadrsuiv=0
anoeudtrouveadrsuiv=0
anoeudbaseadrsuiv=anoeudtrouve;
anoeudbase=anoeudtrouve;}
while(anoeudtrouvend!=vnd);
anoeudbaseadrsuiv=anoeudsuiv;
int ajoute()
{int i,trouve=0;
indice=aliste;
while(indice &&trouve)
{for(i=1;i<=n;i++)
if(a[indicend][i]==1)trouve=1;
if(!trouve)indice=indiceadrsuiv;}
if(indice)
{cycle(indice);
return1;}
else return 0;}
int grad pair()
{int i=1,j,s,touve=0;
while((i<=n) &&!trouve)
{s=0;
for(j=1;j<=n;j++)
s+=a[i][j];
if(s%2)trouve=1;i++)}
return(!trouve)}
void df(int noeud)
{int k;
s[noeud]=1;
for(k=1;k<=n;k++)
if((a[noeud][k]==1) &&(s[k]==0))
df(k);}
int connex()
73
Structures de donnes et algorithmes
{inttrouve=0,i;
df(1);
for(i=1;i<=n;i++)
if(s[i]==0)trouve=1;
return !trouve;}
main()
{lire(graphe.txt,a,n,);
if(connex()]
if(grad pair()]
{aliste=new noeud;
alistend=1; alisteadrsuiv=0;
while(ajoute());
indice=aliste;
while(indice)
{printf(%d,indicend);
indice=indiceadrsuiv;}}
else
printf(le graphe naccomplie pas les
conditions de parite)
else
printf(le graphe nest pas connexe;}
1.4.3. Problmes avec des graphes
1.Soit le graphe suivant:
Calculez le chemin minimal entre les noeuds 1 et 6, en
utilisant lalgorithme R0Y-FLOYD et lalgorithme Djikstra.
2.Soit le graphe suivant:
74
Structures de donnes et algorithmes
En partant du noeud 4, affichez tous les noeuds auxquels
on peut arriver et retourner dans le noeud 4.
Indications: On peut appliquer la composante fortement connexe.
3.Soit la suivante figure:
On demande de trasser cette figure sans lever le crayon de
la carte.
Indications: Le problme demande si le graphe est eulrien ou non.
4.Dans le graphe ci-dessous les noeud reprsentent des
localits, les arcs des chausses et les nombres sur les arcs les
distances entre les localits. On demande de dterminer la
localit la plus proche de la localit reprsente par le noeud 1.
Indications: On peut appliquer lalgorithme Roy-Floyd ou Djikstra
75
Structures de donnes et algorithmes
5.Le problme du commis-voyageur. Soit le graphe
suivant dans lequel les noeuds sont des viles et les arcs sont des
routes entre les viles.
On demande que le commis-voyageur passe par chaque
vile et retourne dans la vile do il est parti.
Indications: On demande si le graphe est hamiltonien.
1.5.ARBRES
1.5.1. Dfinitons
Un arbre est un graphe simple connexe tel que, quels que
soient les sommets distincts i et j, il existe une seule chane
joignante i j.
76
Structures de donnes et algorithmes
Thorme:
Soit G un graphe ayant s sommets; les propositions
suivantes sont quivalentes:
- G est un arbre;
- G est connexe et sans cycles;
- G est sans cycle et possde s-1 artes;
- G est connexe et possde s-1 artes;
- G est sans cycle et toute arte ajoute cre un seule
cycle;
- G est connexe et la supression de nimporte quelle arte
le rend non connexe.
Un graphe A est un arbre couvrant de graphe G connexe
si:
- A possde les mmes sommets que G,
- Les artes de a sont des artes de G,
- A est un arbre.
Si entre les lments dune collection de donnes il y a
une relation dordre, on dit que la structure de cette collection est
une strcture arborescente. Ce type de structure a les suivantes
proprits:
-Il y a un lment unique nomm la racine de larbre.
-Nimporte quel noeud distinct de la racine a un seul
prdcesseur imdiat.
-Un noeud qui nest pas terminal a un nombre fini de
successeurs imdiats.
77
Structures de donnes et algorithmes
Une succession de noeuds (a
i1
, a
i2
a
in
) dans laquelle
pour a
ik
, k

n, a
i,k+1
est un successeur imdiat de a
ik
est
nomm chemin de longueur n-1 entre le noeud a
i1
et a
in
.
Le chemin de longueur maximale est nomm la hauteur
de larbre.
1.5.2. Test pour vrifier si un graphe est arbre
Pour vrifier si un graphe est arbre, il faut crire un
programme qui permette constater deux choses:
-que le graphe soit connexe;
-que le graphe ne contienne des cycles.
a)-Pour constater si un graphe orient est connexe, on
applique le parcours en profondeur (DF). Cet algorithme peut
tre utilis aussi pour les graphes non- orients comme les arbres.
Le seul problme est llimination dun arc quand il ya deux
noeuds lis par deux arcs.
b)-On fait un parcours en profondeur qui assure la
slection dun noeud une seule fois. Si le graphe a un cycle, un
noeud est touch deux fois.
PROGRAMME VRIFICATION SI UN GRAPHE EST ARBRE
# include graphes.cpp
int s[100],a[100][100],trouve,n,i,somme;
void dfma1(int noeud)
78
Structures de donnes et algorithmes
{int j;
s[noeud]=1;
for(j=1;j<=n;j++)
if(a[noeud][j]==1)
{a[j][noeud]=0;if(s[j]==0)bfma1(j);
else trouve=1;}
main()
{live(graphe.txt,a,n);
dfma(1);
somme=0;
for(i=1;i<=n;i++)somme+=s[i];
if(somme!=n)printf(graphe nest pas
connexe);
else
if(trouve)printf(graphe a au moins un
cycle);
else
printf(graphe est arbre)
1.5.3. Arbres binaires
1.5.3.1. Dfinition
Dans un arbre binaire chaque noeud (sommet) a au
maximum deux descendants: un gauche et un droit. Par exemple:
79
Structures de donnes et algorithmes
Cet arbre binaire a comme racine le noeud 1; il a 10 noeuds et
est organis sur 4 niveaux.
1.5.3.2. Reprsentation des arbres binaires
Les arbres sont des graphes, donc ils pouraient tre
reprsents par des matrices et des listes dadjacence. Ce mode
nest pas utilis patiquement parce quil se montre difficile dans
les applications. On utilise plutt la reprsentation par des
vecteurs. On construit deux vecteurs, droit[i] et gauche[i].
Une composante droit[i] retient le nombre dordre du noeud
droit subordonn au nud i et gauche[i] retient le nombre
dordre du nud gauche subordonn au nud i.
Pour lexemple choisi, ces vecteurs ont les suivantes
composantes :
i 1 2 3 4 5 6 7 8 9 10
droit[i] 3 0 6 8 0 10 0 0 0 0
i 1 2 3 4 5 6 7 8 9 10
gauche[i] 2 4 5 7 9 0 0 0 0 0
1.5.3.3. Le parcours des arbres binaires
Le parcours en largeur et en profondeur des arbres peut
tre ralis comme pour tous les graphes. Pourtant, pour les
arbres binaires, on utilise, de plus, trois modalits. Dans ce
dernier cas, on peut considrer que chaque noeud subordonne
deux sous-arbres: un sous-arbre droit et un sous-arbre gauche.
Les trois modalits sont:
a)Le parcours en ordre-GSD(gauche-sommet-droite)
On parcourt le sous-arbre gauche, puis le sommet et puis
le sous-arbre droit.
b)Le parcours en pre-ordre-SGD(sommet-gauche-droite)
80
Structures de donnes et algorithmes
On parcourt le sommet, puis le sous-arbre gauche et puis
le sous-arbre droit.
c)Le parcours en post-ordre-GDS(gauche-droite-sommet)
On parcourt le sous-arbre gauche, puis le sous-arbre droit
et puis le sommet.
Pour larbre exemplifi ci-dessu, les parcours sont:
a)GSD 7 4 8 2 1 9 5 3 6 10
b)SGD 1 2 4 7 8 3 5 9 6 10
c)GDS 7 8 4 2 9 5 10 6 3 1
Voici limplmentation de ces trois modalits de
parcours. On a adopt la variante rcursive, spcifique ces
recherches.
PROGRAMME PARCOURS GRAPHES
#include<costream.h>
int pile[100],droit[100],gauche[100],m,i,v;
void lirearbre()
{printf(n=);
scanf(%d,&,);printf(v=);scanf(%d,&v);
for(i=1;i<=n;i++)
{printf(droit[%d]=\n,);scanf(%d,
&droit[i]);
(gauche[%d]=\n,);scanf(%d,
&gauche[i]);}}
void gsd(int noeud)
{if(noeud)
{gsd(gauche[noeud];
printf(%d\n,noeud);
gsd(droit[noeud]);}}
void sgd(int noeud)
{if(noeud)
{printf(%d\n,noeud);
sgd(gauche[noeud];
sgd(droit[noeud]);}}
void gds(int noeud)
{if(noeud)
81
Structures de donnes et algorithmes
{gds(gauche[noeud];
gds(droit[noeud]);}}
printf(%d\n,noeud);}}
main()
{lirearbre()
printf(gsd;gsd(v);
printf(sgd;sgd(v);
printf(gds;gds(v);}
1.5.4. Arbres de recherche
1.5.4.1. Dfinition
Un arbre de recherche est un arbre binaire dont les noeuds
ont un clef didentification et qui a deux proprits:
-le clef associ un certain nud est plus grand que le
clef associ un nud de son sous-arbre gauche ;
-le clef associ un certain nud est plus petit que le clef
associ un nud de son sous-arbre droit.
Larbre de lexemple prcdent peut tre un arbre de
recherche sil a les suivants clefs:
1.5.4.2. Oprations avec des arbres de recherche
82
Structures de donnes et algorithmes
1.5.4.2.1. Insrtion
On compare le clef du noeud insrer avec le clef du
noeud pre sous lquel on insre le nouveau noeud. Il y a trois
possibilits:
-Le clef du noeud insrer est gal au clef du noeud pre
et alors on renonce linsrtion.
-Le clef du noeud insrer est plus grand que le clef du
noeud pre et alors on essaie linsrtion dans le sous-arbre droit.
-Le clef du noeud insrer est plus petit que le clef du
noeud pre et alors on essaie linsrtion dans le sous-arbre
gauche.
On fait linsrtion proprement dite quand un sous-arbre
est vide.
1.5.4.2.2. Cration
La cration dun arbre de recherche est ralise en
appliquant lopration dinsrtion n fois, n etant le nombre de
noeuds insrer.
1.5.4.2.3. Effacement
Si on efface un noeud qui na pas de descendents ou il a
un seul, il ny a pas de problmes difficiles. Des difficults
apparaissent leffacement dun noeud avec deux descendents
(le droit et le gauche). Lalgorithme utilis doit accomplir la
condition que larbre obtenu aprs leffacement soit toujours un
arbre de recherche. Dans ce cas, pour effacer un certain noeud,
on choisi, dans son sous-arbre gauche, le noeud avec le plus
grand clef. Ce noeud passe au lieu du noeud effac. Par exemple
si on veut effacer le noeud 8 de notre exemple, on choisira le plus
grand noeud du sous-arbre gauche, le noeud 7. Donc, le noeud
83
Structures de donnes et algorithmes
effac, 8, sera remplac par le noeud 7. Larbre de recherche
rsult sera:
Les structures de donnes que nous avons prsentes ont
une utilisation dans les systmes informatiques, gnralement, et
aussi dans la ralisation des algorithmes, particulirement.
Lorganisation des donnes, dont une principale tape est leur
structuration, est aussi importante que la programmation. Un
programme trs bien labor nobtiendra pas de rsultats dsirs
sil utilisera des structures inadquates et une structure
performante ne pourra pas suppler les carences du programme
qui lutilise.
Organiser les donnes signifie:
- dfinir, structurer, ordonner et grouper les donnes en
collections de donnes homognes;
- tablir les relations entre les donnes;
- reprsenter les donnes sur un support informationel,
afin quon peut les traiter dans un systme de calcul.
Les principaux objectifs poursuivis dans lorganisation
des donnes (donc aussi dans la cration des structures) sont:
- la ralisation dun temps minimal daccs aux donnes;
- lassiguration dun espace rduit occup par les
donnes dans la mmoire;
- lunicit des donnes (elles doivent apparaitre une seule
fois dans le systme);
- la flexibilit des donnes (elles doivent permettre le
changement de la structure et des relations dentrelles
84
Structures de donnes et algorithmes
sans modifier les programmes qui les utilisent dans
lapplication courante).
Dans le suivant chpitre, nous allons utiliser la plupart
des structures prsentes.
PROGRAMME ARBRES DE RECHERCHE
#include<iostream.h>
#include<stdio.h>
struct noeud
{int nr;
noeud *as, *ad;
};
noeud *v, *man;
2. ALGORITHMES
2.1. GNRALITS
Un algorithme est une procdure bien dfinie qui
reoit une valeur ou un ensemble de valeurs comme
donnes d'entre et produit une certaine valeur ou un
ensemble de valeurs comme donnes de sortie.
85
Structures de donnes et algorithmes
Les principaux proprits sollicites un algorithme
sont :
-qu'il soit bien dfini c'est--dire que les oprations
requises doivent tre rigoureusement spcifies, sans ambigut;
-qu'il soit trs exactement dcrit, afin qu'il puisse tre
ralis sur un ordinateur;
-qu'il soit effectif, c'est--dire qu'il finisse toujours aprs
l'excution d'un nombre fini de pas ;
-qu'il soit universel, c'est--dire qu'il permette la rsolution
d'une classe de problmes.
2.2 ANALYSE DES PERFORMANCES
DES ALGORITHMES
Dans l'valuation des performances d'un algorithme
interviennent deux facteurs :
-la dure d'excution de l'algorithme ;
-la dimension de la mmoire ncessaire pour l'excution
de l'algorithme.
On trouve encore ces deux facteurs sous les noms :
-complexit sequentielle de temps ;
-complexit spatiale.
Le plus important est, sans doute, le premier de ces deux
facteurs. On peut l'estimer par une grandeur dnomme ordre de
complexit, qui est le temps de calcul pour un certain algorithme,
note avec O(nombre estim d'excutions de l'opration de base).
Gnralement, une opration de base peut tre assimile une
instruction mais la requte primordiale est que le nombre
d'excutions d'une opration de base puisse tre calcul en
fonction de n , o n est la taille des donnes (le nombre de
composantes d'un vecteur, le nombre de valeurs lues au clavier
etc.).
86
Structures de donnes et algorithmes
La complexit de l'algorithme est O(f(n)) o f est
d'habitude une combinaison de polynmes, logarithmes ou
exponentielles. Ceci reprend la notation mathmatique classique,
et signifie que le nombre d'oprations effectues est born par
cf(n) ( o est une constante) lorsque n tend vers l'infini.
La considration du comportement l'infini de la
complexit est justifie par le fait que les donnes des
algorithmes sont de grande taille et qu'on se proccupe surtout de
la croissance de cette complexit en fonction de la taille des
donnes. Une question systmatique se poser est: que devient le
temps de calcul si on multiplie la taille des donnes par ?
Les algorithmes usuels peuvent tre classs en un certain
nombre de grandes classes de complexit.
Les algorithmes sub-linaires, dont la complexit est en
gnral O(log n). C'est le cas de la recherche d'un lment
dans un ensemble ordonn fini de cardinal .
Les algorithmes linaires de complexit O(n) ou O(nlog
n) sont considrs comme rapides, comme l'valuation de
la valeur d'une expression compose de symboles ou les
algorithmes optimaux de tri.
Plus lents sont les algorithmes de complexit situe entre
O(n
2
) et O(n
3
); c'est le cas de la multiplication des matrices
et du parcours dans les graphes.
Au del, les algorithmes polynomiaux en O(n
k
), pour
sont considrs comme lents, sans parler des
algorithmes exponentiels (dont la complexit est
suprieure tout polynme en n) que l'on s'accorde dire
impraticables ds que la taille des donnes est suprieure
quelques dizaines d'units.
La recherche de l'algorithme ayant la plus faible
complexit, pour rsoudre un problme donn, fait partie du
travail rgulier de l'informaticien.
87
Structures de donnes et algorithmes
D'habitude la complexit est un polynme et l'ordre de
complexit d'un polynme peut tre seulement la puissance
maximale du polynme. Par consquence, l'ordre de complexit
plynmiale a la forme O(n
k
) , o k est l'ordre du polynme.
Par exemple, si un algorithme peut effectuer n
2
+n+1
oprations, l'ordre de complexit est O(n
2
), ou, autrement dit,
l'algorithme a un temps d'excution carr.
Pour trouver le maximum (minimum) d'un vecteur, il
faut effectuer n comparaisons, donc l'ordre est O(n) ; l'algorithme
est linaire.
Un autre type d'ordre de complexit est celui
exponentiel : O(a
n
) ou O(n!). Par exemple, l'algorithme gnratif
des permutations a un ordre de complexit O(n!) .
Pratiquement, on admet seulement les algorithmes
polynmiaux. On n'admet pas les algorithmes exponentiels parce
que la fonction exponentielle crot rapidement ; ainsi, pour le
valeurs grandes du n , on peut arriver un temps infini.
Donc, on prfre les algorithmes polynmes mais pas
avec des grandes puissances du n . Dans O(n
k
), pour les grandes
valeurs de k, on peut obtenir des algorithmes non-penformants.
Pourtant, il y a des cas o on ne peut pas viter les algorithmes
exponentiels.
Le calcul de l'ordre de complexit est un problme
difficile qui ncssite des connaissances de mathmatiques trs
avances. Quand on ne russi pas calculer cet ordre, on peut
discuter les trois suivantes valeurs :
-le temps minimal de calcul
-le temps moyen de calcul
-le temps maximal de calcul.
Quand, pour un algorithme, on parle de temps estim ,
il faut prciser de quel temps s-agit-il (moyen, minimal ou
maximal). D'habitude, les plus importants sont le temps maximal
et le temps moyen de calcul et trs souvent on fait une analyse en
moyenne.
88
Structures de donnes et algorithmes
L'ordre de complexit prsente une grande importance
pour l'estimation des performances d'un algorithme. C'est pour a
que chaque problme doit commencer par la prsentation de cet
ordre. Dans cet ouvrage, nous essairons de prsenter l'ordre de
complexit aussi pour chaque problme particulier que pour le
cas gnral d'une mthode de programmation ( divide et
impera , greedy, backtracking etc.).
2.3 ALGORITHMES DE TRI ET DE
RECHERCHE
Les algorithmes de tri et de recherche sont les plus
analyss parce qu'il sont souvent utiliss dans : les bases de
donnes, compilateurs, interpreteurs, systmes d'exploitation etc.
2.3.1. Algorithmes de tri
Ces algorithmes excute le rangement des informations
du mme type dans une ordre ascendante ou descendante.
Il y a plusieures classes d'algorythmes de tri qui utilisent
trois mthodes gnrales :
-la permutation
-la slection
-l'insrtion.
2.3.1.1. Tri par permutation
Le plus connu de cette classe, cause de sa simplicit, est
le tri bulle. Les lments trier se comportent comme les bulles
d'air dans un verre plein d'eau, chacune cherchant son niveau
propre.
89
Structures de donnes et algorithmes
L'algorithme du tri bulle - ou bubble sort - consiste
regarder les diffrentes valeurs adjacentes d'un tableau, et les
permuter si le premier des deux lments est suprieur au second.
L'algorithme se droule ainsi : les deux premiers lments sont
compars, si le premier lment est suprieur au second, une
permutation est effectue. Ensuite, sont compars et
ventuellement permuts les valeurs 2 et 3, 3et 4 jusqu (n-1) et
n. Une fois cette tape acheve, il est certain que le dernier
lment du tableau est le plus grand. L'algorithme reprend donc
pour classer les (n-1) lments qui prcdent. L'algorithme se
termine quand il n'y a plus de permutations possibles. Pour
classer les n valeurs , il faut, au pire, effectuer l'algorithme n fois.
Cet algorithme porte le nom de tri bulle car, petit petit,
les plus grands lments du tableau remontent, par le jeu des
permutations, en fin de tableau. Dans un aquarium il en va de
mme : les plus grosses bulles remontent plus rapidement la
surface que les petites qui restent colls au fond.
Il existe plusieures variantes de cet algorithme :
-La premire consiste n'effectuer les comparaisons que
sur les lments du tableau qui ne sont pas remonts la surface.
Ainsi, si n est le nombre d'lments du tableau et p le nombre de
fois o le parcours complet du tableau a t effectu, a chaque
itration, seul les (n-p) premiers lments sont compars. Le gain
de temps apport par cette optimisation est d'ailleurs loin d'tre
ngligeable, c'est pourquoi une version de ce tri bulle optimis
est galement prsente.
Une autre variante du tri bulle, qui n'est pas trs
diffrente, consiste faire descendre les plus petites valeurs au
dbut du tableau. Dans ce cas, le tableau est parcouru, non plus
de gauche droite, mais de droite gauche. Dans sa version
optimise, ce sont les (n-p) derniers lments qui sont compars.
Cette variante est utilise pour implmenter le tri bulle dans le
cas de listes ou de piles.
90
Structures de donnes et algorithmes
-La seconde consiste reprendre au dbut chaque fois
qu'une permutation est dtecte. Ainsi, les plus petits et les plus
grands lments vont tout doucement migrer en dbut et en fin de
tableau. Cette version de l'algorithme est aussi connue sous le
nom de "tri Shaker" ou de "tri Shuttle".
Une autre version est le "tri Boustrophedon" ou
"bidirectionnel". Elle consiste parcourir le tableau de gauche
droite, puis de droite gauche, le changement de direction ayant
lieu chaque fois que l'une des extrmits est atteinte. Ainsi, les
plus petits lments du tableau descendent au mme rythme que
remontent les plus gros lments.
Exemple 1. Soit la file de nombres:
10 9 8 7 6 5 4 3 2 1.
On veut qu'elle soit ordonne de manire croissante:
10 9 8 7 6 5 4 3 2 1
Pas 1 9 10 10 10 10 10 10 10 10 10
8 7 6 5 4 3 2 1
Pas 2 8 9 9 9 9 9 9 9 9 10
7 6 5 4 3 2 1
Pas 3 7 8 8 8 8 8 8 8 9 10
6 5 4 3 2 1
Pas 4 6 7 7 7 7 7 7 8 9 10
5 4 3 2 1
Pas 5 5 6 6 6 6 6 6 6 6 6 7 8 9 10
4 3 2 1
Pas 6 4 5 5 5 5 6 7 8 9 10
3 2 1
Pas 7 3 4 4 4 4 4 5 6 7 8 9 10
2 1
Pas 8 2 3 3 4 5 6 7 8 9 10
1
Pas 9 1 2 3 4 5 6 7 8 9 10
Pas 10 1 2 3 4 5 6 7 8 9 10
91
Structures de donnes et algorithmes
Observons qu'on a fait dix parcours; dans le dernier il ny
avait plus de permutation. La suite tait ordonne. Considrons
la complexit, en nombre d'oprations du tri bulle, pour un
tableau ou une liste de n lments. Dans le pire des cas, ce qui
correspond une liste pralablement tri de manire
dcroissante, il y a des permutations jusqu' ce que la liste ait t
parcourue (n-1) fois. Dans le cas du tri bulle non optimis, cela
reviens faire (n-1) fois (n-1) comparaisons (et quelques
permutations). Soit une complexit proportionnelle (n-1)
2
=n
2
-
2n+1, soit en O(n
2
). C'est un algorithme assez inefficace pour
des grandes valeurs de n. Dans le cas du tri bule optimis, le
nombre de comparaisons est donn grace au calcul suivant:
la premire itration on fait (n-1) comparaisons.
la p-ime itration on fait (n-p) comparaisons.
Les comparaisons faites seront :


1
1
2
2 2
) (
n
p
n n
p n
Analyse en moyenne.Pour analyser un algorithme de tri,
c'est--dire dterminer le nombre moyen d'oprations qu'il
effectue, on utilise le modle des permutations. On suppose dans
ce modle que la file des nombres trier est la file des entiers
1,2,3.n et l'on admet que toutes les permutations de ces entiers
sont quiprobables. On peut noter que le nombre de
comparaisons effectuer pour un tri ne dpend pas des lments
trier mais de l'ordre dans lequel ils apparaissent. Les supposer
tous compris entre et n'est donc pas une hypothse restrictive
si on ne s'intresse qu' l'analyse et si l'on se place dans un
modle d'algorithme dont l'opration de base est la comparaison.
Pour une permutation de , une inversion est un
couple tel que et . Ainsi, la permutation:
92
Structures de donnes et algorithmes
comporte 21 inversions. Chaque change d'lments de la
procdure tri bulle supprime une et une seule inversion et, une
fois le tri termin, il n'y a plus aucune inversion. Ainsi le nombre
total d'changes effectus est gal au nombre d'inversions dans la
permutation. Calculer le nombre moyen d'changes dans la
procdure de tri bulle revient donc compter le nombre moyen
d'inversions de l'ensemble des permutations sur lments. Un
moyen de faire ce calcul consiste compter le nombre
d'inversions dans chaque permutation, faire la somme de tous
ces nombres et diviser par . Ceci est plutt fastidieux; une
remarque simple permet d'aller plus vite. L'image miroir de toute
permutation est la permutation
. Il est clair que est une inversion de
si et seulement si ce n'est pas une inversion de . La somme du
nombre d'inversions de et de celles de est . On
regroupe alors deux par deux les termes de la somme des
nombres d'inversions des permutations sur lments et on
obtient que le nombre moyen d'inversions sur l'ensemble des
permutations est donn par:
ce qui est donc le nombre moyen d'changes dans la procdure tri
bulle. On note toutefois que le nombre de comparaisons
effectues par tri bulle est le mme que celui de tri selection soit
.
Exemple :
Lvolution du tableau au fil de l'algorithme (en bleu, les
lments qui sont compars, et ventuellement premuts, pour
passer la ligne suivante).

5 3 1 2 6 4
3 5 1 2 6 4
3 1 5 2 6 4
3 1 2 5 6 4
93
Structures de donnes et algorithmes
3 1 2 5 6 4
3 1 2 5 4 6
1 3 2 5 4 6
1 2 3 5 4 6
1 2 3 5 4 6
1 2 3 4 5 6
L'algorithme se termine car il n'y a plus de permutations
possibles. Ce fait sera constat grace un dernier parcours du
tableau ou aucune permutation n'a lieu. Le tri bulle prsent peut
tre optimis en balayant les lments une fois de gauche droite
et la suivante fois de droite gauche.On nomme cet algorithme
tri bulle SHAKER,d'aprs l'instrument dans lequel on mlange
les boissons et qui est renvers de temps en temps.
Exemple: Pour la file de l'exemple prcdent, les pas
dans la mthode SHAKER sont :
10 9 8 7 6 5 4 3 2 1
Pas 1 9 10 10 10 10 10 10 10 10 10
8 7 6 5 4 3 2 1
Pas 2 1 1 1 1 1 1 1 1 1 10
9 8 7 6 5 4 3 2
Pas 3 1 8 9 9 9 9 9 9 9 10
7 6 5 4 3 2
Pas 4 1 2 2 2 2 2 2 2 9 10
8 7 6 5 4 3
Pas 5 1 2 7 8 8 8 8 8 9 10
6 5 4 3
Pas 6 1 2 3 3 3 3 4 8 9 10
7 6 5
Pas 7 1 2 3 6 7 7 7 8 9 10
5 4
Pas 8 1 2 3 4 4 4 5 7 8 9 10
6
Pas 9 1 2 3 4 5 6 7 8 9 10
Pas 10 1 2 3 4 5 6 7 8 9 10
Cette mthode a le mme ordre de complexit O(n
2
) mais,
pour certaines valeurs de n conduit un temps d'excution plus
petit.
Voici l'algorithme implment dans le programme:
94
Structures de donnes et algorithmes
PROGRAMME SHAKER
#include<conio.h>
#include<stdio.h>
typedef int vecteur [100];
void lirevect (int n, vecteur v)
{ int i ;
for(i=0 ; i<n; i++)
{printf(v[%d]=,I); scanf(%d,&v[I]);}}
void shaker (int n, vecteur v)
{int i ,t, k;
do{k=0 ;
for(i=0; i<=n-2; i++)
if (v[i+1]<v[i])
{ t=v[i]; v[i]+v[i+1]; v[i+1]=t;k=1;}}
void ecrire vect(int n, vecteur v)
{ int i ;
for(i=0 ; i<n ; i++)
printf(v[%d]=%d\n, i, v[i]);}
main( )
{int n; vecteur v;
clrscr( ) ; printf(n=); scanf(%d,&n);
lirevect (n,v) ;
shaker(n,v) ;
ecrirevect(n,v);}
2.3.1.2. Tri par slection
Le tri par slection dtermine au commencement
l'lment de rang minimal et le substitue au premier lment de
la suite ordonner. Puis, dans les (n-1) lments rests, est
dtermin de nouveau l'lment de rang minimal et plac sur la
deuxime position. Le procd continue jusqu' on ordonne
compltement la file.
Exemple :
95
Structures de donnes et algorithmes
Pour la file utilise dans les exemples prcdents, on
doit faire les suivants pas :
10 9 8 7 6 5 4 3 2 1
Pas 1 1 9 8 7 6 5 4 3 2 10
Pas 2 1 2 8 7 6 5 4 3 9 10
Pas 3 1 2 3 7 6 5 4 8 9 10
Pas 4 1 2 3 4 6 5 7 8 9 10
Pas 5 1 2 3 4 5 6 7 8 9 10
Observons qu'on excute un nombre plus petit de pas. La
mthode est meilleure mais conduit aussi un ordre de
complexit de O(n
2
) .
Voici une implmentation de la mthode SHAKER :
void select(int n, vecteur v)
{int i,j,c,t,k ;
for (i=0 ; i<n-1 ; ++i)
{k=0; c=i; t=v[i];
for (j=i+1; j<n; ++j)
{if(v[j]<t) { c=j; t=v[j]; k=1;}}
if(k) {v[c]=v[i]; v[i]=t;}}}
2.3.1.3 Tri par insertion
Le tri par insertion est le suivant algorithme :
D'abord on ordonne les deux premiers lments de la
suite. Puis on met le troisime lment dans la position dans
laquelle les trois lments sont ordonns. Ensuite on insre le
quatrime lment parmi les trois, de la manire que tous les
quatre soient ordonns. On continue de la mme manire jusqu'
l'insertion du dernier lment.
Pour l'exemple que nous avons choisi, les pas du
rangement sont les suivants :
96
Structures de donnes et algorithmes

Cet algorithme a aussi un ordre de complexit O(n
2
).
Soit une liste de n lments; pour mettre en oeuvre le tri
par insertion, il faut insrer, un un, (n-1) lments dans une
liste pralablement trie. Dans le pire des cas, cest--dire quand
la liste trier de manire croissante est classe de manire
dcroissante, pour insrer le p-ime lment, il faut dcaler les
(p-1) lments qui le prcdent. Soit une complexit totale, dans
le pire des cas, donne par la formule suivante :


n
p
n n
p
2
2
2 2
) 1 (
Cependant, en moyenne, seul la moiti des lments est
dcale. Soit un dcalage de (p-1) lments et donc une
complexit en moyenne qui se calcule ainsi :


n
p
n n p
2
2
4 4
)
2
1
2
(
Cette complexit est analogue la complexit du tri bulle
optimis et du tri par slection.
Mais le tri d'insertion prsente deux grands avantages :
10 9 8 7 6 5 4 3 2 1
Pas 1 9 10 8 7 6 5 4 3 2 1
Pas 2 8 9 10 7 6 5 4 3 2 1
Pas 3 7 8 9 10 6 5 4 3 2 1
Pas 4 6 7 8 9 10 5 4 3 2 1
Pas 5 5 6 7 8 9 10 4 3 2 1
Pas 6 4 5 6 7 8 9 10 3 2 1
Pas 7 3 4 5 6 7 8 9 10 2 1
Pas 8 2 3 4 5 6 7 8 9 10 1
Pas 9 1 2 3 4 5 6 7 8 9 10
97
Structures de donnes et algorithmes
-Il a un comportement naturel, c'est--dire le volume de
calcul est petit pour une suite d'lments deja ordonne et un
volume de calcul grand pour une suite de donnes en ordre
invers. C'est pour a que l'algorithme s'applique bien pour une
suite de donnes presqu'en ordre.
-Il prsente la conservation de l'ordre des lments, c'est-
-dire si une suite d'lments est range d'apres deux critres diff
rents, aprs l'application le la mthode d'insertion la suite restera
ordonn d'aprs tous les deux critres.
Voici l'implmentation du tri d'insertion :
PROGRAMME INSERTION
void insert (int n, vecteur v)
{int i, j, t, ;
for (i=1 ; i<n ; ++i)
{t=v[i];
for(j=i-1; j>=0 && t<v[j];j--)
v[j+1]=v[j];
v[j+i]=t;}}
2.3.1.3.1. Le tri SHELL
Tous les algorithmes prsents jusqu'ici ont le
dsavantage d'avoir un ordre de complexit car, O(n
2
). Pour une
grande taille de donnes, l'algorithme devient trop lent,
quelquefois conduisant aux temps d'excution inadmissibles. Le
tri SHELL est un tri suprieur, ayant un ordre de complexit
O(n
1,2
). Il porte le nom de son crateur D.L.Shell.
Cet algorithme consiste en les suivants pas :
pas 1 on ordonne tous les lments situs la distance
de trois positions ;
pas 2 - on ordonne tous les lments situs la
distance de deux positions ;
pas 3 - on ordonne tous les lments voisines.
98
Structures de donnes et algorithmes
Voyons maintenant cet algorithme appliqu ntre
exemple :

L'implmentation de cet algorithme reste comme thme
pour l'tude individuel.
2.3.1.3.2. Le tri rapide (Hoare)
Le tri rapide a t propos par C.A.R. Hoare, raison pour
laquelle il est dnomm le tri HOARE. Il est l'un des meilleur tri
connus. Le principe de fonctionnement est celui de la
permutation. Le procd consiste dans la slection d'une valeur
quelconque, nome pivot ou comparand, qui va diviser la liste en
deux parties. La premire partie contiendra tous les lments
infrieurs ou gaux au comparand, tandis que la seconde partie
contiendra tous les autres. On applique puis la mme opration
ces deux parties jusqu' l'ordonnation totale des lments.
10 9 8 7 6 5 4 3 2 1
Pas 1 7 5 8 10
4
3 9
2
10
1
6 9 10 3
pos.
Pas 2 4 3 2 7
1
5 8 7 6 9 10
Pas 3 1 3 2 4 5 8 7 6 9 10
Pas 4 1 3 2 4 5 8
6
7 8 9 10 2
pos.
Pas 5 1 3
2
3 4 5 6 7 8 9 10 1
pos.
99
Structures de donnes et algorithmes
Cette mthode fait partie de la mthode de
programmation DIVIDE ET IMPERA que nous allons tudier
dans le chapitre Mthodes d'laboration des algorithmes.
La valeur du pivot peut tre choisie en deux modes :
-de manire alatoire ;
-comme moyenne d'un sous-ensemble de valeurs de la
suite initiale ;
-pour simplifier, le milieu de l'intervalle, comme dans
l'implmentation suivante.
Pour le tri HOARE nous avons choisi une implmentation
rcursive :
PROGRAMME HOARE
void qs(vecteur v,int gauche, int droite)
{int i, j, x, y ;
i=gauche ; j=droite ; x=v[(gauche
+droite)/2] ;
do{
while(v[i]<x && i<droite) i++ ;
while (x<v[j] && j>gauche) j--;
if(i<=j) {x=v[i] ; v[i]=v[j] ;v[j]=y ;i++ ;
j--;}}
while(i<=j)
if(gauche<j) qs(v,gauche,j);
if(droite>i) qs(v,i,droite)}
void rapide(int n, vecteur v)
{qs(v,0,n-1) ;}
2.3.2. Algoritmes de recherche
On organise l'information dans les bases de donnes de
manire qu'on permette un utilisateur de localiser un article par
la simple introduction d'un mot-clef.
Il y a des mthodes de recherche diffrentes pour les
listes ordonnes et pour les listes dsordonnes.
100
Structures de donnes et algorithmes
Avec les donnes organises en tableaux, on peut aussi
faire des tables. Une table contient des informations sur certaines
cls. Par exemple, la table peut tre un annuaire tlphonique.
Les cls sont les noms des abonns. L'information rechercher
est le numro de tlphone. Une table est donc un ensemble de
paires (nom, numero). Il y a plusieurs manires d'organiser cette
table: un tableau d'enregistrement, une liste ou un arbre (comme
nous le verrons plus tard). Pour l'instant, nous supposons la table
dcrite par deux tableaux, nom et tel, indics en parallle, le
numro de tlphone de nom[i] tant tel[i]. Un exemple
de recherche en table:
nom tel
paul 2811
roger 4501
laure 2701
anne 2702
pierre 2805
yves 2806

La premire mthode pour rechercher un numro de tlphone
est une recherche squentielle (ou linaire). On examine
successivement tous les lments de la table et on regarde si on
trouve un abonn du nom voulu. La recherche squentielle est la
plus simple mthode et signifie la recherche d'un lment parmis
tous les lments de la liste. Elle s'applique aux listes
dsordonnes.
Voici l'implmentation d'une fonction qui cherche un
nombre dans le vecteur v et retourne les positions sur
lesquelles elle trouve ce nombre. Si elle ne le trouve pas,
retourne (-1).
cherchevaleur(vecteur v, int c)
{int i, j;
for(i=0;i<=n-1;i++)
if(c= =v[i]) {j++;return t;}
101
Structures de donnes et algorithmes
if(j!=0) return 1;}
Pour les listes deja ordones on utilise une recherche
binaire. Cette mthode est de type DIVIDE ET IMPERA.
On teste chaque fois l'lment qui se trouve au milieu de
la liste. S'il est plus grande que l'lment recherch, on testera le
milieu de l'intervalle gauche, si non, on va tester le milieu de
l'intervalle droite. Le procd va tre continu jusqu'on trouve
l'lment cherch.
Nous allons implmenter maintenant la variante non-
rcursive et, dans le cadre de la mthode DIVIDE ET IMPERA,
nous prsenterons une mthode rcursive.
PROGRAMME RECHERCHE BINAIRE
recherchebin(vecteur v, int c)
{(int min, max, med, cont ;
min=0; max=cont-1;
while(min<=max)
{med=(min+max)/2;
if(c<v[med]) max=med-1;
else
if(c>v[med]) min=med+1
else
return med;}
return 1;}
2.4. MTHODES D'LABORATION DES
ALGORITHMES
2.4.1. La mthode DIVIDE ET IMPERA
La mthode DIVIDE ET IMPERA est base sur un
principe extrmement simple: on dcompose le problme en deux
ou plusieurs sous-problmes qu'on peut aisment rsoudre ; la
solution de la problme initiale est obtenue par la combinaison
des solutions de ces sous-problmes. Le procd est repris pour
102
Structures de donnes et algorithmes
chaque sous-problme, jusqu'on arrive aux problmes avec des
solutions imdiates. On peut rsoudre un petit nombre de cas par
cette mthode, parce qu'il faut que la dcomposition soit possible.
L'implmentation de cette technique est presque toujours
rcursive.
Maintenant, nous allons prsenter quelques applications
de cette mthodes, beaucoup d'elles clasiques.
2.4.1.1 La recherche binaire
Un vecteur v[n] est ordonn ascendent. Si un nombre
nrest trouv parmis les lments du vecteur, crivez l'indice de
cet lment.
L'algorithme est :
- si nr=v[(i+j)/2] alors c'est la solution
- si (i<j) il-y-a deux possibilits :
nr<v[(i+j)/2] s'apple la fonction avec
les paramtres i et (i+j)/2)-1
nr>v[(i+j)/2] s'apple la fonction avec
les paramtres (i+j)/2)+1 et j
PROGRAMME RECHERCHE BINAIRE
#include <stdio.h>
#include <conio.h>
int v[100],n,nr,m=0;
void recherchebin(int i, int j)
{if(nr= =v[(i+j)/2])
{printf(trouve indice %d, (i+j)/2); m=1}
else
if(i<j)
if (nr<v[(i+j)/2] recherche (i,(i+j)/21);
else
recherche ( (i+j)/2+1, j)
main ( )
{(int j;
clrscr ( );
103
Structures de donnes et algorithmes
printf(n=); scanf(%d,&n);
for(j=1 ; j<njj++)
{printf(v[%d]=,j); scanf(%d,&v[j]);
printf(nr=); scanf(%d,&nr)
recherchebin(1,n);
if nr= =0 printf(pas trouve) ;}
2.4.1.2. Les tours de Hanoi
Soient trois tiges symbolises par a,b,c. Sur la tige a on
trouve des disques diffrents diamtres, placs dans une ordre
dcroissante regards de bas en haut. On demande de transporter
les disques de la tige a sur la tige b, en utilisant comme
intermdiaire la tige c et en respectant les suivantes rgles :
- chaque pas on doit transporter un seul disque ;
- il n'est pas permis de poser un disque avec un diamtre
plus grand sur un disque avec le diamtre plus petit.
Solution :
- Si n=1, on transporte le seul disque de la tige a sur la
tige b, donc on fait le mouvement ab .
- Si n=2, on fait les mouvements ac, ab, ac.
- Si n>2, conformment la stratgie DIVIDE ET
IMPERA, on essaye de dcomposer le problme en
deux sous-problmes du mme type, en continuant,
puis, avec la combinaison de leurs solutions.
Le transport de ces n disques de la tige a sur la tige b,
par la tige intermdiaire c , est quivalent avec :
- le transport de (n-1) disques de la tige a sur la tige
c, utilisant comme tige intermdiaire la tige b ;
- le transport du disque rest, sur la tige b ;
- le transport de (n-1) disques de la tige c sur la tige b
utilisant comme tige intermdiaire la tige a.
Ces trois tapes permettent de dfinir une fonction
rcursive H(n,a,b,c), ainsi :
104
Structures de donnes et algorithmes
H(n,a,b,c)=

'

>

1 , , , 1 ( , ), , , , 1 (
1
n si a b c n H ab b c a n H
n si ab

Pour n=2,
H(2,a,b,c)=H(1,a,c,b),ab,H(1,c,b,a)=ac,ab,cb

Pour n=3,
H(3,a,b,c)=H(2,a,c,b),ab,H(2,c,b,a)=
=H(1,a,b,c,),ac,H(1,b,c,a),ab,H(1,c,a,b),cb,H(
1,a,b,c)=ab,ac,bc,ab,ca,cb,ab

Voici l'implmentation de ce problme:
#include<stdio.h>
#include<conio.h>
char a,b,c; int n;
void han (int n,char a,char b,char c)
{if(n= =1) printf(%c%c\n,a,b);getch( );
else
{han(n-1,a,c,b);
printf(%c %c\n,a,b); getch( );}
han(n-1,c,b,a);}}
main( )
{clrscr( );
printf(n=); scanf(%d,7n);
a=a; b=b; c=c;
han(n,a,b,c);}
2.4.1.3 La solution approximative d'une quation,
dans un intervalle donn.
Cette mthode peut tre applique seulement aux
quations qui ont une seule racine relle dans l'intervalle [ab].
On part de la consquence du thorme de Darboux qui
dmontre que l'quation a au moin une racine relle dans
l'intervalle [a,b] si f(a).f(b) <0. L'algorithme applique la
105
Structures de donnes et algorithmes
mthode de la moiti de l'intervalle et puis il cherche l'intervalle
o se trouve la solution.
Si m=(a+b)/2, on calcule le signe des expressions
f(a).f(m) et f(m).f(b). Si, par exemple, f(a).f(m)<0, on
prend la moiti de l'intervalle (a,m). Le procd continue
jusqu'on arrive la prcision desir. La solution est le milieu de
l'intervalle o on a arrt l'itration.
Exemple: Trouvez, avec une aproche donne, la solution
de l'quation x
5
+x-1 , en sachant qu'elle admet une solution dans
l'intervalle (0,1).
Vraiment, nous avons f(0)=-1, f(1)=1,
f(0).f(1)<0, donc l'quation a une solution dans cet intervalle.
La solution est unique, parce que f''(x)=5x
4
=1>0 , f(x) est
croissante, f(-)<0 , f(+)>0, donc la fonction a un seul
point d'intersection avec l'axe Ox, dans l'intervalle (0,1). Reste
voir le mode dans lequel la racine calcule par ce programme
approche la racine relle. Il y a plusieures possibilites . La plus
simple est de chercher la moiti de l'intervalle. Plus on fait cette
opration plusieures fois, plus l'approche sera meilleure. Une
autre mthode est de calculer la longueur du dernier intervalle
dans la recherche de la solution et si cette longueur est infrieure
un nombre initialement donn (nomm prcision ), l'algorithme
s'arrte. Pour l'implmentation, nous avons choisi cette dernire
solution.
Nous avons not avec min et max les bouts de l'intervalle
(au commencement min=0 et max=1). L'talon est la prcision
voulue. Dans ce cas, l'itration n, la longueur de intervalle est
(max-min)/2
n
. Donc, le programme s'arrte quand
(1/2
n
)<talon.
PROGRAMME QUATION
#include <stdio.h>
#include <conio.h>
main( )
double max, min, racine=0,5, pre=1,etalon;
106
Structures de donnes et algorithmes
min=0 ; max=1; racine=(max+min)/2 ;
printf(la precision est);
scanf(%lf ,&etalon);
while(pre>etalon)
{if((min*min*min*min*min+min-1)*
(racine*racine*racine*racine*racine+
racine-1))<0
max=racine ;
else
racine=(max+min)/2 ; pre=pre*0,5 ;
printf(racine est%ef, racine);}
2.4.1.4. Le problme des incisions
On donne une tle de longueur l et hauteur h, ayant sur
sa surface n trous de coordonnes nombres entiers. On
demande de dcouper d'elle un morceau de maxime aire qui ne
prsente pas des trous.
Solution:
Les coordonnes des trous sont retenues dans deux
vecteurs xv et yv. Le rectangle initiel et les rectangles coups
sont mmoriss par les coordonnes du coin gauche en haut
(x,y), par la longueur (l) et par la hauteur (h).
Pour un rectangle, on vrifie s'il y a ou non un trou sur sa
surface. S'il existe, on fait une coupure verticale et une coupure
horizontale par le trou. On choisi, de ces quatre rectangles, le
morceau avec l'aire maximale et qui n'a pas des trous. Ce
morceau est retenu est, puis, compar avec les autres morceaux
obtenus par la mme mthode. On observe que, dans ce cas, la
technique DIVIDE ET IMPERA spare le problme donn en
quatre sous-problmes.
Le rectangle de maximale aire, sans trous, est mmoris
par les mmes paramtres que les le rectangle avec des trous,
dans xf, yf, lf, hf.
Le rectangle avec un trou:
107
Structures de donnes et algorithmes
Pour se situer dans l'intrieur du rectangle, le trou doit
satisfaire simultanment les conditions :
1) xv[i]>x
2) xv[i]<x+l
3) yv[i]>y
4) yv[i]>y+h
Si on fait une incision verticale par le trou, on obtient
deux rectangles :
2) x,y, xv[i]-x,h;
3) xv[i], y, 1+x-xv[i],h
Si on fait une incision horizontale, les rectangles sont:
1) x,y,l,yv[i]-y
2) x,yv[i],l, h+y-yv[i]
PROGRAME INCISIONS
#include<stdio.h>
#include<conio.h>
int l,h,i,n,xf,yf,lf,hf,xv[10],yv[10];
void rectangle(int x,int y, int l, int h,
int &x-l, int &yf)
int lf, int &hf, int xv[10], int yv[10];
{int trouve=0, i=1;
while(i<=n && !trouve)
if(xv[i]>x && xv[i]<l
&& yv[i] >y && yv[i]<y+h)
trouve=1;
else
if(trouve)
rectangle(x,y,xv[i]-x, h, xf, yf, lf,
hf, xv,yv);
rectangle(xv[i],y,l+x-xv[i],
h,xf,yf,lf,hf,xv,yv);
108
xv[i],yv[j]
Structures de donnes et algorithmes
rectangle(x,y,l,yv[i]-y,xf,yf,lf,hf,xv,yv);
rectangle(x,yv[i],l,h+y-yv[i],
xf,yf,lf,hf,xv,yv);}
else
if(l*h>lf*hf)
{xf=x; yf=y;
lf=1 ; hf=h ; }}
main( )
{printf(n=; scanf(%d, &n) ;
for(int i=1 ; i<=n; i++)
{printf(xv(%d)=,i); scanf(%d,&xv[i]);
printf(yv(%d)=,i); scanf(%d, &yv[i])}
printf(l=); scanf(%d,&l);
printf(h=); scanf(%d,&h);
rectangle(0,0,l,h,xf,yf,lf,hf,xv,yv);
printf(hf=); printf(lf=; lf);
printf(xf=;xf); printf(yf=; yf);}
2.4.1.5.-Devination dun nombre
laborez un programme qui doit deviner un nombre
propos par l'oprateur. Le programme utilisera la mthode
DIVIDE ET IMPERA . Il va calculer la moiti de l'intervalle et
va proposer ce nombre l'oprateur qui rpondra avec 1 si le
nombre propos est suprieur celui choisi, avec 2 s'il est
infrieur et avec 0 s'il est le nombre choisi.
Solution:
Le programme est de type recherche binaire. Le passage
dans l'un de ces deux intervalles est dtermin par la rponse de
l'oprateur. On prendra seulement 10000 nombres dans le
programme.
Exemple:
L'oprateur a choisi le nombre 100. Voici le dialogue:
Programme Oprateur
5000 1
2500 1
109
Structures de donnes et algorithmes
1250 1
625 1
313 1
156 1
78 2
102 1
85 1
93 1
97 1
99 1
100 0
2.4.1. La mthode GREEDY (GOURMAND)
Soit un ensemble A avec n lments. La mthode
GREEDY consiste dans la cration d'un sous-ensemble B de
l'ensemble A. Chaque lment du B est choisi en considrant un
optimum local. Autrement dit, on choisi un lment de
l'ensemble A et, s'il correspond un bien dfini optimum local,
on l'ajoute au sous-ensemble B ; s'il n'accompli pas les conditions
poses, il ne sera pas choisi et on passera au suivant lment.
C'est pour a que la mthode GREEDY est denomme la
mthode de l'optimum local .
Observations :
1) Chaque fois quand on labore un algorithme
Greedy, il faut dmontrer mathmatiquement qu'il conduit une
solution finale optimale; l'optimum local ne conduit pas
obligatoirement un optimum final.
2) Il-y-a des problmes qui admettent un Greedy
euristique ( qui a une utilitit dans la dcouverte scientifique ou
autre). Cela signifie que, bien qu'on a appliqu l'optimum local
pour chaque pas, la solution gnrale n'est pas optimale. On
admet ces algorithmes euristiques pour les problmes qui n'ont
pas des autres solutions.
110
Structures de donnes et algorithmes
3) L'ordre de complexit des algorithmes
GREEDY est polynmial, donc ils sont d'une assez haute
performance.
4) Souvent il est ncessaire que les lments de
l'ensemble A soit ordonns au commencement.
Nous allons tudier des applications bases sur le choix
de type GREEDY.
2.4.2.1. Planification des spectacles
C'est un problme classique de type GREEDY qui admet
aussi bien des clones ( problmes avec des solutions semblables).
Dans une salle, dans un jour, il faut planifier n
spectacles. Pour chaque spectacle on connat l'heure de dbut et
l'heure de l'achvement. On demande de planifier un nombre
maximal de spectacles, condition qu'ils ne soient superposs.
Solution :
L'algoritme de type GREEDY a les suivants pas :
-On fait un rangement ascendent des spctacles, d'apres
leur heure d'achvement.
-Le premier spctacle de cette liste est choisi (donc celui
qui se termine le premier).
-On choisi le suivant spctacle qui commence apres la fin
du premier. La condition est que l'heure du commencement du
spctacle (i+1) soit suprieure l'heure d'achvement du
spctacle (i). Cette condition est, en fait, le choix GREEDY.
On cherche parmis les suivants spctacles le premier qui
accomplisse cette condition.
Exemple :
Le
spctacle
Lheure
du dbut
Lheure de
lachvement
1 8
30
9
45
2 9
00
11
00
3 8
45
10
30
111
Structures de donnes et algorithmes
4 10
00
12
00
5 9
30
12
30
6 10
45
11
30
7 14
00
19
00
8 15
00
20
00
9 17
00
18
45
10 18
00
18
30
On ordonne les spctacles selon l'heure d'achvement:
Le
spctacle
L'heure du
dbut
L'heure de
l'achvement
Choix
CREDY
1 8
30
9
45
Choisi
3 8
45
10
30
2 9
00
11
00
6 10
45
11
30
Choisi
4 10
00
12
00
5 9
30
12
30
10 18
00
18
30
Choisi
9 17
00
18
45
7 14
00
19
00
8 15
00
20
00
Conformment l'algorithme on a choisi trois spctacles:
S1, S6, S10.
PROGRAMME SPCTACLES
#include<stdio.h>
#include <conio.h>
int s[2] [10], o[10],n,i,h1,m1,h2,m2,heure;
void ordonne( )
{int pret, m,i;
do{pret=1;
for(i=1;i<=n; -1; I++
112
Structures de donnes et algorithmes
if(s[i][o[i])>s[i][o(i+1]])
{ m=o[i]; o[i]=o[i+1]; o[i+1]=m; pret=0;}
while(!pret);}
main ( )
{clrscrc();
printf(n=); scanf(%d, &n);
for(i=1; i<=n ;i++)
{o[i]=i;
printf(lheure du debut\n);
printf(heure); scanf(%d,&h1) ;
printf(minutes); scanf(%d,&m1);
s[0][i] =h1*60+m1;
printf(l'heure d'achevement) ;
print(heure); scanf(%d, &h2);
printf(minutes); scanf(%d, &m2);
s[1][i]=h2*60+m2;}
ordonne ( );
printf(l'ordre des spectacles est);
printf(%d , o[1]);
heure=s[i][o[i];
for (i=2; i< =n; i++)
{if(s[o][o[i])>=heure)
{printf(%d\n, o[i]);
heure=s[i][o[i]);}}}

2.4.2.2.-Le problme du havresac (continu)
Quelqu'un a un havresac avec lequel on peut transporter
un poids maximal G. La personne dispose de n objets et connat
pour chaque objet son poids (g
i
) et le gain (c
i
) quon obtient par
son transport. On demande de prciser quels sont les objets
quon doit transporter afin que le gain soit maximal.
Observation. On permet de couper les objets. Cest pour
a quon dnomme ce problme continu. Il y a aussi un
problme discret du havresac, dans lequel on ne peut pas couper
les objets. Ce dernier problme sera tudi la programmation
linaire.
113
Structures de donnes et algorithmes
Solution :
Lalgorithme GREEDY pour le problme du havresac a
les suivants pas :
- On calcule, pour chaque objet, lefficience du transport,
en divisant le gain par le poids.
- On range les objets de manire dcroissante de
lefficience du transport.
- On charge le havresac avec les objets, dans lordre
descendente de lefficience du transport, sans dpasser la
capacit maximale G du havresac.
- Quand on arrive un objet dont la charge porterait au
dpassement du G, on coupe seulement la partie qui complte le
poids jusqu la valeur G.
Exemple :
Objet Poids Gain Efficience
1 10 30 3
2 5 20 4
3 2 50 25
4 3 21 7
5 4 32 8
6 2 4 2
7 10 100 10
8 15 90 6
G=30 (la capacit du havresac)
On range les objets dans lordre descendente de leur
efficience et on remplit le havresac jusquau poids G :
Objet Poids Gain Efficience Poids
total
dans le
havresac
Objet choisi
3 2 50 25 2 Choisi
7 10 100 10 12 Choisi
5 4 32 8 16 Choisi
4 3 21 7 19 Choisi
8 15 90 6 30 Choisi coup
(seulement 11
units de poids)
2 5 20 4 Non choisi
1 10 30 3 Non choisi
114
Structures de donnes et algorithmes
6 2 4 2 Non choisi
PROGRAMME HAVRESAC
#include<stdio.h>
#include<conio.h>
double c[30], g[30], ef[30], gr,man,profit ;
int n, i, man1, inv, ord[30];
main( )
{clrscr( );
printf(poids maximal=); scanf(%d, &gv);
printf(nombres objets=); scanf(%d, &n);
for(i=1; i<=n ; i++)
{printf(c[%d]=, i); scanf(%d, &c[i]);
printf(g[%d]=, i); scanf(%d, &g[i]);
ord[i]=i; ef[i]=c[i]/g[i];}
do
{inv=0;
for(i=1; i<n; i=)
if(ef[i]<ef[i+1])
{ man=ef[i]; ef[i]=ef[i+1]; ef[i+1]=man;
man=c[i]; c[i]=c[i+1]; c[i+1]=man;
man=g[i]; g[i]=g[i+1]; g[i+1]=man; inv=1;
man 1 = ord[i]; ord[i]=ord[i+1];
ord[i+1]=man1;}}
while(inv);
i=1;
while(gv>0 && i<=n)
{ if(gv>g[i])
{ printf(objet); printf(%d\n, ord [i]);
gv= =g[i]; profit + = +c[i];}
else
{ printf(objet); printf(%d\n, ord[i);
profit + = c[i]*gv/g[i];
gv=0; } i++};
printf(profit total est); printf(%d,
profit);}
2.4.2.3.- Calcul rapid de la puissance dun nombre
115
Structures de donnes et algorithmes
Pour a et n donns, ( a

N , n

N), on demande
de calculer a
n
par la formule :
( )
( )

'

1 2
2
2
2
k n pour a a
k n pour a
a
k
k
n

Solution :
Cest un exemple de GREEDY euristique. On ne connat
pas un algorithme polynmial qui puisse assurer un nombre
minimal de multiplications. Cet algorithme de type GREEDY
rduit considrablement le nombre des multiplications.
Pour utiliser la fomule il faut la transformer dans une
relation de rcurence. On peut ecrire :
( )
( )

'

1 2
2
2
2
k n pour a a
k n pour a
a
k
k
n
Si on note :
) , ( n a f a
n

alors :

'

1 2 ) 1 , (
2 )
2
, (
) , (
2
k n pour n a af
k n pour
n
a f
n a f
Par exemple, pour n=20 :
20 16 4 16 16 4 16 4
8 4 4 4 4 2
1 ) 0 , ( ) 1 , (
) 2 , ( ) 4 , ( ) 5 , ( ) 10 , ( ) 20 , (
a a a a f a a a f a
a f a a f a a f a f a f


On observe que, au lieu de 19 multiplications, on fait seulement
6.
116
Structures de donnes et algorithmes
PROGRAMME MULTIPLICATION RAPIDE
#include <stdio.h>
long alan (long a, long n)
{ long prod=1, i=0;
while (n)
{ if (n%2{prod*=a; n- =1; i++;}
else { a=a*a; n/=2; i++;}}
printf(%ld\n,i);
return n ; }
int main( )
{long n,a:
printf(a=); scanf(%ld, &a);
printf(n=); scanf(%ld, &n);
printf(%ld, alan(a,n));}
2.4.2.4.-Les ennemis
Un groupe est form de n personnes. Chaque personne
peut avoir seulement trois ennemis qui sont connus.
videmment, si i est lennemi de j, j est aussi lennemi de i.
On demande de diviser le goupe initial en deux ensembles
disjoints dans lesquels, en un ensemble une personne ait tout au
plus un ennemi.
Solution:
Le problme a toujours une solution. Cette chose doit tre
dmontre.
Lalgorithme est de type GREEDY. On part avec deux
initiaux ensembles : un ensemble vide et un ensemble de n
personnes. On passe dans le premier ensemble toutes les
personnes qui ont 2 ou 3 ennemis. Il faut dmontrer que
lalgorithme est fini.
Exemple:
Soit n=6 et 1,2,3,4,5,6 les six personnes. Les ennemis de
chaque personne sont:
117
Structures de donnes et algorithmes
2 1 1 1 2 3
1 3 2 4 3 5 4 2 5 3 6 4
4 5 6 6 6 5
Gr. I Gr.II Obs.
- 1 2 3 4 5 6 1, avec trois ennemis,
passe dans le group I
1 2 3 4 5 6 2, avec deux ennemis,
passe dans le goupe I
1 2 3 4 5 6 3, avec deux ennemis,
passe dans le groupe I
1 2 3 4 5 6 6, avec deux ennemis,
passedans le groupe I
1 2 3 6 4 5 1,avec deux ennemis,
passe dans le groupeII
2 3 6 1 4 5
Donc, si on forme les deux groupes : 2,3,6 et 1,4,5,
personne na pas deux ou trois ennemis dans le mme groupe.
Implmentation :
On choisi une matrice, m[100] [100], dans laquelle
lindice de ligne est le nombre de la personne et lindice de
colonne est le nombre de lennemi de la personne.
Pour lexemple prcdent, avec n=6 et les ennemis
prsents, la matrice est :
1 2 3 4 5 6
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 1
5 1 1 1
6 1 1 1
118
Structures de donnes et algorithmes
Observons que m[i][j]=m[j][i], donc la matrice est
symtrique.
Les deux groupes seront mmoriss dans un vecteur v[n]
, (pour notre exemple n=6), o :

'

II groupe au apartient i si
I groupe au apartient i si
i v
2
1
] [
Pour notre exemple, la fin, le vecteur v[i] a les
suivantes composantes: v[1]=2, v[2]=1, v[3]=1, v[4]=2,
v[5]=2, v[6]=1.
On construit aussi une fonction change( ) qui assure le
passage dune personne dun groupe dans lautre.
PROGRAMME ENNEMIS

#include <stdio.h)
int m[100],v[100],n ;
int f(int k)
{int i, s=0;
for(i=1; i< =n; i++)
if(i!=k)
if(v[i]= =v[k])
if(m[i][k]) s++;
return s; }
int change( )
{ int i,j;
for(i=1; i< = n; i++)
if(v[i]= =1)
if(f(i)>1)
{ v[i]=2;
return1;}
for(i=1; i< =n; i++)
if(v[i]= =2)
{ v[i]=1;
return1;}
return 0;}
main( )
{int i,j, nre, h;
119
Structures de donnes et algorithmes
printf(n=); scanf (%d, &n);
for(i=1 ; i< =n ; i++)
{printf(nombre dennemis pour
une personne %d, i);
scanf(%d, &nre);
for(j=1; j<nre; j++)
{ scanf(%d, &h); m[i][h]=1;}}
for(i=1; i<n; i++)
v[i]=1;
while(change( ) );
for(i=1; i< =n; i++)
printf(%d\n, v[i]; }
Cet algorithme est de complexit O(n
2
).
2.4.2.5. Polygone convexe
On lit les coordonnes rales de n points du plan.
Dcidez si ces n points peuvent former un polygone convexe.
Dans le cas affirmatif, listez les points dans une ordre qui permet
de trasser le polygone convexe. En cas ngatif, spcifiez quon
ne peut pas former un polygone convexe.
Solution :
Un polygone est convexe sil est situ tout entier du
mme ct de toute droite portante lun de ses cts.
Soit deux sommets conscutifs, de coordonnes (x
k
,y
k
)
et (x
i
, y
i
), et la droite qui les unissent Ax+By+C=0 ; la
condition que ces deux sommets fassent partie dun polygone
convexe est :
Ax
j
+By
j
+c doit avoir un signe constant pour

j[1,n] avec j i,j k,


o j reprsente les autres n-2 sommets.
Lalgorithme est le suivant :
-On part dun point arbitraire (i).
-On cherche parmis les autres n-1 points un point
(j)pour lequel la droite (i,j) a de mme ct tous les autres
120
Structures de donnes et algorithmes
n-2 points. Si un tel point nexiste pas, le problme na pas de
solution. Sil existe, alors on choisi le point i comme faisant
partie du polygone.
-Le procd continue jusquon a slct tous les n points,
si le problme a solution, ou jusquon ne trouve plus un point
avec la proprit requise, quand le problme na pas de solution.
2.4.3. La mthode backtracking
(Arrire cheminement)
Variante standard
On utilise cette mthode quand nous avons n
ensembles, A
1
, A
2
, ..A
n
, et nous intressent les solutions de
la forme x
1
x
2
x
3
x
n
, o x
i

A
i
, pour i =
n ...... 1
. Dans la
plupart des cas les ensembles A
1
, A
2
, A
3
,.A
n
concident.
Pour ce type de problme, on pourrait appliquer la
mthode de la force brute qui signifie: engendrer tous les
lments du produit cartesien A
1
xA
2
xA
3
xA
n
et tester chaque
lment s'il est une solution ou non. Cette mthode conduit aux
temps d'excution pratiquement infinis. C'est pour a que,
d'habitude, elle ne s'applique pas.
La mthode backtracking ( arrire cheminement) utilise,
pour l'obtention des solutions, une pile controle par deux
paramtres :
-le niveau k de la pile, k ayant des valeurs de 1 n ;
-la valeur pl(k) du niveau k de la pile.
La mthode consiste dans la construction d'un vecteur
dans la pile :
x
1
,x
2
,x
3
x
n
o x
k
appartient au niveau k de la
pile et
pl(k), d'habitude, a
i
k=
n ......... 1
121
Structures de donnes et algorithmes
Pour la construction de ce vecteur, on teste une certaine
valeur sur un niveau de la pile et, si elle est valide, on passe au
niveau suprieur, en testant une autre valeur. Si cette dernire
n'est pas valide, on essaie une autre valeur. Si cette nouvelle
valeur n'est pas valide , on essaie des autres, et si on ne trouve
pas une valeur valide, on descend sur le niveau infrieur de la
pile pour chercher une autre solution. Au moment o on est
arriv sur le dernier niveau de la pile, n, avec une solution valide,
on imprime tout le vecteur stock sur la pile. Gnralement, la
mthode cherche des solution en haut et en bas de la pile, ce qui
explique son nom.
D'habitude, on utilise une routine spcifique qui appelle
des fonctions standard. Celui qui rsout un problme doit crire
explicitement, pour ce problme, les fonctions appeles par la
routine backtracking.
Cette routine a la suivante forme :
void arriere ( )
{ int as ;
k=1; init( );
while (k>0)
{ do ( )
while ( (as=successeur ( ) && ! valid( );
if(as)
if(solution) print ( );
else {k++; init ( ); }
alse k--; }}
Cette routine contient 5 fonctions:
int() est la fonction qui initialise un niveau de la pile; on
le fait, d'habitude, avec zero.
solution() est la fonction qui teste si on est arriv ou
non la solution finale.
print() imprime quand existe une solution. Cette
fonction imprimera la solution, c'est dire toutes les valeurs de la
pile.
122
Structures de donnes et algorithmes
successeur() teste si, sur un certain niveau de la pile,
existe un successeur. En cas affirmatif retourne 1, en cas ngatif
retourne 0.
valid() teste si un lment d'un niveau de la pile
accomplit les conditions imposes par le problme, donc s'il est
valide. S'il est valide la fonction retourne 1, si non, elle retourne
0. Bienentendu, si un lment est valide, il est retenu sur la pile et
on passe au suivant niveau.
Observons qu'on fait le mouvement en haut et an bas dans
la pile avec la routine arrire() et la slection et la validation
des lments avec les autres fonctions.
Le problme d'un programmeur en backtracking est
d'crire de nouveau les cinq fonctions pour chaque application.
Dans la plupart des cas , les fonctions int( ), solution( ),
et print( ) restent inchanges. Il faut changer seulement les
fonctions successeur( ) et valide( ) chaque application.
Pour crire un programme en backtracking il faut :
- tablir le rle des variables spcifiques k et pl(k),
variables globales, dans le contexte donn du
problme ; on constate que parfois une seule pile ne
suffit pas mais il faut utiliser une pile double ou triple ;
dans nos applications nous utiliserons une seule pile ;
- crire les fonctions spcifiques pour le problme,
surtout les fonctions successeur( ) et valide ( ).
Observations :
1)Le temps de rsoudre un problme de type backtracking
est trs grand. On utilise cette mthode seulement quand il
n'existe pas un autre algorithme plus efficient.
2)La mthode donne toutes les solutions d'une problme
mais, quelquefois, une seule solution est ncessaire et alors on
arrte la routine aprs l'obtention d'une solution.
123
Structures de donnes et algorithmes
3)Cette routine a t crite en variante itrative, pas
rcursive, par raisons didactiques, pour une meilleure
comprhension du mcanisme du backtracking.
4)Bien que nous avons appris que la structure de type pile
peut tre exploite seulement par les instructions push et pop,
pour les applications en backtracking on adresse tous les niveaux
de la pile.
Ci desous nous prsenterons quelques applicatons de la
mthode backtracking.
2.4.3.1. Les permutations d'un ensemble n
lments.
Engendrez toutes les permutations dun ensemble de n
nombres.
Solution :
En ce cas, le niveau k est reprsent par le nombre d'ordre
d'un lment et pl[k] l'lment mme.
Pour n=6, une solution sur la pile a la forme suivante :

k=6 4 pl[6]=4
k=5 5 pl[5]=5
k=4 6 pl[4]=6
k=3 2 pl[3]=2
k=2 3 pl[2]=3
k=1 1 pl[1]=1
Nous allons crire toutes les cinq fonctions pour cette
application.
void int ( )
{pl[k]=0 ;}
Chaque valeur d'un niveau est
initialise zero.
124
Structures de donnes et algorithmes
int solution( )
{return k= =n ;}
On retourne le niveau de la pile
o on est arriv.
void print( )
{for (int i=1 ; i< = n; i+
+)
printf(pl[%d]=%d\n, i,
pl[I])}
On affiche toutes les valeurs de la
pile, du premier au dernier niveau,
la pile tant traite, pour cette
fonction, comme un vecteur.
int successeur( )
{ if(pl[k]<n)
{pl[k]++; return 1:}
else
return 0;}
Pour un certain niveau k, si on
n'est pas arriv la dernire
valeur n, cela signifie qu'il y a un
succeseur et on retourne 1 ; en
mme temps on incrmente la
valeur sur la pile. Si on est arriv
la dernire valeur, a signifie
qu'il n'y a plus de succeseur et on
retourne 0.
int valid( )
{for (int i=1 ; i<k ; i++)
if (pl[i]= =pl[k]) return
0;
return 1;}
La condition de validit d'une
solution, dans le cas des
permutations, est qu'il ne soient
pas deux valeurs identiques sur
des niveaux diffrents de la pile.
Ci-desous on donne un programme complet. Pour les
autres applications on crira seulement les fonctions qui diffrent
de celles du programme permutations.
PROGRAMME PERMUTATIONS
#include <stdio.h>
#include <conio.h>
int pl[50],n,k;
void init( )
{ pl[k]=0;}
int solution( )
{return k= =n;}
void print( )
{for (int i=1; i< =n; i++)
125
Structures de donnes et algorithmes
printf(pl[%d]=%d\n, i, pl[i]);}
int valid( )
{for(int i=1; i<k; i++)
if(pl[i]= =pl[k]) return 0;
return 1;}
int succeseur ( )
{if(pl[k]<n)
{pl[k]++; return 1}
else
return 0; }
void arriere( )
int as;
k=1; init( );
while(k>0)
{do( )
while((as=successeur( )&&!valid( ));
if(as)
if(solution) print( );
else{k++; init( );}
else k--;}}
main( )
clrscr( );
{printf(n=); scanf(%d, &n);
arriere( );}
Pour mieux comprendre le mcanisme backtracking,
voyons comment volue la pile jusqu' une solution, dans le cas
de ce programme, avec n=3.
k=1 ;
int( ) fait pl[1]=0
succeseur( ) fait pl[1]++, donc
pl[1]=1
Parce que l'lment choisi est valide, on sort de
la boucle do while.
126
0
1
Structures de donnes et algorithmes
Ce n'est pas une solution finale, on fait k++,
donc k=2
init( ) fait pl[2]=0
successeur( ) fait pl[2]++, donc
pl[2]=1
Cette solution n'est pas valide
(pl[1]=pl[2]=1), donc on reste dans la boucle
do while.
On parcourt de nouveau la boucle do while
succeseur( ) fait pl[2]++, donc
pl[2]=2
Cette solution est valide, donc on sort de la
boucle do while.
Cette solution n'est pas finale, donc on ne
l'imprime pas.
On fait k++, donc k=3
La fonction init( ) fait pl[3]=0
On entre dans la boucle do while.
succeseur( ) fait pl[3]++, donc
pl[3]=1
Ce n'est pas un lment valide, donc on reste
dans la boucle.
succeseur( ) fait pl[3]++, donc pl[3]=2
Ce n'est pas un lment valide, donc on reste
dans la boucle.
succeseur( ) fait pl[3]++, donc pl[3]=3
C'est un lment valide, donc on sort de la boucle
do while. On imprime cette solution.
Puis on fait k--, donc k=2
On entre de nouveau dans la boucle do while.
succeseur( ) fait pl[2]++, donc pl[2]=3
C'est un lment valide, donc on sort de la
boucle.
127
0
1
1
1
2
1
0
2
1
1
2
1
2
2
1
3
2
1
3
1
Structures de donnes et algorithmes
Ce n'est pas une solution, donc on fait k++, c'est
dire k=3
init( ) fait pl[3]=0
On entre de nouveau dans la boucle do while
succeseur( ) fait pl[3]++, donc pl[3]=1
Ce n'est pas un lment valide, donc on reste
dans la boucle.
succeseur( ) fait pl[3]++, donc pl[3]=2
C'est un lment valide, donc on sort de la
boucle.
On imprime cette solution.
2.4.3.2. Les sous-ensembles de p lments d'un
ensemble avec n lments (p

n).
Engendrez tous les sous-ensembles de p lments d'un
ensemble avec n lments (pn). Donc, formez toutes le
combinaisons de n objets pris p.
Solution: Si n=6 et p=5,
' 5
6
C
=6,on doit engendrer 6 sous-
ensembles : 12345
12346
12356
12456
13456
23456
Comme dans le problme des permutations, le niveau k
represente le nombre d'un lment et pl(k) est l'lment
respectif.
Nous allons rsoudre le problme par backtracking ;
crivons toutes le fonctions, pour cette application :
128
0
3
1
1
3
1
2
3
1
Structures de donnes et algorithmes
void init( )
{if(k>1)
pl[k]=pl[k-1] ;
else
pl[k]=0;}
Sur le niveau 1 on initialise avec 0 .
Sur les autres niveaux l'initialisaton
consiste en copier la valeur du niveau
antrieur.
int successeur()
{if(pl[k]<n-p+k)
{pl[k]++;return1;}
else
return 0;}
On engendre tous les lments
infrieurs n-p+k
int valid( )
{return 1 ;}
Par le mode dont on a cr les
fonctions init( ) et succeseur(),
chaque nouveau lment est valide,
donc la fonction valid(), dans ce cas,
ne doit tre construite. Pourtant, pour
oprer en manire standardise,nous la
consrvons.
Les fonctions print() et solution() sont les mmes quau
problme prcdent.
2.4.3.3. Le problme des n reines
Soit un chiquier de dimensions n x n . On demande
toutes les solutions de rangement des n reines, ainsi que les
reines ne s'attaquent pas entr'elle (il faut que deux reines ne se
trouve pas sur la mme ligne, colonne ou diagonale).
Pour n=4, une solution serait :
X
X
X
X
129
Structures de donnes et algorithmes
Afin de rsoudre ce problme par backtracking, nous choisirons
une matrice (n x n) dans laquelle les lignes sont reprsentes
par le niveau k de la pile et les colonnes par les pl[k]. Toutes les
fonctions restent les mmes que celles des permutations,
l'exception de la fonction valid( ) qui doit tre rconstruite.
Pour la matrice (4 x 4), nous avons une solution :

p[1] pl[2] pl[3] pl[4]
1 X
2 X
3 X
4 X

avec la solution sur la pile :
pl[4] 3 4
pl[3] 1 3
pl[2] 4 2
pl[1] 2 1
pl[k] k
La condition pour que les reines ne soient pas sur la mme ligne
est obtenue automatiquement ; la condition pour qu'elles ne
soient pas sur la mme colonne est :
pl[i]

pl[k] pour k

i
et la condition que les deux reines ne soient pas sur la mme
diagonale est :
] [ ] [ k pl i pl k i
La fonction valid( ) aura la suivante forme :
valid( )
{ for(int i=1 ; i<k ; i++)
if(pl[k]= =pl[i]||abs(pl[k]-pl[i])= =abs(k-i))
return 0;
return 1;}
130
Structures de donnes et algorithmes
2.4.3.4. Le problme de la coloration des cartes
On donne n pays sur une carte et on demande toutes les
solutions de colorier la carte, avec mximum 4 couleurs, ainsi que
deux pays avec commune frontire soient coloris de faon
diffrente. La carte est fournie au programme l'aide d'une
matrice M[n][n] o :
[ ] [ ]

'

j pays le avec frontiere commune pas a n i pays le si


j pays le avec frontiere commune a i pays le si
j i M
' 0
1
La matrice M[n][n] est symtrique.
Exemple

,
_

0 1 1 1 0 0
1 0 1 0 0 1
1 1 0 1 1 1
1 0 1 0 1 0
0 0 1 1 0 1
0 1 1 0 1 0

131



Structures de donnes et algorithmes

sent
par le pays k
- pl[k] est sent par la couleur du pays k
videmment :
pl[k]={1,2,3,4}
1kn , kN
On change dans le programme permutations seulement la
fonction valid( ):
int valid( )
{ for (int i=1 ; i< =k-1; i++)
if( pl[i]= =pl[k] && m[i][k]= =1) return 0;
return1;}
2.4.3.5. Le problme du commis voyageur
Un commis voyageur doit visiter n villes. Il faut qu'il
parte de la ville 1, qu'il passe par chaque ville une seule fois, qu'il
ne laisse pas des villes non-visites et qu'il retourne dans la ville
1. Imprimez tous les chemins possibles pour le commis
voyageur.
Les liaisons entre les villes sont donnes par la matrice
m(n)(n) ainsi :

'

j et i villes les entre route e un pas a y n il s


j et i villes les entre route e un a y il s
j i m
' ' 0
' 1
) )( (

132
Structures de donnes et algorithmes
:

133



Structures de donnes et algorithmes

,
_

0 1 1 0 0 0 1 1
1 0 0 1 1 1 0 0
1 0 0 1 0 0 0 1
0 1 1 0 1 0 0 0
0 1 0 1 0 1 0 0
0 1 0 0 1 0 1 0
1 0 0 0 0 1 0 1
1 0 1 0 0 0 1 0

valid() :
134
Structures de donnes et algorithmes
int valid()
{if(!m[pl[k-1]][pl[k]])return 0
else
for(int i=1 ;i<=k-1 ;i++)
if(pl[i]==pl[k]) return 0;
if(k==n && !a[i][pl[k]] return 0;
return 1 ;}
solution d'une cuation, en
nombres naturels

tre
reprsent par pl[k] et k est le nombre dinconnues.
Dans ntre cas nous choisissons :
pl[i]=x pl[2]=y pl[3]=z et k=3
On doit crire de nouveau la fonction valid( )
On impose la condition :
pl[1]+pl[2]+pl[3]+pl[1]*pl[2]*pl[3]=54
me des
tandards
Prcisez tous les drapeaux tricolores quon peut projeter
avec 6 couleurs (blanc, jaune, vert, bleu, rouge, noir) si les
suivantes conditions sont accomplis simultanment :
-que les couleurs dun drapeau soient distinctes ;
135
Structures de donnes et algorithmes
-dans le milieu du drapeau on ne peut avoir blanc, jaune
ou rouge ;
-sur un drapeau il ne faut pas coexister les couleurs rouge
et noir, vert et jaune, blanc et bleu.
Solution
Le niveau de la pile est k, le nombre des couleurs sur un
drapeau est n (n=3).
pl[k] reprsente la couleur. pl[k] ={1,2,3,4,5,6},
chaque nombre reprsente une couleur.

'crire de nouveau les fonctions


typises de la routine backtracking. Mais, souvent, le temps
d'excution de ces programmes est pratiquement infini. Pour
diminuer ce temps, on utilise une
mthode

canisme de chercher en avant et en arrire. La majorit des


programmes qui travaille en backtracking non-standard sont
rcursives.
136
Structures de donnes et algorithmes
Nous allons prsenter ci-desous quelques applications
classiques du backtracking non-standard.
2.4.4.1. Engendrement des partitions d'un nombre
naturel
Affichez, pour un nombre naturel n , tous les modes de
dcomposition

Exemple:

er une fonction
partition (k,m), dans laquelle le paramtre k est le niveau
de la pile et le paramtre m controlera la valeur d'un niveau.
Au commencement, on apelle partition(1,n). Puis, de
la valeur qui se trouve sur un niveau, pl[k], on soustrait, l'une
aprs l'autre, les valeurs 1,2,3pl[k-1], valeurs avec
lesquelles on apelle la fonction pour le suivant niveau. Quand on
revient, on refait la valeur existente. Donc, on peut dire que, tant
donn un niveau quelconque, on imprime le vecteur et puis on
soustrait toutes les valeurs possibles jusqu'on arrive 1. Avec ces
valeurs, la fonction est appele de nouveau. Quand on revient, il
faut refaire la valeur, pour excuter correctement la soustraction
suivante.
PROGRAMME PARTITIONS NOMBRE
#include <stdio.h>
#include <conio.h>
int pl[50],n; clrser( );
void prin(int k)
{for (int i=1; i<=k; i++)
137
Structures de donnes et algorithmes
printf(pl[%d]=%d, i, pl[i]);
void partition (int k,int m)
{int i;
pl[k]=m; print(k);
for(i=1; i<=pl[k]-1; i++)
{pl[k]=pl[k]-1; partition(k+1,i);pl[k]=pl[k]-
i;}}
main( )
{printf(n=); scanf(%d, &n);
partition(1,n);}
2.4.4.2.Remplissage d'une surface ferme
On donne une matrice qui a seulement des lments 0
et 1. Supposons qu'il y a une surface d'lments 0 entoure
d'lments 1. Les lments 0 reprsentent une surface ferme.
En partant d'un point 0 , on demande de remplir cette surface
avec des lments 1. Cet algorithme este dnomm FILL.
Exemple
Soit la matrice M[5][8] o la suface ferme de 0 est
entoure par des lments 1.
0 0 1 1 1 1 1 1
1 0 1 0 0 0 0 0
1 1 1 1 1 0 0 0
0 1 0 0 0 0 0 0
1 1 1 0 0 0 1 1
En partant d'un point de la surface, par exemple M[2][4],
on remplira toute la portion avec 1. Aprs le remplissage, la
matrice sera:

138
Structures de donnes et algorithmes

,
_

0 0 1 1 1 1 1 1
1 0 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1

'une surface quand on connait les cordonnes d'un point de


l'intrieur.
L'algorithme utilise une fonction rcursive pour tester
l'lment qui on est arriv. S'il est 0, le transforme en 1, s'il est
1, on sort de la fonction. Puis, la fonction est autoapelle pour
chaque lment voisin (en haut, en bas, droite, gauche). Afin
qu'on ne fasse trop le teste de sortie de la matrice, on la borde
avec une ligne en haut, une ligne en bas, une collone droite e
une collone gauche, toutes avec des lments 1.
PROGRAMME FILL
#include<stdio.h>
#include<conio.h>
typedefni nt matrice100][100]
void fill (int a, int b,matrice m)
{if (m[a][b]= =0)
{m[a][b]=1;
fill(a+1,b,m);
fill(a,b+1,m);
fill(a-1,b,m);
fill(a,b-1,m);
void lirematrice(int c, int d, matrice m)
{int i,j;
for(i=1;i<=c;i++)
for(j=1;j<=d;j++)
{printf(m[%d][%d]=,i,j);
139
Structures de donnes et algorithmes
scanf(%d\n,&m[i][j])}}
void ecrire matrice(int c,int d,matrice m
int i,j
{printf(m[%d][%d]=%d
void bord(int c,int d, matrice m)
int i
for(i=1;i<=d;i++)
{m[0][i]=1;m[c+1][i]=1;}
for(i=1;i<=c;i++)
{m[i][0]=1;m[i][d+1]=1;}}
main()
{matrice m;
int c,d;
printf(nombre de lignes;scanf(%d,&c);
printf(nombre de colonnes;scanf(%d,&d);
lire matrice(c,d,m)
bord(c,d,m)
fill(c,d,m)
ecrire matrice (c,d,m)

e
de cubes rangs en n niveaux, ainsi qu'un cube s'appuie sur
deux cubes du niveau infrieur. Le nombre des cubes est
n(n+1)/2. On lit n(n+1)/2 nombres naturels et on demande de
les poser dans les cubes, condition que le nombre trouv dans
un cube soit la somme des nombre situs dans les deux cubes sur
lesquels il sappuie.
Exemple
Pour n=5, [n(n+1)/2]=15
Les quinze nombre sont:
50,100,50,5,5,0,10,10,15,25,25,25,15
140
Structures de donnes et algorithmes
Obsrvation: sur le dernier niveau on peut mettre
quelconque nombre.

1 0 0
5 0 5 0
2 5 2 5 2 5
1 0 1 0 1 5 1 5
5 5 1 0
0 1 5

Si on ne peut pas former une telle pyramide, on donne un
message correspondant.
Solution: Les nombres seront tris de manire
dcroissante, sparment dans un vecteur. La pyramide sera une
pile avec n niveaux. On va crer une fonction qui posera les
nombres sur chaque niveau, avec les conditons:
-Les cubes de la pyramide seront complts d'en haut en
bas, en mettant sur le niveau n, le suprieur, le plus grand
nombre.
-Sur les niveaux infrieurs on choisira les nombres de la
suite dcroissante, en respctant la condition que le nombre dans
un cube soit la somme des nombres situs dans les cubes sur
lesquels il sappuie.
-On fera la slection des nombres sur un niveau avec la
technique backtracking.
2.4.4.4. Problme de la photographie blanc/noir
Soit une photo spcifie par une matrice quadratique avec
les lments 0 et 1 ( 0 pour les points blancs et 1 pour les points
noirs). On considre le fond blanc et les objets noirs et si deux
points noirs sont voisins sur une ligne, colonne ou diagonale, ils
141
Structures de donnes et algorithmes
appartiennent au mme objet. On demande de prciser combien
d'objets apparaissent sur la photo.
Exemples:
Dans cette photo apparait un seul objet:
0 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 0 0
0 1 0 1 0 1

1 1 0 0 1 0
1 1 0 1 0 1
0 0 0 0 0 0
1 0 0 0 1 1
0 1 0 0 1 1
0 0 1 0 1 1

droite et gauche, cette fois


avec 0, pour ne pas sortir de la matrice.
On va crer une fonction rcursive, comme au FILL, mais
cette fois elle cherchera 8 points, pas 4 points, parce que il y a
aussi des voisins sur la diagonale.
142
Structures de donnes et algorithmes
Quand on revient de la fonction, on incrmente un
compteur dobjets. Puis la fonction cherchera un autre objet en
incrmentant de nouveau le compteur.
2.4.5. Programmation dynamique
La programmation dynamique est une mthode de
rsoudre des problmes dont les solutions sont construites
dynamiquement, en temps. Son initiateur est Richard Bellman,
professeur aux plusieurs universits amricaines.
Cest un procs de dcision en tapes. Dans la premire
tape on prend une dcision qui dtermine un nouveau tat du
problme, dans lequel on prend une nouvelle dcision et puis on
continue de cette manire.
Le terme dynamique se rfre la dpendance de temps
des tapes.
Pour rsoudre un problme, il faut tablir certaines choses:
-tablir ltape initiale, pour un procs decisional
descendent;
-tablir ltape finale, pour un procs dcisional ascendent;
-tablir la rgle de passer dune tape lautre; dhabitude
cette rgle est exprime par une relation de rcurrence;
-tablir une structure de donnes dans laquelle on
construira la solution, pas pas; la structure de donnes est
ressemblente celle du problme: vecteur, matrice, liste, pile etc.
On peut dire que les solutions obtenues par la mthode de
programmation dynamique sont, gnralement, bases sur la
ralisation dune optimisation; on trouve une suite optimale de
transformations, conformment au critre qui nous intresse.
Lexprience et lintuition du programmeur ont ici beaucoup
dimportance.
143
Structures de donnes et algorithmes
Nous prsenterons ci-dessous quelques problmes
classiques de programmation dynamique. On mettra laccent sur
le mode de construire la relation de rcurrence. Proprement dit,
crire cette relation signifie rsoudre le problme, tout le reste
ntant que limplmentation dans le language. Ainsi, dans tous
les exemples, nous avons prsent la relation de rcurrence;
quelquefois il y a aussi limplmentation dans le language.
2.4.5.1. Le problme du triangle
On considre un triangle de nombres dans lequel sur la
premire ligne apparait un nombre, sur la deuxime ligne
apparaissent deux nombres et sur la n-ime ligne appraissent n
nombres.
On demande de dterminer le maximum de la somme
forme de n nombre, un de chaque ligne, en commenant den
haut. Chaque nombre a un successeur dans la suivante ligne,
dessous ou en diagonale droite.
Exemple:
Soit le suivant triangle cinq lignes:
10
3 9
6 5 1
2 8 4 5
5 3 9 6 7
Le maximum dune telle somme sera 10+9+5+8+9=41
Solution: On observe quon peut former 2
n-1
sommes de ce
genre. Lalgorithme pour calculer cette somme serait dune trs
longue dure. Donc on utilisira la programmation dynamique. Si
le triangle initiel a une matrice A, nous allons construire une
autre matrice B daprs la relation de rcurrence:
B[i][j]=max{A[i][j]+B[i+1][j],
144
Structures de donnes et algorithmes
A[i][j]+B[i+1][j+1]}
o i{1,2,3,n-1}
j{1,2,3.i}
Pour notre exemple, on construira la matrice B ligne aprs ligne:
Ligne 5 :
La ligne 5 de la matrice b est la ligne 5 de la matrice A.
5 3 9 6 7
Ligne 4 :
B[4][1] =max{2+5, 2+3}=7
B[4][2] =max{8+3, 8+9}=17
B[4][3] =max{4+9, 4+6}=13
B[4][4] =max{5+6, 5+7}=12
Ligne 3 :
B[3][1]=max{6+7, 6+17}=23
B[3][2]=max{5+17, 5+13}=22
B[3][3]=max{1+13, 1+12}=14
Ligne 2 :
B[2][1]=max{3+23, 3+22}=26
B[2][2]=max{10+26, 10+31}=41
Donc, la matrice a les composantes :
41
26 31
23 22 14
7 17 13 12
5 3 9 6 7
La somme maximale se trouve dans llment
B[1][1]=41.
PROGRAMME TRIANGLE
#include<stdio.h>
#include<conio.h>
145
Structures de donnes et algorithmes
int a[50][50], b[50][50], route[50][50], n,
i, j;
main( )
{printf(n=); scanf(%d, &n);
for(i=1; i<=n; i++);
for(j=1; j<=i; j++);
{printf(a[%d][%d]=, i, j,); scanf(%d,
&a{i][j]);}
for(j=1; j<=n; j++) b[n][]j]=a[n][j]/* on
copie la derniere ligne de la matrice a dans
b*/
for(i=n-1; i>=1; i--)
{for(j=1; j<=i; j++)
if b{i+1][j]<b[i+1][j+1]
{b[i][j]=a[i][j]+b[i+1][j+1]; route[i]
{j]=j+1;}
else
{b[i]][j]=a[i][j]+b[i+1][j]; route[i][j]=j;}}
printf(la somme maximale est %d\n, b[i]
[1]};
for(i=1; j=1; i<=n; i++)
{printf(%d\n, a[i][j]; j=route[i][j];}
/*le vecteur route memorise tous les nombres
qui participent a la somme maximale, etant
affiches par ce dernier for*/}
2.4.5.2. La variante discrte du havresac
Nous avons vu, la mthode Greedy, la solution pour la
variante continue du problme de havresac, cest--dire quand
les objets peuvent tre coups. La variante discrte du havresac,
quand les objets ne peuvent pas tre coups, est une application
typique de la programmation dynamique.
Avec un havresac de capacit G on doit transporter n
objets pour lesquels on connait le poids et le gain obtenu par son
transport. Le nombre des objets est illimit. Combien dobjets il
faut choisir afin que le gain soit maximale?
146
Structures de donnes et algorithmes
Exemple :
Type
dobjet
1 2 3
Poids 3 4 3
Gain 2 3 8
La capacit du havresac, G=8.
Les objets de type 1,2,3 sont en nombre illimit.
On observe que, dans ce cas, on ne peut prendre que deux objets ;
pour trois objets on dpasse la capacit G=8. Les possibilits
sont :
Objet Objet Gain
1 2 5
1 3 10
2 3 11
1 1 4
2 2 6
3 3 8
On observe que le gain maximal est 8, quand on
transporte deux objets de type 3.
Solution :
Nous utiliserons deux vecteurs :
CHOIX [G=1]
PROFIT[G+1]
Au commencement ils sont 0.
La logique de mmorisation dans ces vecteurs est la
suivante :
- Si CHOIX[j]=K, alors la capacit K retient lobjet K et
les objets retenus de la capacit : j-g[k].
- Si PROFIT[j]=1, alors le transport des objets retenus
de la capacit j apporte un gain 1.
Nous aurons :
Pour i, entre 1 et n objets.
Pour j, entre 1 et G unit capacit.
Si lobjet i entre dans la capacit j, alors (j-g[i])0
147
Structures de donnes et algorithmes
Si le chargement de lobjet i dans la capacit j conduit
un gain plus grand :
profit[j]<profit[j-g[i]+c[i]
Alors on actualise les donnes.
La capacit j retient aussi lobjet i. (CHOIX[j-g]=i)
Le nouveau gain est obtenu par le chargement du i :
profit[j-g[i]]+c[i].
Lvolution du vecteur dans lexemple considr :
i=1
lindice 0 1 2 3 4 5 6 7 8
CHOIX 0 0 0 1 1 1 1 1 1
PROFIT 0 0 0 2 2 2 4 4 4
i=2
lindice 1 2 3 4 5 6 7 8
CHOIX 0 0 1 2 2 1 2 2
PROFIT 0 0 2 3 3 4 5 6
i=3
lindice 1 2 3 4 5 6 7 8
CHOIX 0 0 3 3 3 3 3 3
PROFIT 0 0 8 8 8 16 16 16
On imprime 3, pour CHOIX[8]=3 ; lobjet 3 a le poids 3,
donc reste la capacit 8-3=5, PROFIT[5]=3, reste la capacit
5-3=2 et lalgorithme finit. Le gain est de 16.
PROGRAMME HAVRESAC DISCRETE
#include<stdio.h>
int c[10],g[10], profit[10000], choix[10000],
g, n, ob;
{int i j ;
printf(n=); scanf(%d ,&n);
for(i=1 ; i<=n ; i++)
{printf(poids; scanf(%d,&g[i]);
printf(profit); scanf(%d,&c[i]);}
printf(G=; scanf(%d,&G);
148
Structures de donnes et algorithmes
for(i=1,i<=n; i++)
{for(j=1; j<=G; j++)
if(j-g[i])>0)
if(profit[j]<profit[j-g[i] )+c[i] )
{profit[j]=profit[j-[j-g[i] ]+c[i];
choix[j]=i;}}
printf(profit maximale %d,profit[G];
i=G; ob=choix[i];
while(i && ob)
{printf(objet numero %d\n, ob);
i- =g[ob]; ob=choix[i];}}
2.4.5.3. La plus grande file ascendente dun vecteur
On considre un vecteur avec n lments nombres
entiers. Imprimez la plus longue sous-file ascendente du vecteur.
Exemple:
Pour n=8 on donne le vecteur v=5,4,3,6,8,9,1,20.
La longueur maximale dune file ascendente est 5. Par exemple
5,6,8,9,20.
Solution: Lide est de calculer, pour chaque lment, la
longueur de la plus longue sous-file ascendente quon peut
former en commenant avec celui-ci. On commence avec le
dernier lment du vecteur et on finit avec le premier. Pour
chaque nouveau lment choisi, la longueur de la sous-file peut
crotre avec une unit ou peut rester la mme. la fin, on
choisira le maximun de toutes ces longueurs.
Pour limplmentation, on choisira un vecteur a[n] avec
la mme longueur, dans lequel la composante a[i] reprsente la
longueur maximale de la file ascendente commenant avec v[i].
Pour notre exemple, les lments du vecteur sont:
a[8]=1 (un seul lment a la longueur 1)
a[7]=2 ( v[7]<a[8] ) donc la longueur ++
a[6]=2 ( v[6]>a[7] )
a[5]=3 ( v[5]<a[6] ) donc la longueur ++
a[4]=4 ( v[4]<a[5] ) donc la longueur ++
149
Structures de donnes et algorithmes
a[3]=5 ( v[3]<a[4] ) donc la longueur ++
a[2]=5 ( v[2]>a[3] )
a[1]=5 ( v[1]>a[2] )
la fin on choisira le maximum dentre ces lments,
cest dire 5.
La construction du vecteur a[n] est simple :
[ ]
[ ] [ ]

'

+ + + +

1 ) 1 (
1
i a i a si i a
n i si
n a
Pour lister cette sous-file on procde de la suivante
manire:
- On cherche le maximum et lindice o se trouve ce
maximum dans le vecteur a[n] ; on affiche ce
maximum.
- On trouve et on imprime le premier lment egal ou
plus grand que ce maximum.
- Le processus continue jusquon puise tous les
lments de la sous-file.
PROGRAMME FILE ASCENDENTE
#include<stdio.h>
#include <conio.h>
typedef int vecteur[1000] ;
void lirevect(int n, vecteur v)
{int i ;
for(i=1 ; i<=n ; i++)
{printf(v[%d]=\n,i);scanf(%d, &v[i] )}}
main( )
vecteur v,a;
int n,i,k,max,t ;
printf(n=); scanf)(%d,&n);
a[n]=1;
for(k=n-1; k>1;k--)
{max=0;
150
Structures de donnes et algorithmes
for(i=k+1;i<=n; i++)
if( v[i]>=v[k]&& a[i]>max)
max=a[i];
a[k]=max+1;}
max=a[i]; t=1;
for(k=1; k<=n; k++)
if(a[k]>max)
{max=a[k]; t=k;}
printf(longueur maximale est %d, max);
for(i=t+1;i<=n; i++)
if(v[i]>v[t] && a[i]= =max-1)
{printf(%d, v[i] ); max--;}}
2.4.5.4.Le problme des parenthses; la multiplication
optimale dune file de matrices.
Montrons dabord que, si on doit multiplier un nombre de
matrices, le nombre de multiplications lmentaires dpend du
mode de mettre les parentheses, en tenant compte que la
multiplication des matrices est associative.
Si on multiplie les matrices A[n,m]xB[m,k] le nombre
de multiplications lmentaires est n x m x k
Par exemple:
A[10,1]xB[1,10]xC[10,1]xD[1,10]
Si on multiplie en ordre naturelle, le rsultat sera:
A[10,1]xB[1,10]=E[10,10]
1x10x10=100multiplications
E[10,10]xC[10,1]=F[10,1]
10x10=100mutiplications
F[10,1]xD[1,10]=G[10,10]
1x10x10=100multiplications
Total 300 multiplications
Si on met des parenthses, une possibilit serait :
( (Ax(BxC)xD)
B[1,10]xC[10,1]=E[1,1] 1x10x1=10 multiplications
A[10,1]xE]1,1]=F[10,1] 10x1x1=10 multiplications
151
Structures de donnes et algorithmes
F[10,1]xD[1,10]=G[10,10] 10x1x10=100multiplications
Total =120 multiplications
Un problme trs intressant apparat: quel est le mode de
mettre les parenthses ainsi que le nombre de multiplications
lmentaires soit minimal.
Solution :
Pour rsoudre le probme on choisi deux structures de
donnes :
- Le vecteur DIMENSION[n+1] qui retient le nombre de
lignes et de colonnes des matrices multiplier. Pour
lexemple prcdent :
A[10,1]xB[1,10]xC[10,1]xD[1,10]
ce vecteur, DIMENSION[5], est 10,1,10,1,10.
- Une matrice A[n][n], dans laquelle A[i][j], i<j,
reprsente le nombre minimal de multiplications pour
effectuer le produit des matrices A
i
x.xA
j
.
Dans la matrice A il y a les suivantes relations :
1)A[i][j]=0 ;
2)A[i][i+1]=DIM[i] x DIM[i+1] x DIM[i+1];
3)A[i][j]=min{A[i][k]+A[k+1][k]
+DIM[i]xDIM[k+1]xDIM[j+1]}
ik
Justifions ces relations:
1)Nous avons A[i][i] =0 parce quon ne multiplie une
matrice par elle mme, donc on effectue 0 mutiplications.
2)Si on multiplie deux matrices conscutives dans le
produit des matrices, le nombre de multiplications sera donn par
A[i][i+1] et le vecteur DIMENSION sera A[i]
[i+1]=DIM[i]xDIM[i+1]xDIM[i+2].
3)Si on multiplie les matrices A
i
xA
i+1
x.xA
k
, on obtient
une matrice avec un nombre de lignes egal celui de la matrice
A
i
, donc DIM[i], et un nombre de colonnes egal avec celui de
la matrice A
k
, donc DIM[k+1] .
Si on multiplie les matrices A
k+1
x A
k+2
x .xA
j
,on
obtient une matrice dont le nombre de lignes est egal celui de la
152
Structures de donnes et algorithmes
matrice A
k+1
, donc DIM[k+1], et dont le nombre de colonnes est
celui de la matrice A
j
, cest--dire DIM[j+1] .
La relation 3) montre le fait que, pour obtenir le nombre de
multiplications optimal pour le produit A
i
x A
i+1
x A
k
x A
k+1
x..A
j
, on multiplie, en effet, deux matrices :
-une obtenue comme produit optimal entre A
i
x A
i+1
x.x A
k
et
-une obtenue comme produit optimal entre A
k+1
x A
k+2
xx A
j
supposant quon connat le nombre de multiplications ncessaires
effectuer ces deux produits, pour nimporte qeuelle valeur du k
entre les limites donnes. Cest dans ce procd que la
programmation linaire consiste.
Calculons maintenant les lments de la matrice A pour
notre exemple (n=4).
A[1][1]=A[2][2]=A[3][3]=A[4][4]=0
A[1][2]=DIM[1]xDIM[2]xDIM[3]=10x1x10=100
A[2][3]=DIM[2]xDIM[3]xDIM[4]=1x10x1=10
A[3][4]=DIM[3]xDIM[4]xDIM[5]=10x1x10=100
A[1][3]=min {A[1][k]+A[k+1][3]+DIM[1].DIM[k+1].DIM[4]}=
1k<3
=min{A[1][1]+A[2][3]+DIM[1]xDIM[2]xDIM[4]},
k=1
k=2 A[1][2] + A[3][3] + DIM[1]xDIM[3]xDIM[4]}=
=min{0+10+10x1x1 , 100+0+10x10x10}=20
A[2][4]=min {A[2][k]+A[k+1][4]+DIM[2]xDIM[k+1]xDIM[j]}
2k<4
=min {A[2][2]+A[3][4]+DIM[2]xDIM[3]xDIM[5] ,
k=2
k=3 A[2][3]+A[4][4]+DIM[2]xDIM[4]xDIM[5]}=
=min{0+100+1x10x10 , 10+0+1x10x1}=min{200 , 20}=20
A[1][4]=min {A[1][k]+A[k+1][4]+DIM[1]xDIM[k+1]xDIM[5]}=
1k<4
=min{A[1][1]+A[2][4]+DIM[1]xDIM[2]xDIM[5],
153
Structures de donnes et algorithmes
k=1
k=2 A[1][2]+A[3][4]+DIM[1]xDIM[3]xDIM[5] ,
k=3 A[1][3]+A[4][4]+DIM[1]xDIM[4]xDIM[5]}=
=min{0+20+10x1x10,100+100+10x10x10,20+0+10x1x10}=
=min{120, 1200, 120}=120
Dans notre cas, nous intresse A[1][4]=120. La matrice A[4]
[4] est:

,
_

0
100 0
20 10 0
120 20 100 0
PROGRAMME MULTIPLICTIONS MATRICES
#include<stdio.h>
#include<conio.h>
int i,n, dim[20], a[10][10];
void matrix(int n, int dim[20], int a[10]
[10])
{int k, i, j, m,p;
for(i=1; i<=n; i++) a[i][i]=0;
for(k=1;k<n; k++)
for(i=1; i<=n-k; i++)
{j=i+k; a[i][j]=1000000;
for(p=i; p<=j-p; p++)
{m=a[i][p]+a[p+1][j]+dim[i]xdim[p+1]x
dim[p+1];
if(a[i][j]>m)
{{a[i][j]=m; a[j][i]=p;}}}
printf(optim%d\n, a[i][n]};}
main( )
{clrscr( );
printf(n=; scanf(%d, &n);
154
Structures de donnes et algorithmes
for(i=1; i<=n+1; i++)
{printf(d=); scanf(%d,&dim(i));}
matrix(n,dim,a);}
2.4.5.5. Le problme du labyrinthe
Soit un labyrinthe reprsent par une matrice binaire
(avec des lments 0 et 1) de dimensions n x m. Quelquun part
dune position initiale donne et arrive dans une position finale
donne. Dans le labyrinthe il parcourt dans une seconde les
carrs reprsents par 0 et en deux secondes les carrs
reprsents par 1. On demande le temps minimal ncessaire
cette personne pour quelle se dplace de la position initiale la
position finale. Le dplacement est permis selulement sur
lhorizontale et sur la verticale, indiffremment du sens.
Solution:
Soit le labytrinthe suivant (6x6):
dpart
Arrive
reprsent par la matrice:
A=

,
_

0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 0
0 1 1 1 1 0
155
Structures de donnes et algorithmes
Nous allons construire une matrice R(n,m) dans laquelle
r[i][j] est le temps minimal ncessaire pour arriver de la
position initiale la position (i,j).
r[i][j]=
{ }
{ }

,
_

+ + +
+ + +
1 ] ][ [ ] ][ 1 [ ], 1 ][ [ ], 1 ][ [ ], ][ 1 [ min 2
0 ] ][ [ ] ][ 1 [ ], 1 ][ [ ], 1 ][ [ ], ][ 1 [ min 1
j i a si j i r j i r j i r j i r
j i a si j i r j i r j i r j i r
Le calcul des lments de la matrice r[n][m] est le
suivant: on dtermine toutes les positions dans lequelles on
arrive en un temps 1, toutes les positions dans lequelles on
arrive en un temps 2, toutes les positions dans lequelles on
arrive en un temps 3 etc.
Pour le labyrinthe de notre exemple, la matrice r[6][6]
est:
r =

,
_

11 10 9 8 7 6
12 12 11 9 7 5
11 11 9 8 6 4
10 9 7 6 5 3
9 8 6 5 4 2
10 9 7 5 3 1
On observe que le temps minimal est 11.
2.4.5.6. La somme maximale des lments dun vecteur,
condition quil ny ait pas deux lments voisins
Soit un vecteur v[n] avec n lments nombres entiers.
Trouvez les lments du vecteur dont la somme est maximale,
156
Structures de donnes et algorithmes
condition que deux lments de cette somme ne soient pas
voisins dans le vecteur.
Solution:
Soit le vecteur v={1, 40, 2, 5, 80, 6, 7, 8}. On
observe que la somme maximale requise est 40+80+8=128.
Pour rsoudre le problme par la mthode de la
programmation dynamique, nous allons construire un vecteur
a[n], avec n composantes. La formule de rcurrence entre
deux tats est:
a[i] = v[j] + max{a[j],j>i+1}
Une composante a[i] reprsente la somme maximale
quon peut former en commenant de la position i jusqula fin
du vecteur. De cette manire, dans a[1] ou a[2] nous aurons la
somme maximale. Pour lexemple choisi, les lments du vecteur
a sont:
a[8]=v[8] = 8
a[7]=v[7] = 7
a[6]=v[6]+max{a[8]} = 6 + 8 = 14
a[5]=v[5]+max{a[8],a[7]}=80 + max{8,7} = 88
a[4]=v[4]+max{a[8],a[7],a[6]}=5+max{8,7,14}=19
a[3]=v[3]+max{a[8],a[7],a[6],a[5]}=2+max{8,7,1
9,88}=90
a[2]=v[2]+max{a[8],a[7],a[6],a[5],a[4]}=
=40+max{8,7,14,88,19}=128
a[1]=v[1]+max{a[8],a[7],a[6],a[5],a[4],a[3]}=
=1+max{8,7,14,88,19,90}=91
max{a[1],a[2]}= a[2]=128, la somme requise.
2.4.5.7. La plus longue sous-file commune pour deux
files
157
Structures de donnes et algorithmes
Soit deux files, donnes par deux vecteurs A[n] et B[m].
Touvez la plus longue sous-file commune ces deux files.
Exemple :
Soit :
A[6]={1,2,3,4,5,6}
B[9]={17,8,9,19,2,3,4,5,11}
On observe que la file maximale commun, en fait la
seule, est :
2,3,4,5 de longueur 4
Solution :
Soit la matrice c[n][m] dfinie ainsi :
c[i][j] =

,
_

] [ ] [
] [ ] [ 0
j B i A si
commune file sous
longue plus la de longueur la
j B i A si
Lalgorithme de rsolution est conforme la
programmation dynamique quand il y a une ventuelle suite de
transformations optimale.
La rsolution est la suivante:
Pour A[i]=B[j] on cherche, parmi les premiers (i-1)
lments de la file A et les premiers (j-1) lments de la file B,
la plus longue file commune, laquelle on ajoute le respectif
lment.
La matrice C[i][j] , dans notre exemple, est:
158
Structures de donnes et algorithmes
c[6][9]=

,
_

0 0 0 0 0 0 0 0 0
0 4 0 0 0 0 0 0 0
0 0 3 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
On choisi puis max{c[i][j]} qui, dans notre cas, est 4.
Si on veut laffichage des lments communs, on reprend le
procd pour llment maximal.
2.4.5.8. Reconstitution dune phrase
On donne une phrase dans laquelle manquent les espaces
entre les mots. On demande de reconstituer la phrase, ayant
comme base un dictionnaire form de queleues paroles. Sil y a
plusieurs solutions, on demande celle avec le minimum de mots.
Exemple :
Donnes dentre :
La phrase crite sans espaces entre les mots : lavachequirit
Le dictionnaire : {vache, la, qui, rit, rien, on, sur, dans}
Le nombre de lettres de la phrase : n
Donnes de sortie :
La phrase crite correctement .
Solution: On construit un vecteur avec (n+1) lments
dans lequel nous avons :
c[0]=0
c[i]=le nombre minimal de mots de la sous-phrase qui
commence avec la lettre de la position 1 et finit avec la lettre de
la position i. Sil ny a aucun mot, c[i]=-1. la fin, dans c[n]
nous aurons le nombre minimal de mots de la phrase lue
lentr.
La relation de rcurrence est :
c[i]=1+min{c[j], j=1,2,3,.i-1
159
Structures de donnes et algorithmes
et les lettres commenant avec la position
j+1 jusqu la position i forment un mot du
dictionnaire}
Pour lexemple choisi :
c[0]=0 c[7]=2
c[1]=-1 c[8]=-1
c[2]=1 c[9]=-1
c[3]=-1 c[10]=3
c[4]=-1 c[11]=-1
c[5]=-1 c[12]=-1
c[6]=-1 c[13]=4
Dans c[13] on trouve le nombre de mots de la phrase : 4.
Pour la rconstitution de la phrase, les mots finissent avec la
lettre qui se trouve aprs un c[n]

-1. Les lettres donnes


sont :
l a v a c h e q u i r i t
1 2 3 4 5 6 7 8 9 10 11 12 13
Les fins de mots seront : c[2] .. a ; c[7] ...e ; c[10]. i; c[13]..t.
La phrase correctement crite :
la vache qui rit
2.4.5.9.Le problme de la matrice binaire qui on peut
ajouter une unit
Soit une matrice binaire A[n][m] . Chaque ligne et chaque
colonne reprsente un nombre naturel crit en base 2. Le chiffre
droite de la ligne et le chiffre en bas de la colonne sont les plus
significatifs. La seule opration quon peut faire avec ces nombre
est laddition dune unit lun des nombres dune ligne ou
dune colonne.
On demande de dterminer le nombre minimal dunits
quil faut ajouter afin que la matrice ait seulement des chiffres 1.
160
Structures de donnes et algorithmes
Exemple :
Soit la matrice A=

,
_

1 0 1
1 0 0
0 0 1
crite en base 2.
En numration dcimale la matrice sera :

,
_

5
4
1
crite en colonnes ou
( ) 6 0 5
crite en lignes.
(+1) On ajoute 1 unit la colonne 3 :

,
_

1 0 1
1 0 0
1 0 1
(+2) On ajoute 2 units la colonne 1 :

,
_

1 0 1
1 0 1
1 0 1
(+2) On ajoute 2 units la ligne 3 :

,
_

1 1 1
1 0 1
1 0 1
(+3) On ajoute 3 units la colonne 2 :

,
_

1 1 1
1 1 1
1 1 1
Donc le nombre minimal dunits ajoutes est 8.
161
Structures de donnes et algorithmes
Solution : On construit la matrice c[n][m] o c[i]
[j] reprsente le nombre minimal dunits quon doit ajouter
afin que la matrice a, qui a le coin den haut gauche [1][1] et
celui den bas droite [i][j], ait des lments seulement de 1.
La manire de calculer les lments de la matrice c[n]
[m] est la suivante :
c[1]=1-a[1][1]
Les lments de la premire ligne seront :
c[1][j]=1-a[1][j]+c[1][j-1] pour 2jm
Les lments de la premire colonne seront :
c[i][1]=1-a[i][1]+c[i-1][1] pour
2in
On calcule les autres lments ainsi :
c[i][j] =

'

+ +

+
0 ] ][ [ ] 1 ][ 1 [ ] 1 ][ [ ] ][ 1 [ 2
1 ) , min(
1 ] ][ [ ] 1 ][ 1 [ ] 1 ][ [ ] ][ 1 [
j i a si j i c j i c j i c
j i
j i a si j i c j i c j i c

Pour notre exemple, la matrice c[3][3] est :
c=

,
_

8 6 1
5 4 1
2 1 0
Dans c[n] [m] on trouve la solution ; dans notre cas cest 8.
PROGRAMME AJOUTER UNIT
#include <stdio.h>
#include <conio.h>
#include <math.h>
main( )
{int a[10][10],c[10][10];
int m,n,i,j,k;
clrscr( );
162
Structures de donnes et algorithmes
printf(n=); scanf(%d,&n);
printf(m=); scanf(%d,&m);
for (i=1; i<=n; i++)
for (j=1;j<=m; j++)
{printf(a[%d][%d]=, i, j);
scanf(%d, &a[i][j];}
c[1][i]=!a[1][1];
for(j=2; j<=m; j++)
c[1][j]=1-a[1][j]+c[i][j-1];
for(i=2; i<=n; i++)c[i][1]=1-a[i][1]+c[i-1]
[1];
for(j=2; j<=m; j++)
{if(i<j) k=i-1; else k=j-1;
if(a[i][j] c[i][j]=c[i][j-1]+c[i-1][j]-c[i-
1][j-1];
else
c[i][j]=c[i][j-1]+c[i-1][j]-c[i-1[j-
1]+pow(2,k);
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
printf(c[%d][%d]=%d\n, i, j, c[i][j]);
printf(le nombre minimal dincrementatons
est %d, i, j, c[i][j]);}
2.4.5.10. Le problme du domino
On considre une file de pices de domino. Chaque pice
peut tre tourne, avec 180
0
, autour de son axe. Dterminez la
squence de pices de longueur maximale dans laquelle deux
pices voisines contiennent le mme nombre: le second nombre
dune pice concide avec le premier de la pice suivante.
Les donnes dentre sont : le nombre de pices de
domino et les pices avec les nombres inscrites sur elles. Les
donnes de sortie sont : la longueur de la plus grande squence.
163
Structures de donnes et algorithmes
Exemple :
Soit n=8 et les pices suivantes :
12
34
36
65
25
14
43
25
La squence maximale est forme de 4 pices :
43 tourne
36
65
52 tourne
Solution :
Une solution de ce problme est de dterminer la sous-
file de longueur maximale dune file donne, problme traite
auparavant toujours par la programmation dynamique.
c(i,j) est la dimension de la sous-file de longueur
maximale, ayant comme dernier lment la pice i, qui se forme
si on prend la dcision j (j=0 signifie que la pice nest pas
tourne et j=1 signifie que la pice est tourne).
La relation de rcurrence est :
c(i,j) = max {c(t,k) + d(a(i,j,), a(t,k) )
avec 0<=k<=1 et 1<=t=i-1
o d est la distance entre un nombre situ sur la pice i
et un nombre situ sur la pice j. d=1 si les nombres sont
gaux et d=0 si les nombres ne sont pas gaux.
164
Structures de donnes et algorithmes
Limplmentation du programme:
Le programme demande de trouver la plus longue file de
pices de domino ayant n pices donnes. Les pices peuvent tre
tournes, pour continuer la file. Si la pice x+1 ne peut pas tre
couple la pice x, la file est considre intrompue.
On rsoud le problme par la programmation dynamique,
la mthode en arrire.
On va crer un vecteur bidimensionel, dans lequel on va
retenir la longueur de la plus longue file posible, qui commence
avec avec une certaine pice i; la deuxime dimension va
prciser si la pice est tourne (bit=1) ou non (bit=0).
On retient aussi dans un autre vecteur bidimensionel
(succ), la pice successive la pice i tourne ou non.
Dans ce problme, la programmation dynamique consiste
dans la construction du vecteur long et de la relation sur
laquelle est base cette construction:
auxMax = ((long[i][0]>long[i][1]) ? long[i][0] :
long[i][1]);

#include <stdio.h>
#include <conio.h>
#include <iostream.h>
typedef struct /deffiniton dune structure qui
retient les pices donnes/
{int n1, n2;} Piece;
Piece vp[200];
int nr;
165
Structures de donnes et algorithmes
int iMax, bit; /*si la pice est tourne
(bit=1) si non (bit=0)*/.
int succ[200][2];/dans succ on retient le
successeur de la pice*/
int long[200][2];/*dans long on retient la
longueur de la plus longue file qui commence
avec une certaine pice tourne ou non*/
void lire()
{int i;
cout<<"ecrivez les pices"<<endl;
for (i=1; i<=nr; i++)
{cout<<"pice"<<i<<endl;
cout<<"gauche"; cin>>vp[i].n1;
cout<<"droite"; cin>>vp[i].n2;
cout<<endl;}}
void traitement ()
{int i, auxMax;
long[nr][0]=1; succ[nr][0]=-1;/*la longueur
correspondente la dernire pice (non
tourne) est 1; la pice na pas de
successeur*/
long[nr][1]=1; succ[nr][1]=-1;/* la longueur
correspondente la dernire pice (tourne)
est 1; la pice na pas de successeur*/
iMax=nr; bit=0;
for (i=nr-1; i>=1; i--) /*on parcourt le
vecteur en manire dcroissante et on vrifie
le couplage des pices*/
{long[i][0]=1; succ[i][0]=-1;
long[i][1]=1; succ[i][1]=-1;
if ((vp[i+1].n1 == vp[i].n2) && (long[i]
[0]<long[i+1][0]+1))
{long[i][0]=long[i+1][0]+1;
succ[i][0]=i+1;}
if ((vp[i+1].n2 == vp[i].n2) && (long[i]
[0]<long[i+1][1]+1))
{long[i][0]=long[i+1][1]+1;
succ[i][0]=i+1;}
166
Structures de donnes et algorithmes
if ((vp[i+1].n1 == vp[i].n1) && (long[i]
[1]<long[i+1][0]+1))
{long[i][1]=long[i+1][0]+1;
succ[i][1]=i+1;}
if ((vp[i+1].n2 == vp[i].n1) && (long[i]
[1]<long[i+1][1]+1))
{long[i][1]=long[i+1][1]+1;
succ[i][1]=i+1;}
auxMax = ((long[i][0]>long[i][1]) ? long[i]
[0] : long[i][1]); /*auxMax
retient la longueur un moment donn*/
if (auxMax>long[iMax][bit])
{iMax=i;
bit = ((long[i][0]>=long[i][1]) ? 0 : 1);}}}
void afficher ()
{int aux;
cout<<"longueur="<<lung[iMax][bit]<<endl;
if (bit==0)
{aux=vp[iMax].n2;
cout<<vp[iMax].n1<<" "<<vp[iMax].n2<<endl;}
else
{aux=vp[iMax].n1;
cout<<vp[iMax].n2<<" "<<vp[iMax].n1<<endl;}
iMax = succ[iMax][bit];
while (iMax!=-1)
{if(aux==vp[iMax].n1)
{cout<<vp[iMax].n1<<" "<<vp[iMax].n2<<endl;
aux=vp[iMax].n2;
bit=0;}
else
{cout<<vp[iMax].n2<<" "<<vp[iMax].n1<<endl;
aux=vp[iMax].n1;bit=1;}
iMax=succ[iMax][bit];}}
void main()
167
Structures de donnes et algorithmes
{clrscr();
cout<<"c0mbien de pieces a le domino? ";
cin>>nr;
lire ();
traiter ();
afficher ();
getch();}
2.5. ALGORITHMES GNTIQUES
2.5.1. Dfinition et courte histoire
Les algorithmes gntiques reprsentent un cas particulier
des algorithmes volutifs qui, leur tour, font partie de
lintelligence artificielle. Ils sont des algorithmes stochastiques.
Un algorithme stochastique rsout un problme dont la
solution prsente des changments en temps (alatoires ou non).
Si ces changements consistent dans une serie progressive de
transformations, on dit que lalgorithme est volutif. Parmi les
algorithmes volutifs, ceux qui sont des procdures qui
sinspirent des mcanismes de la slection naturelle et des
phnomnes gntiques portent le nom dalgorithmes gntiques.
Ils utillisent un vocabulaire similaire celui de la gntique,
168
Structures de donnes et algorithmes
cependant, les processus auquels ils font rfrence sont beaucoup
plus complexes.
Les algorithmes gntiques ont t utiliss dabord dans
les problmes doptimisation. Puis, leur domaine dapplication
devient plus gnral. Dans les dernires dix annes, la littrature
donne de nombreux tudes qui cherchent dintroduir ces
algorithmes dans des divers problmes concrets.
Ltude thorique des algorithmes gntiques donne dj
de sustantiels rsultats ; cependent ces rsultats demandent un
investissement supplmentaire dans la comprhension des outils
dvelopps. Demeurent beaucoup dinterrogations concernant les
relations relles entre les diffrents paramtres caractrisant
lalgorithme gntique et les choix pratiques de ceux ci.
Dans ce domaine, la pratique devance encore la thorie,
mme si les mcanismes commencent tre plus clairs.
Il reste galement tudier les nombreux raffinements
existants aujourdhui en application.
Le premier qui a introduit la notion de calcul volutif a t
I. Rechenberg, en 1960, dans son ouvrage EVOLUTIONS
STRATEGIES.
Les premiers travaux sur les algorithmes gntiques ont
commenc dans les annes cinquante lorsque plusieurs
biologistes amricains ont simul des structures biologiques sur
lordinateur. Puis, John Holland, sur la base des travaux
prcdents, dvelopa les principes fondamentaux des algorithmes
gntiques, dans le cadre de loptimisation mathmatique, et,
surtout, dans son livre ADAPTION IN NATURAL AND
ARTIFICIALS SYSTEMS, publi en 1975. Louvrage de
D.Goldberg, GENETIC ALGORITMS, 1989, qui dcrit
lutilisation des algorithmes gntiques pour la rsolution des
problmes concrets, a permis de mieux faire connatre ces
derniers et a marqu le dbut dun nouvel intrt pour ces
techniques.
169
Structures de donnes et algorithmes
La dnommination de programmation gntique appartient
John Koza qui, en 1992, a utilis les algorithmes gntiques
pour dveloper des programmes destins aux divers buts
concrets.
Les derniers dix annes ont dmontr que ces mthodes ne
se rduisent pas la simple recherche de loptimum dun
processus mais elles savrent tre galement de puissants outils
pour lanalyse des situations dynamiques complexes comme lon
rencontre dans tous les domaines.
2.5.2.Termes biologiques utiliss aux
algorithmes gntiques
Comme dans la biologie, on parle dindividu dans une
population. Lindividu est compos dun ou plusieurs
chromosomes. Les chromosomes sont eux-mme constitus de
gnes qui contiennent les caractres hrditaires de lindividu.
Sur des populations on aplique des processus de
slection, de croisement et de mutation qui sappuient sur les
processus naturels du mme nom.
Un chromosome est, en fait, un vecteur. Le plus souvent
ce vecteur est binaire (a seulement des lments 0 et 1).
La fitness dun chromosome permet de calculer
ladaptation de chaque lment au problme. En termes
biologiques, on peut dire que la fitness est lesprance de vie
dun chromosome. Elle doit avoir des valeurs extrmes :
minimales ou maximales. Dans la plupart des applications la
condition impose est dobtenir une fitness, la plus grande
possible.
Le gne est un lment v[i] dun vecteur.
La population initiale est un ensemble de chromosomes,
donc un ensemble de vecteurs. Les paramtre qui dterminent la
population initiale sont :
n - le nombre des crhomosomes, donc des
170
Structures de donnes et algorithmes
vecteurs ;
nr - le nombre des gnes dun chromosomes, donc
le nombre des composantes dun vecteur .
Le paramtre n doit tre assez grand, pour quon puisse raliser
un nombre de combinaisons suffisamment grand, mais pas trop
grand puisque, de cette manire, on ralentira lalgorithme.
Cette population initiale, qui sert de base aux gnrations
futures, doit tre la plus htrogne possible. Sa gnration est,
dhabitude, alatoire mais, quelequefois, peut tre euristique.
La slection est lopration didentifier statistiquement
les meilleurs individus dune population et dliminer les
mauvais. Les chromosomes dune population antrieure sont
slects pour former la population actuelle. On connat un
nombre important de mthodes de slection. Nous allons
prsenter un des plus utilis, la mthode de la roulette russe.
Le principe de nimporte quel mthode est de slecter
une nouvelle population conformment sa fitness. Dans la
mthode de la roulette rousse, il y a une roue dans laquelle
chacun de ses secteurs est proportionnel, en aire, avec la fitness
dun chromosome. Quand on jette une bile sur la roulette, il y a
plus de chance de slection pour les chromosomes avec une
fitness plus grande.
On fait la simulation de la roulette de manire suivante :
-On calcule la somme de toutes les fitness des chromosome (S)
-On engendre alatoirement un nombre entre 1 et S. Soit C.
-On parcourt la population et on calcule la somme des fitness des
chromosomes jusquon arrive la valeur C. Cest le chromosome
choisi.
La mutation simple consiste, en gnral, tirer
alatoirement un gne dans le chromosome et le remplacer par
une valeur alatoire. Dans le cas dlments cods en binaire, on
remplacera la valeur 0 par 1 ou vice-versa.
Exemple :
171
Structures de donnes et algorithmes
lment initial
1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0
lment mut
1 1 1 1 0 0 1 0 1 1 1 1 0 0 0 0
La mutation croise ou le croisement (crossover) a pour
but denrichir la diversit de la population, en manipulant les
composantes des individus (des chromosomes). Lopration par
laquelle on combine de nouveau les gnes des deux
chromosomes de la mme longueur a pour rsultat lobtention de
deux autres chromosomes de squences analogues. Les deux
parents gnrent deux enfants. Un type de croisement est le
croisement dcoupage. On tire alatoirement une position de
dcoupage. On change ensuite les deux sous-chaines terminales
de chacun des deux chromosomes (parents), ce que produit deux
nouveaux chromosomes (enfants) . On peut faire, aussi, deux
dcoupages. Par exemple :
Les parents :
C1= 1 0 1 0 1 0 1 0 0 0 0 0 1 1 1 1
C2= 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0
Les enfants :
C1= 1 0 1 0 1 1 0 0 0 0 0 0 1 1 0 0
C2= 1 1 0 0 1 0 1 0 1 1 0 0 1 1 1 1
2.5.3.La structure dun algorithme gntique
Un schma gnral dun algorithme gntique est la
suivante :
cration population initiale (n, nr) ;
compteur=0 ;
rpter
compteur ++ ;
slection population intermdiaire ( ) ;
172
Structures de donnes et algorithmes
croisement (pmc) ;
mutation simple (pms) ;
jusque quand ( compteur=compteur maximal)
afficher rsultat ( ) ;
Le programme commence par:
creation population initiale (n,nr) ;
Cette fonction va crer alatoirement la population
initiale, cest--dire un nombre n de vecteurs, chacun ayant un
nombre nr de composantes, ou, en parlant gntiquement, une
population de n chromosomes chacun ayant nr gnes.
Pour chaque application il y a le problme de la
correspondance logique entre les donnes spcifiques de
lapplication et la populaton initiale. Dhabitude on utilise des
vecteurs en binaire mais le programmeur doit dfinir la
correspondance entre les chromosomes et les dones du
programme ralis.
Ensuite vient une boucle de programme qui se rpte un
nombre de fois gal au :
compteur maximal ;
les paramtres sont tablis par le programmeur.
On excute la boucle avec les suivants pas : on cre une
population intermdiaire laide de la fonction
selection population intermediaire
en utilisant une des mthodes de slection, dans notre cas
la mthode de la roulette russe.
Sur un pourcentage de la population intermdiaire on
excutera un croisement laide de la fonction :
croisement(pmc) ;
le paramtres pmc (la probabilit de mutation croise) a la valeur
de 0,1, cest--dire on appliquera le croisement sur 10% de la
totalit des chromosomes. Pour chaque chromosome de la
population intermdiaire on engendre un nombre entre 0 et 1. Si
ce nombre est infrieur pmc , le chromosome sera slect pour
le croisement. On ralise le croisement ainsi :
Soit les chromosomes slects :
173
Structures de donnes et algorithmes
C
1
=x
1
x
2
x
3
..x
nr
C
2
=y
1
y
2
y
3
..y
nr
On engendre alatoirement un nombre naturel
t{1,2.nr}.
Aprs le croisement, les chromosomes seront :
C
1
=x
1
x
2
x
3
x
t
y
t+1
y
t+2
..y
nr
C
2
=y
1
y
2
y
3
y
t
x
t+1
x
t+2
..x
nr
Puis on appliquera la mutation simple avec la fonction
mutation simple(pms)
Le paramtre pms ( la probabilit de mutation simple) est
le pourcentage des chromosomes qui subiront la mutation simple.
Dhabitude il est plus petit que pmi (cca. 2%).
Aprs quoi on engendrera
compteur maximal,
gnrations intermdiaires, on va slecter et on affichera le
rsultat.
La fonction
afficher resultat
joue le rle de slecter le plus valeureux chromosome de la
dernire gnration et de lafficher.
Observations gnrales:
-Une caractristique des algorithmes gntiques cest
quils oprent sur lentire population. Comment voluent les
individus, a ne compte pas. Limportant cest comment volue
la population prise comme entier. On ne garanti pas quune
nouvelle gnration sera plus valeureuse. Cette volution a lieu
la suite de certaines lois statistiques. Finalement on arrive une
population qui nvolue plus.
-Pour obtenir une bonne convergeance du programme
gntique, trs important est le mode de choisir les paramtres
n, nr, compteur maximal, pmc et pms.
-Le plus souvent il est ncessaire que ces algorithmes
soient tests en employant une autre gnrateur de nombres
alatoires que la fonction random( ).
174
Structures de donnes et algorithmes
-La complexit de temps des algorithmes gntiques est
polynmiale. La fonction est O(n, nr, compteur maximal).
2.5.4.Exemples de programmes gntiques
2.5.4.1. Le maximum dune fonction dans un intervalle
donn
Crez un programme gntique pour calculer le
maximum dune fonction dans un intervalle donn.
Nous allons essayer de voir les pas de cet algorithme sur
un exemple simple
f :[0,1]R , f(x)=x
Solution :
Au commencement il faut tablir la correspondance entre
les points pris dans lintervalle et les chromosomes. On divise
lintervalle en points pour lesquels on calculera le maximum de
la fonction. La distance entre les points est: d=(la longueur
de lintervalle)/(n-1), o n est le nombre de
chromosomes (le nombre des vecteurs).
Pour des vecteurs forms de deux lments binaires:
d=1/(4-1)=0,33
la correspondance est :
vecteur Nombre dans
lintervalle
00 0
01 0,33
10 0,66
11 1
Pour des chromosomes forms de trois lments binaires:
d=1/(8-1)=0,14
la correspondance est :
vecteur Nombre dans lintervalle
000 0
001 0,14
010 0,28
175
Structures de donnes et algorithmes
011 0,42
100 0,56
101 0,70
110 0,84
111 1
Considrons un exemple avec 10 chromosomes (vecteurs)
binaires, chacun ayant trois gnes (lments binaires), donc
n=10 et nr=3.
Nr. vecteur Nombre
dans
lintevalle
1 001 0,14
2 110 0,84
3 111 1
4 010 0,28
5 100 0,56
6 001 0,14
7 011 0,42
8 101 0,70
9 010 0,28
10 001 0,14
Cest la population initiale, forme de 10 chromosomes,
chacun ayant 3 gnes.
Ensuite, conformment lalgorithme gntique, on passe
la slection de la population laide de la mthode de la
roulette russe. Dabord il faut calculer la fitness de chaque
chromosome. Dans ce cas, la fitness est la valeur de la fonction
f(x)=x dans le point. On nous intresse une fitness, la plus
grande possible, donc le maximum de cette fonction.
fitness(chromosome[i])=f(chromosome[i])=chromosome[i]
Pour notre exemple:
Nr. chromosome fitness
1 001 0,14
2 110 0,84
176
Structures de donnes et algorithmes
3 111 1
4 010 0,28
5 100 0,56
6 001 0,14
7 011 0,42
8 101 0,70
9 010 0,28
10 001 0,14
Puis, nous allons appliquer la slection par la roulette
russe. ce but, nous allons calculer la probabilit dapparition de
chaque chromosome i :
p
i
=fitness
i
/ S
o S est la somme des fitness de tous le chromosomes.
Dans notre exemple :
S=

10
1 i
i
fitness =4,50
Les probabilits seront :
p1 0,14 / 4,50 0,031
p2 0,84 / 4,50 0,186
p3 1,00 / 4,50 0,217
p4 0,28 / 4,50 0,062
p5 0,56 / 4,50 0,124
p6 0,14 / 4,50 0,031
p7 0,42 / 4,50 0,093
p8 0,70 / 4,50 0,155
p9 0,28 / 4,50 0,062
p10 0,14 / 4,50 0,031
videmment
1
10
1

i
i
p
. La roulette sera :
177
Structures de donnes et algorithmes
On engendre 10 nombres alatoires compris entre 0 et 1
et, pour chaque nombre associ un chromosome, on voit dans
quelle zone de probabilit est situ. Puis, on remplace le
respectif vecteur avec celui qui correspond cette zone de
probabilit.
Nr.
crt.
Nombres
alatoires
Vecteur
(chromosome)
courant
Vecteur
(chromosome)
nouveau
1 0,21 001 110
2 0,43 110 111
3 0,59 111 100
4 0,71 010 011
5 0,75 100 101
6 0,12 001 001
7 0,34 011 010
8 0,91 101 010
9 0,52 010 100
10 0,67 001 011
178
Structures de donnes et algorithmes
Une nouvelle population est obtenue :
1 110
2 111
3 100
4 011
5 101
6 001
7 010
8 010
9 100
10 011
Ensuite on opre le croisement. Si pmc=0,2 on
appliquera le croisement sur 20% dentre chromosomes, cest--
dire pour deux chromosomes ; soit c
1
et c
6
et t=1.
c
1
= 1 1 0
c
6
= 0 0 1
c
1
'= 1 0 1
c
6
'= 0 1 0
La nouvelle population est :
1 101
2 111
3 100
4 011
5 101
6 010
7 010
8 010
9 100
10 011
179
Structures de donnes et algorithmes
Puis on fait la mutation simple quon applique sur un seul
chromosome (pms=0,1).
Soit :
C
4
= 0 1 1
C
4
'= 1 1 1
La nouvelle population est :
1 101
2 111
3 100
4 111
5 101
6 010
7 010
8 010
9 100
10 011
Si on choisi compteur maximal =10, la population sera dix
fois modifi. Puis, de la dernire population, on choisi le plus
valeureux chromosome qui, dans notre cas peut tre 111,
correspondant au nombre 1. Donc le maximum de la foncton est
1.
PROGRAMME GNTIQUE POUR LE MAXIMUM DE LA FONCTION
f(x)=x DANS LINTRVALLE [0,1]
#include<conio.h>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
main()
{ clrscr();randomize();
int
180
Structures de donnes et algorithmes
nrbiti,nrchrom,nrgener,ng,i,k,j,crparents[50]
[32],cmbcr[32],parent1,parent2;
int c,t,iaux,temp,br,semn,crfils[50]
[32],rand,cont,nrc,icmbfk;
float vpar[50][3],vfils[50]
[3],xk,cmbfk,aux,a,b,arand;
long pd;
INITIALISATION
a=0;b=1;
printf("nrbiti=");scanf("%d",&nrbiti);
printf("nrchrom nr
par=");scanf("%d",&nrchrom);
printf("nrgener=");scanf("%d",&nrgener);
for(i=1;i<=nrchrom;i++)
{for(j=1;j<=nrbiti;j++)
{crparents[i][j]=random(nrcrom*nrchrom)
%2; } }
for(j=1;j<=nrbiti;j++)
{ cmbcr[j]=0;}
cmbfk=0;
//CYCLES DE GNRATIONS
for(ng=1;ng<=nrgener;ng++)
{
LA DTERMINATION DE LA MEILLEURE FITNESS CMBFK
for(i=1;i<=nrchrom;i++)
{k=0;pd=1;
for(j=1;j<=nrbiti;j++)
{k=k+crparents[i][nrbiti-j+1]*pd;
pd=pd*2;}
vpar[i][1]=k;
xk=a+k*(b-a)/(pd-1);
vpar[i][2]=xk;
vpar[i][3]=xk;
if(vpar[i][3]>cmbfk)
{cmbfk=vpar[i][3];} }
printf("ng=%d",ng);
181
Structures de donnes et algorithmes
printf("cmbfk=%f",cmbfk);
RANGEMENT DE LA POPULATON EN ORDRE CROISSANTE DE LA
FITNESS
do{signe=1;
for(i=1;i<=nrchrom-1;i++)
{if(vpar[i][3]>vpar[i+1][3])
{for(j=1;j<=nrbiti;j++)
{iaux=crparents[i+1][j];
crparents[i+1][j]=crparents[i][j];
crparents[i][j]=iaux;}
aux=vpar[i+1][1];
vpar[i+1][1]=vpar[i][1];
vpar[i][1]=aux;
aux=vpar[i+1][2];
vpar[i+1][2]=vpar[i][2];
vpar[i][2]=aux;
aux=vpar[i+1][3];
vpar[i+1][3]=vpar[i][3];
vpar[i][3]=aux;
signe=0;}}}
while(signe==0);
GNRATION ALATOIRE DES FILS
DES MEILLEURS PARENTS
cont=1;
for(nrc=1;nrc<=nrchrom/2;nrc++)
{icmbfk=cmbfk*1000;
rand=random(icmbfk+1);
arand=rand;
arand=arand/1000;
c=1;
do{c=c++;}
while(vpar[c][3]<arand&c<=nrchrom);
parent1=c;
icmbfk=cmbfk*1000;
182
Structures de donnes et algorithmes
rand=random(icmbfk+1);
arand=rand;
arand=arand/1000;
c=1;
do{c=c++;}
while(vpar[c][3]<arand & c<=nrchrom);
parents2=c;
t=random(nrbiti);
if(i==0) i=1;
for(k=1;k<=t;k++)
{crfils[cont][k]=crparents[parent1][k];
crfils[cont+1]
[k]=crparents[parent2][k];}
for(k=t+1;k<=nrbiti;k++)
{crfils[cont][k]=crparents[parent2][k];
crfils[cont+1][k]=crparents[parent1][k];}
DTERMINATION DUNE MUTATION DES FILS
br=random(nrbiti);
if(br<2) br=2;
temp=crfils[cont][br];
crfils[cont][br]=crfils[cont][br-1];
crfils[cont][br-1]=temp;
br=random(nrbiti);
if(br<2) br=2;
temp=crfils[cont+1][br];
crfils[cont+1][br]=crfils[cont+1][br-1];
crfils[cont+1][br-1]=temp;
cont=cont+2;}
CHANGEMENT DE LA GNRATION
for(i=1;i<=nrchrom;i++)
{for(j=1;j<=nrbiti;j++)
{ crparents[i][j]=crfils[i][j];}}}
printf("cmbfk=%f",cmbfk);
getch();}
183
Structures de donnes et algorithmes
2.5.4.2. La solution dune quation dans un intervalle
donn
PROGRAMME POUR CALCULER LA SOLUTION DE
LQUATION 2X-3=0 DANS LINTRVALLE [0,3]
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <dos.h>
int population_initiale[64][6],
population_intermediaire[64][6];
float unite;
int nr_chromosomes, dim_chromosomes;
void creation_population_initiale(int nr_c,
int dim_c)
{int i, k;
for(i=0; i<=nr_c; i++)
{k = i;
for(int j=0; j<dim_c; j++)
{if((k/int(pow(2, (5-j)))) != 0)
{population_initiale[i][j] = 1;
k -= int(pow(2, (5-j))); }
else population_initiale[i][j] = 0;}}}
int stach()
{float somme = 0, niveau = 0, stach[64], x;
int run;
for(int i=0; i<nr_chromosomes; i++) somme =
somme + fabs(2*(unite*i)-3);
stach[0] = somme/fabs(-3);
for(i=1; i<nr_chromosomes; i++)
{ x = fabs(2*(unite*i)-3);
if (x != 0) stach[i] = stach[i-1] + somme/x;
else stach[i] = stach[i-1] + 150;}
184
Structures de donnes et algorithmes
niveau = stach[nr_chromosomes-1];
run = int(random(niveau));
i=0;
while(run > int(stach[i])) i++;
return i;}
void selection_population_intermediaire()
{int x, i, j;
for (i=0; i<nr_chromosomes; i++)
{x = stach();
for(j=0; j<dim_chromosomes; j++)
population_intermediaire[i][j] =
population_initiale[x][j];}
for (i=0; i<nr_chromosomes; i++)
for(j=0; j<dim_chromosomes; j++)
population_initiale[i][j] =
population_intermediaire[i][j];}
void croisements(int pmc)
{int x, y , i, j, aux;
for(i=0; i<(nr_chromosomes-1); i++)
{x = random(10);
if(x<=pmc)
{ y=random(dim_chromosomes);
for(j=y; j<dim_chromosomes; j++)
{aux = population_initiale[i][j];
population_initiale[i][j] =
population_initiale[i+1][j];
population_initiale[i+1][j] = aux;}}}}
void mutations_simples(int pms)
{int x, y , i;
for(i=0; i<(nr_chromosomes-1); i++)
{x = random(10);
if(x<=pms)
{y=random(dim_chromosomes);
if (population_initiale[i][y])
population_initiale[i][y] = 0;
else population_initiale[i][y] = 1;}}}
185
Structures de donnes et algorithmes
void afficher _resultat()
{int i, j, v;
float c, sol=3, res;
for(i=0; i<nr_chromosomes; i++)
{v=0;
for (j=0; j<dim_chromosomes; j++)
{if (population_initiale[i][j])
v=v+pow(2,j);}
c = v*unite;
if (fabs(2*c-3)<sol) {sol = fabs(2*c-3);
res=c;}}
printf("Solution de lecuation 2x+3=0 est:
%f", res);}
void main()
{int g, gmax, pmc, pms;
clrscr();
printf("Introduire le nombre de chromosomes:
");
scanf("%d", &nr_chromosomes);
printf("Introduir la dimension dun
chromosome: ");
scanf("%d", &dim_chromosomes);
printf("Introduir le nombre des generations:
");
scanf("%d", &gmax);
printf("Introduir la probabilite du
croisement: ");
scanf("%d", &pmc);
printf("Introduir la probabilite de la
mutation simple: ");
scanf("%d", &pms);
unite = 3/double(nr_chromosomes);
randomize();
creation_population_initiale(nr_chromosomes,
dim_chromosomes);
g=0;
while (g<gmax)
186
Structures de donnes et algorithmes
{randomize();
selection_population_intermediaire();
randomize();
croisements(pmc);
randomize();
mutations_simples(pms);
g++;}
afficher_resultat();
getch();
187
Structures de donnes et algorithmes
BIBLIOGRAPHIE
1 - Tudor Sorin-Informatica.Varianta C++-Editura
L&S, Bucureti,2001
2 - Ioan Tomescu-Bazele Informaticii-Editura Didactic
i Pedagogic-Bucureti, 1998
3 - Tudor Sorin-Tehnici de programare-Editura
L &S,1999
4 - Musc Gavril, Nedelcu Dumitru,Sofronie Alex,
Baze de date,Ed. Venus, Iai, 2002
5 - Florescu V., Stanciu V., Cozgarea A., Cozgarea
B.-Baze de date-Editura Economic, Bucureti,2000
6 - Valentin Cristea, Irina Atanasiu, Eugenia Kalisz,
Valeriu Iorga - Tehnici de programare-Editura
Teora, Bucureti, 1997
7 - Donald E. Knuth-Arta programrii calculatoarelor-
vol.1-Algoritmi fundamentali-Editura Teora,
Bucureti ,1999
8 - J.M.Aldous, R. J. Wilson- Graphs and
applications: an introductory approach- Springer
Verlag, 2000
9 - Grard Grancher Thorie des graphes -
Universit de Rouen UMR 6085- 2002
10 - Mihai Oltean-Proiectarea i implementarea
algoritmilor-Editura Agora, 1998
11 - Thomas C. Cormen, Charles E. Leiseron, Ronald
R. Rivest-Introducere n algoritmi- Traducere dup
Introduction to Algorithms, Massachusetts Institute of
Technology-Editura Teora, Bucureti, 1990
12 - R. Bellman, R. Dreyfus Programarea dinamic n
aplicaii Editura tehnic, Bucureti, 1967
188
Structures de donnes et algorithmes
13 - Gh. Pun Jocuri logice Editura Sport-
Turism,1990
14- Alliot J.M.,T. Schies Intelligence artificielle et
informatique Editions Cpadues, 1993
15 - D. Goldberg Genetic Algorithms Ed. Addison
Wesley,1989
16 - Z. Michalewicz Genetic Algorithms +Data
Structures=Evolution programs Springer Verlag,
New-York,1991
17 - Colecia Gazeta de Informatic
18 - Colecia Journal of the ACM
189
Structures de donnes et algorithmes
CONTENU
Pg.
INTRODUCTION... 3
1. STRUCTURES DE DONNES... 5
1.1 LISTES LINAIRES... 11
1.1.1 Listes linaires avec allocation squentielle... 12
1.1.2 Listes linaires avec allocation chaine.. 14
1.1.2.1 Listes linaires simplement chaines. 14
1.1.2.2 Listes circulaires 22
1.1.2.3 Listes linaires doublement chaines. 23
1.1.3 Problmes avec des listes 30
1.2 PILES 32
1.2.1 Dfinitions, proprits, programmes. 32
1.2.2 Problmes avec des piles... 37
1.3 QUEUES... 37
1.3.1 Dfinitions, proprits, programmes. 37
1.3.2 Problmes avec des queues... 41
1.4 GRAPHES 42
1.4.1 Graphes orients 42
1.4.1.1 Definitions 42
1.4.1.2 Modes de reprsenter les graphes 45
1.4.1.3 Le parcours des graphes... 48
1.4.1.3.1 Le parcours en largeur
(BF-BREADTH FIRST)... 49
1.4.1.3.2 Le parcours en profondeur
(DF DEPHT FIRST)... 53
1.4.1.4 Composantes fortement connexes 54
1.4.1.5 Graphes pondrs. 57
1.4.1.5.1 Matrice des poids. 57
1.4.1.5.2 Lalgorithme Roy-Floyd.. 60
1.4.1.5.3 LalgorithmeDIJKSTRA. 63
1.4.2 Graphes non-orients 68
1.4.2.1 Graphes hamiltoniens.. 68
190
Structures de donnes et algorithmes
1.4.2.2 Graphes eulriens. 69
1.4.3 Problmes avec des graphes. 74
1.5 ARBRES... 76
1.5.1 Dfinitions. 76
1.5.2 Test pour vrifier si un graphe est arbre... 78
1.5.3 Arbres binaires. 79
1.5.3.1 Dfinition. 79
1.5.3.2 Reprsentation des arbres binaires... 79
1.5.3.3 Le parcours des arbres binaires 80
1.5.4 Arbres de recherhe 82
1.5.4.1 Dfinition. 82
1.5.4.2 Oprations avec des arbres de
recherche.. 82
2. ALGORITHMES 85
2.1 GNRALITS... 85
2.2 ANALYSE DES PERFORMANCES DES
ALGORITHMES.. 85
2.3 ALGORITHMES DE TRI ET DE RECHERCHE... 88
2.3.1 Algoritmes de tri... 89
2.3.1.1. Tri par permutation.. 89
2.3.1.2. Tri par slection.... 95
2.3.1.3. Tri par insertion.... 96
2.3.1.3.1. Le tri SHELL.... 98
2.3.1.3.2. Le tri rapide.. 98
2.3.2 Algorithmes de recherche. 100
2.4. MTHODES DLABORATION DES
ALGORITHMES..
102
2.4.1 La mthode DIVIDE ET IMPERA... 102
2.4.1.1. La recherche binaire. 102
2.4.1.2. Les tours de Hanoi 103
2.4.1.3. La solution aproximative dune
quation,dans un intervalle donn.... 105
2.4.1.4. Le problme des incisions.... 106
2.4.1.5. Devination dun nombre... 108
2.4.2 La mthode GREEDY.. 109
2.4.2.1. Planification des spectacles.. 110
2.4.2.2. Le problme du havresac.. 113
2.4.2.3. Calcul rapid de la puissance dun
nombre.. 115
2.4.2.4. Les ennemis.. 116
191
Structures de donnes et algorithmes
2.4.2.5. Polygone convexe. 119
2.4.3 La mthode backtracking (standard). 120
2.4.3.1. Permutations dans un ensemble de n
lments.. 123
2.4.3.2. Les sousensembles de p lments dans un
ensemble de n lments... 127
2.4.3.3. Le problme des n reines.. 128
2.4.3.4. La coloration des cartes.... 130
2.4.3.5. Le problme du commis-voyageur... 131
2.4.3.6. Rsolution dune quation, en nombres
naturels... 133
2.4.3.7. Le problme des tandards... 133
2.4.4 La mthode backtracking (non-standard). 134
2.4.4.1. Engendrement des partitions dun nombre
naturel.. 134
2.4.4.2. Remplissage dune surface ferme.. 136
2.4.4.3. Le problme de la pyramide. 138
2.4.4.4. Problme de la photographie
blanc/noir. 139
2.4.5 Programmation dynamique... 140
2.4.5.1. Problme du triangle 141
2.4.5.2. La variante discrte du havresac.. 144
2.4.5.3 La plus grande file ascendente dun
vecteur.. 146
2.4.5.4. Le problme des parantses ; la
multiplication optimale dune file de
matrices 148
192
Structures de donnes et algorithmes
2.4.5.5. Le problme du labyrinte. 152
2.4.5.6. La somme maximale des lments dun
vecteur, condition quil ny ait pas deux
lments voisins 154
2.4.5.7. La plus longue sous-file commune pour
deux files.. 155
2.4.5.8. Reconstitution dune phrase. 156
2.4.5.9. Le problme de la matrice binaire qui on
peut ajouter une unit 158
2.4.5.10
Le problme du domino 160
2.5 ALGORITHMES GNTIQUES 166
2.5.1 Dfinition et courte histoire.. 166
2.5.2 Termes biologiques utiliss pour les algorithmes
gntiques. 167
2.5.3 La structure dun algorithme gntique 170
2.5.4 Exemples de programmes gntiques... 172
2.5.4.1. Le maximum dune fonction dans un
intervalle donn 172
2.5.4.2. La solution dune quation dans un
intervalle donn 181
3 BIBLIOGRAPHIE 185
193