UniversiteParisXII-IUT
RouteforestiereHurtault
F-77300Fontainebleau
egielskiuniv-paris12.fr
Vous avez reu une initiation ala programmationstruturee et aux stru-
tures de donnees lassiques (tableaux, strutures ou enregistrements, hiers,
...)enillustrantlesproposal'aidedulangageC.Vousavezegalementetudiela
programmationorienteeobjetenillustrantlesproposal'aidedulangageC++
(oudulangageJava).
Nousallonsmaintenantvoirl'inter^etdesstruturesdedonneesabstraiteset
etudierlesplusimportantesd'entreellesenvoyantommentlesimplementeret
desutilisationslassiquesdeelles-i.
R
EF
ERENCES
Table des matieres
1 Vue generale 1
1.1 RappelsdelangageC . . . 1
1.2 RappelsdelangageC++ . . . 1
2 Les piles 3 2.1 Notion . . . 3
2.2 Implementation . . . 4
2.2.1 ImplementationenlangageC++ . . . 4
2.2.2 ImplementationenlangageC . . . 6
2.2.3 ImplementationenlangageCorienteobjet . . . 8
2.3 Appliation1:expressionsbienparenthesees . . . 11
2.3.1 Leprobleme. . . 11
2.3.2 Veriationdubonparenthesage . . . 11
2.3.3 ImplementationenlangageC++ . . . 11
2.3.4 Exeries . . . 14
2.4 Appliation2:evaluation desexpressionsalgebriques. . . 15
2.4.1 Leprobleme. . . 15
2.4.2 Mahinespostxe . . . 15
2.4.3 Conversioninxe apostxe . . . 19
vi TABLEDESMATIERES
Table des gures
Chapitre 2
Les piles
2.1 Notion
Une pile (stak en anglais) est une struture de donnees (lineaire) dans
laquellel'aesestrestreintal'elementleplusreemmentinsere.C'estdanse
sensquel'onparled'unepile d'assiettesoud'unepiledejournaux.
Insererunelementdansune piles'appelleempilerunelement(to push en
anglais).Retirerunelementd'unepile(nonvide)s'appelledepilerunelement
(topopenanglais).Onvoitl'inter^etd'unefontionbooleennepoursavoirsiune
2.2 Implementation
2.2.1 Implementation en langage C++
Un langageorienteobjettelquelelangageC++est bien adapteal'imple-
mentation des strutures de donnees abstraites. C'est don par lui que nous
allonsommener.
Erivonsunprogramme en langageC++ qui implemente la notiondepile
de arateres omme struture auto-referente et qui teste elle-i en empilant
leslettresquionstituentlemot`Bonjour'puisquidepilejusqu'aequelapile
soitvideenaÆhantleontenudeelle-i.
Vousdevrieztrouverunprogrammeapeupresdelaformesuivante:
// pile.pp
#inlude <iostream.h>
// Element d'une pile
lass StakElt
{
// attribut
har val;
lass StakElt *suivant;
// methodes
publi:
StakElt();
StakElt(har a);
StakElt(har a, StakElt *);
har getVal();
StakElt * getSuivant();
};
StakElt::StakElt()
{
val = '\0';
suivant = NULL;
}
StakElt::StakElt(har a)
{
val = a;
suivant = NULL;
}
StakElt::StakElt(har a, StakElt *s)
{
val = a;
suivant = s;
}
har StakElt::getVal()
{
return val;
}
StakElt * StakElt::getSuivant()
{
return suivant;
// Pile
lass Stak
{
// attributs
lass StakElt *dessus;
// methodes
publi:
Stak();
void push(har a);
har pop();
int IsEmpty();
};
Stak::Stak()
{
dessus = NULL;
}
void Stak::push(har a)
{
StakElt *ptr;
ptr = new StakElt(a,dessus);
dessus = ptr;
}
int Stak::IsEmpty()
{
if (dessus==NULL) return 1;
else return 0;
}
har Stak::pop()
{
har a;
if (IsEmpty()) return '\0';
else
{
a = dessus->getVal();
dessus = dessus->getSuivant();
return a;
}
}
/* Test de la lasse pile */
void main(void)
{
Stak s;
har ;
s.push('r');
s.push('u');
s.push('o');
s.push('j');
s.push('n');
s.push('o');
s.push('B');
{
= s.pop();
out << ;
}
out << '\n';
}
dontl'exeution donne:
# g++ pile.pp
# ./a.out
Bonjour
#
2.2.2 Implementation en langage C
Un langage oriente objet tel que le langage C++ est bien adapte au test
desstruturesdedonneesabstraitesmais,malheureusement,nedonnepaslieu
aunodeexeutablesuÆsammenteÆaepourqu'onpuissel'utiliser pourles
logiielsritiquestels quelessystemesd'exploitation.
Unefoisleprototypebienaupointdansunlangageorienteobjet,onadon
inter^et alereeriredans unlangage qui donnelieu aun ode exeutableplus
eÆae.
L'analogue de notre programme i-dessusen langage C seraquelque hose
ommeequisuit:
/* pile. */
#inlude <stdio.h>
#inlude <stdlib.h>
/* Element d'une pile */
strut StakElt
{
har val;
strut StakElt *suivant;
};
har getVal(strut StakElt se)
{
return se.val;
}
strut StakElt * getSuivant(strut StakElt se)
{
return se.suivant;
}
void init(strut StakElt * se, har a, strut StakElt * suiv)
{
se->val = a;
se->suivant = suiv;
}
/* Pile */
strut Stak
strut StakElt *dessus;
};
void push(strut Stak * s, har a)
{
strut StakElt *ptr;
har ;
ptr = (strut StakElt *) mallo(sizeof(strut StakElt));
init(ptr, a, s->dessus);
s->dessus = ptr;
}
int IsEmpty(strut Stak s)
{
if (s.dessus==NULL) return 1;
else return 0;
}
har pop(strut Stak * s)
{
har a;
if (IsEmpty(*s)) return '\0';
else
{
a = getVal(*(s->dessus));
s->dessus = getSuivant(* (s->dessus));
return a;
}
}
void initStak(strut Stak *s)
{
s->dessus = NULL;
}
/* Test de la lasse pile */
void main(void)
{
strut Stak *s;
har ;
s = (strut Stak *) mallo(sizeof(strut Stak));
initStak(s);
push(s, 'r');
push(s, 'u');
push(s, 'o');
push(s, 'j');
push(s, 'n');
push(s, 'o');
push(s, 'B');
while(!(IsEmpty(*s)))
{
= pop(s);
puthar();
}
puthar('\n');
dontl'exeution donne:
# g pile.
pile.: In funtion `main':
pile.:74: warning: return type of `main' is not `int'
# ./a.out
Bonjour
#
DanslamesureounoustraduisonsequiaeteonenlangageC++,nous
obtenonsunodepropre.N'oublionspasependantleserreursquenousaurions
puommettresinousavionserite programmediretementenlangageC:
{ les attributs des strutures strut StakElt et strut Stak n'etant
pas prives,nous aurionspu avoir latentation de lesutiliser diretement
sanspasserpardesmethodesadapteessuresstrutures;
{ es methodes adaptees, telle que la methode getVal() de la struture
strut StakElt, nesontpas vraimentassoieesaux struturesorres-
pondantes;ellesapparaissentommedesfontionsordinaires;
{ il n'yapasdeonstruteurmais unemethodeinit().
2.2.3 Implementation en langage C oriente objet
Ilexisteune faonenlangage Cd'emulerl'orienteobjet ave desmethodes
assoieesauxstrutures.Reerivonsnotredernierprogrammedeettefaon:
/* pileOO. */
#inlude <stdio.h>
#inlude <stdlib.h>
/* Element d'une pile */
strut StakElt
{
/* attribut */
har val;
strut StakElt *suivant;
/* methodes */
har (*getVal)(strut StakElt *);
strut StakElt * (*getSuiv)(strut StakElt *);
};
har getValeur(strut StakElt * se)
{
return se->val;
}
strut StakElt * getSuivant(strut StakElt * se)
{
return se->suivant;
}
void init(strut StakElt * se, har a, strut StakElt * suiv)
{
se->val = a;
se->suivant = suiv;
se->getSuiv = &getSuivant;
}
/* Pile */
strut Stak
{
/* attribut */
strut StakElt *dessus;
/* methodes */
void (*push)(strut Stak *, har a);
har (*pop)(strut Stak *);
int (*IsEmpty)(strut Stak *);
};
void empile(strut Stak * s, har a)
{
strut StakElt *ptr;
har ;
ptr = (strut StakElt *) mallo(sizeof(strut StakElt));
init(ptr, a, s->dessus);
s->dessus = ptr;
}
int estVide(strut Stak * s)
{
if (s->dessus==NULL) return 1;
else return 0;
}
har depile(strut Stak * s)
{
har a;
if (s->IsEmpty(s)) return '\0';
else
{
a = (s->dessus)->getVal(s- >des sus );
s->dessus = (s->dessus)->getSuiv(s->d ess us);
return a;
}
}
void initStak(strut Stak *s)
{
s->dessus = NULL;
s->push = &empile;
s->pop = &depile;
s->IsEmpty = &estVide;
}
/* Test de la lasse pile */
void main(void)
{
strut Stak *s;
har ;
initStak(s);
s->push(s, 'r');
s->push(s, 'u');
s->push(s, 'o');
s->push(s, 'j');
s->push(s, 'n');
s->push(s, 'o');
s->push(s, 'B');
while(!(s->IsEmpty(s)) )
{
= s->pop(s);
puthar();
}
puthar('\n');
}
dontni laompilation,nil'exeution n'indiquentriendespeial:
# g pileOO.
pileOO.: In funtion `main':
pileOO.:92: warning: return type of `main' is not `int'
# ./a.out
Bonjour
#
Commentonse programme:
{ Le hampd'unestruture, parexemplelehampgetValdela struture
strut StakElt,peut^etred'untypedefontiondontilfautdelarerle
typederetouretletypedesarguments.Lasyntaxeestlasuivante:
type (*nom)(typesArguments);
pourle hampnom. Ceinous permet d'obtenirdes attributs et desme-
thodes.
{ Un hampdetypefontion d'uneentitestruturee doit^etreinitialisede
lafaonsuivante:
nom = &fontion;
oufontionestune fontiondenie(oudelaree)preedemment.
{ Iln'yanionstruteur,nidestruteur(avedesnomspredenis)pourune
struture enlangageC. Onremplaeraunonstruteurparune fontion
d'initialisation,quiestunefontionordinaire,sansoublierdeommener
parallouerunemplaementmemoirepourlepointeursurettestruture.
{ Cela peut sembler assezsophistiquede faireappelaux methodeset non
diretement auxfontionsassoiees.C'est vraidans notreaspartiulier
ou nousn'avonsfait intervenirqu'uneseuleinstantiationde nospseudo-
lasses.
Dansleasouilyaplusieursinstantiations,onpeututiliserdesfontions
dierentespourdesinstantiationsdierentesetraisonnerdefaongenerale
avelamethode.C'est leaspourlaoneptiondessystemesd'exploita-
tion,parexemple.Ondenitunsystemevirtueldehiersommepseudo-
lasse.Pourhaquetypedesystemesdehiers,oninstantie,parexemple,
2.3 Appliation 1: expressions bien parenthe-
sees
2.3.1 Le probleme
Consideronsuneexpressionutilisantdesparenthesestelleque:
(1 + [2*(3 - 4)℄ + 5)/6
Cette expression utilise deux types de parentheses: le ouple des parentheses
ouvrante `(' et fermantes `)' et elui des rohets ouvrant `[' et fermant `℄'.
Elleest bienparentheseedanslamesureouune pairedeparenthesesdem^eme
type('est-a-direparentheseourohet)nesehevauhepasaveunepairede
parenthesesd'unautretype.
Parontrel'expression:
([)℄
n'estpasbien parentheseedans lamesureou lespairesdeparenthesessehe-
vauhent:laparentheseouvranteappara^tavantlerohetfermant.
Les ompilateurs,en partiulier,verientle bon parenthesage,pourlesex-
pressionsalgebriquesertes,maisaussipourlesommentairesoupourlesblos.
2.3.2 Veriation du bon parenthesage
Lebonparenthesaged'uneha^nedearaterespeut^etreveriegr^aeaune
pile(dearateres,enfaitunepiledeparentheses):
Instantierunepilevide.Lirelesarateresjusqu'alandelaha^ne
dearateres.Silearatereestuneparentheseouvrante(d'untype
quelonque), l'empiler. Si le aratere est une parenthese fermante
et si la pile est vide, aÆher une erreur. Sinon depiler. Si le sym-
boleobtenun'estpasuneparentheseouvrantedum^emetypequela
parenthesefermante,aÆherune erreur.
Alandelaleture,sila
pilen'estpasvide,aÆheruneerreur.
Remarquons que dans le as ou une \parenthese" peut ouper plusieurs
arateres (par exemple dans le as de `/*' et `*/' pour les ommentaires en
langageC),onparledetoken aulieudearatere.
2.3.3 Implementation en langage C++
Le programme suivant,erit en langage C++, demande une ha^nede a-
rateres(delongueurinferieurea100)etenverielebonparenthesage,unique-
mentpourleoupledeparentheses`(' et`)':
// parentheses.pp
#inlude <iostream.h>
#inlude <stdio.h>
#inlude <string.h>
// Element d'une pile
{
// attribut
har val;
lass StakElt *suivant;
// methodes
publi:
StakElt();
StakElt(har a);
StakElt(har a, StakElt *);
har getVal();
StakElt * getSuivant();
};
StakElt::StakElt()
{
val = '\0';
suivant = NULL;
}
StakElt::StakElt(har a)
{
val = a;
suivant = NULL;
}
StakElt::StakElt(har a, StakElt *s)
{
val = a;
suivant = s;
}
har StakElt::getVal()
{
return val;
}
StakElt * StakElt::getSuivant()
{
return suivant;
}
// Pile
lass Stak
{
// attributs
lass StakElt *dessus;
// methodes
publi:
Stak();
void push(har a);
har pop();
int IsEmpty();
};
Stak::Stak()
{
dessus = NULL;
void Stak::push(har a)
{
StakElt *ptr;
ptr = new StakElt(a,dessus);
dessus = ptr;
}
int Stak::IsEmpty()
{
if (dessus==NULL) return 1;
else return 0;
}
har Stak::pop()
{
har a;
if (IsEmpty()) return '\0';
else
{
a = dessus->getVal();
dessus = dessus->getSuivant();
return a;
}
}
// Test des parentheses
void wp(har *mot)
{
Stak s;
har , d;
int n, i, test = 1;
n = strlen(mot);
i = 0;
while((i < n) && test)
{
= mot[i℄;
if ( == '(') s.push();
if ( == ')')
{
if (s.IsEmpty()) test = 0;
else
{
d = s.pop();
if (d != '(') test = 0;
}
}
i++;
}
if (!s.IsEmpty()) test = 0;
if (test) out << "Expression bien parenthse" << '\n';
else out << "Expression mal parenthse" << '\n';
}
// Essai
void main(void)
{
out << "Entrez une expression parenthse : ";
gets(mot);
wp(mot);
}
2.3.4 Exeries
Exerie1.-Implementerl'algorithme vui-dessusenlangageC.
Exerie2.-Implementerl'algorithme vui-dessusenlangageCorienteobjet.
Exerie3.-Implementerl'algorithme vui-dessusenlangageJava.
Exerie4.- Implementer l'algorithme vu i-dessus en prenant en ompte les
paires de parentheses `('{`)', `['{`℄' et `f'{`g' dans les divers langages de pro-
grammation.
Exerie5.- Implementer l'algorithme vu i-dessus en prenant en ompte les
pairesde parentheses`('{`)', `['{`℄', `f'{`g' et `/*'{`*/' dans lesdivers langages
2.4 Appliation2:evaluation desexpressions al-
gebriques
2.4.1 Le probleme
L'evaluationdesexpressionsalgebriquesdemandeunpetit peud'astue.
Pouruneexpressionalgebriquesimpletelleque:
1 + 2
il n'y apas deprobleme.Mais ela devientunpetit peu plusompliquepour
desexpressionstellesque:
1 + 2*3
10 - 4 - 3
2.4.2 Mahines postxe
Expressionpostxe
LelogiienpolonaisLesniewskiaintroduitlanotiondenotation postxe
danslesannees1930pourmontrerquel'onn'avaitpasbesoin,entheorie,despa-
renthesesdanslesexpressions.Ceidiminuaitlenombredesymbolesprimitifs,
equietaitl'undesbutsdujeudansesannees-la.
Au lieud'erire:
1+2*3
onerit:
123*+
L'evaluationsefaitommeei:lorsqu'onrenontreunoperande,onlemet
de^ote; lorsqu'onrenontre unoperateur,on reuperele nombred'operandes
adequats (en general deux), les derniers que l'on a mis de ^ote, on eetue
l'operationetonmetde^oteleresultat.
Dans le as de notre expression postxe: on renontre 1, que l'on met de
^ote; on renontre 2, que l'on met de ^ote; on renontre 3, que l'on met de
^ote;onrenontrel'operateurdemultipliation,onreupere3et 2,onobtient
6,quel'onmetde^ote;onrenontrel'operateurd'addition,onreupere6et1,
d'ouleresultat7.
Bienentendu,\mettrede^ote"peutsetraduireimmediatementparempiler
et\retirer"pardepiler.
Evaluation d'une expressionpostxe
Leprogrammesuivant,eritenlangageC++,permet d'evalueruneexpres-
sion postxe portant sur les quatre operations, les onstantes entieres etant
onstitueesd'unseulhire:
// postfix.pp
#inlude <iostream.h>
#inlude <stdio.h>
#inlude <string.h>
lass StakElt
{
// attribut
int val;
lass StakElt *suivant;
// methodes
publi:
StakElt();
StakElt(int a);
StakElt(int a, StakElt *);
int getVal();
StakElt * getSuivant();
};
StakElt::StakElt()
{
val = 0;
suivant = NULL;
}
StakElt::StakElt(int a)
{
val = a;
suivant = NULL;
}
StakElt::StakElt(int a, StakElt *s)
{
val = a;
suivant = s;
}
int StakElt::getVal()
{
return val;
}
StakElt * StakElt::getSuivant()
{
return suivant;
}
// Pile
lass Stak
{
// attributs
lass StakElt *dessus;
// methodes
publi:
Stak();
void push(int a);
int pop();
int IsEmpty();
};
Stak::Stak()
{
}
void Stak::push(int a)
{
StakElt *ptr;
ptr = new StakElt(a,dessus);
dessus = ptr;
}
int Stak::IsEmpty()
{
if (dessus==NULL) return 1;
else return 0;
}
int Stak::pop()
{
int a;
if (IsEmpty()) return 0;
else
{
a = dessus->getVal();
dessus = dessus->getSuivant();
return a;
}
}
// Evaluation des expressions postfixes
int postEval(har exp[℄, int *res)
{
int n, i, test = 1, a, b, ;
Stak s;
n = strlen(exp);
i = 0;
while ((i < n) && test)
{
= exp[i℄;
if (('0' <= ) && ( <= '9')) s.push( - '0');
if ( == '+')
{
if (s.IsEmpty()) test = 0;
else
{
a = s.pop();
if (s.IsEmpty()) test = 0;
else
{
b = s.pop();
= a + b;
s.push();
}
}
}
if ( == '-')
{
if (s.IsEmpty()) test = 0;
else
a = s.pop();
if (s.IsEmpty()) test = 0;
else
{
b = s.pop();
= b - a;
s.push();
}
}
}
if ( == '*')
{
if (s.IsEmpty()) test = 0;
else
{
a = s.pop();
if (s.IsEmpty()) test = 0;
else
{
b = s.pop();
= a*b;
s.push();
}
}
}
if ( == '/')
{
if (s.IsEmpty()) test = 0;
else
{
a = s.pop();
if (s.IsEmpty()) test = 0;
else
{
b = s.pop();
= b/a;
s.push();
}
}
}
i++;
}
if (!test) return -1;
if (s.IsEmpty()) return -1;
a = s.pop();
if (!s.IsEmpty()) return -1;
else
{
*res = a;
return 0;
}
}
// Test de l'evaluation des expressions postfixes
void main(void)
har exp[100℄;
int err, n;
out << "Entrez une expression postfixe : ";
gets(exp);
err = postEval(exp, &n);
if (err < 0) out << "expression non postfixe" << '\n';
else out << "resultat = " << n << '\n';
}
2.4.3 Conversion inxe a postxe
L'ideepourevalueruneexpressioninxeest,dansunepremiereetape,dela
onvertir enl'expressionpostxeorrespondantepuis,dansuneseondeetape,
d'evalueretteexpressionpostxe.
Algorithmede onversion
Oninitialiseunepiledearateresavide.Onparourtl'expressioninxede
gauhe adroiteen regardanthaquearatere.On eetue uneation suivant
lanature deelui-i:
{ Operande:onlereportetelquedansl'expressiondestination.
{ Parenthese ouvrante:onl'empile.
{ Parenthese fermante: ondepiletouslesarateresde lapilequel'on re-
portedansl'expressiondestinationjusqu'aequ'uneparentheseouvrante
soitrenontree(quel'onnereportepas).
{ Operateur:depilertouslesarateresdelapilejusqu'ae qu'onaperoit
un symbole de priorite moindre ouegale. On reporte les symboles dans
l'expressiondestination etonreempilelesymbole.
{ Finde l'expressionsoure:on depileet onreportedansl'expressiondes-
tination tousleselementsrestants.
Miseen plae
Le programme C++ suivant transforme une expression inxe en une ex-
pression postxe en suivant les reglesde preedene suivantes: parenthese et
exponentiation auniveau leplushaut, multipliationet division auniveauin-
termediaire,additionetsoustrationauniveauleplusbas.
// infix2postfix.pp
#inlude <iostream.h>
#inlude <stdio.h>
#inlude <string.h>
// Element d'une pile
lass StakElt
{
// attribut
har val;
lass StakElt *suivant;
publi:
StakElt();
StakElt(har a);
StakElt(har a, StakElt *);
har getVal();
StakElt * getSuivant();
};
StakElt::StakElt()
{
val = 0;
suivant = NULL;
}
StakElt::StakElt(har a)
{
val = a;
suivant = NULL;
}
StakElt::StakElt(har a, StakElt *s)
{
val = a;
suivant = s;
}
har StakElt::getVal()
{
return val;
}
StakElt * StakElt::getSuivant()
{
return suivant;
}
// Pile
lass Stak
{
// attributs
lass StakElt *dessus;
// methodes
publi:
Stak();
void push(har a);
har pop();
har IsEmpty();
};
Stak::Stak()
{
dessus = NULL;
}
void Stak::push(har a)
{
StakElt *ptr;
ptr = new StakElt(a,dessus);
dessus = ptr;
har Stak::IsEmpty()
{
if (dessus==NULL) return 1;
else return 0;
}
har Stak::pop()
{
har a;
if (IsEmpty()) return -1;
else
{
a = dessus->getVal();
dessus = dessus->getSuivant();
return a;
}
}
// Conversion infixe vers postfixe
har * inf2post(har exp[℄)
{
har post[100℄;
Stak s;
int n, i, j;
har , d;
n = strlen(exp);
j = 0;
for (i=0; i < n; i++)
{
= exp[i℄;
if (('0' <= ) && ( <= '9'))
{
post[j℄ = ;
j++;
}
if ( == ')')
{
if (s.IsEmpty()) return NULL;
d = s.pop();
while(d != '(')
{
post[j℄ = d;
j++;
if (s.IsEmpty()) return NULL;
d = s.pop();
}
}
if ( == '^' || == '(') s.push();
if ( == '+' || == '-')
{
d = '0';
while (!s.IsEmpty() && (d != '('))
{
d = s.pop();
if (d != '(')
{
post[j℄ = d;
j++;
if (d == '(') s.push(d);
}
s.push();
}
if ( == '*' || == '/')
{
d = '0';
while (!s.IsEmpty() && (d != '(') && (d != '+') && (d != '-'))
{
d = s.pop();
if (d != '(' && (d != '+') && (d != '-'))
{
post[j℄ = d;
j++;
}
if (d == '(' || (d != '+') || (d != '-')) s.push(d);
}
s.push();
}
}
while (!s.IsEmpty())
{
post[j℄ = s.pop();
j++;
}
post[j℄ = '\0';
puts(post);
return post;
}
// Test de l'valuation des expressions postfixes
void main(void)
{
har *exp, *post;
int n;
exp = new har[100℄;
post = new har[100℄;
out << "Entrez une expression infixe : ";
gets(exp);
post = inf2post(exp);
out << "expression postfixe assoiee : ";
puts(post);
out << '\n';
}
2.5 Exeries
Exerie1.-
Erire unpatron de lasse pile dont letype deselementsest une
variabledetype.
Exerie2.-
Erireunprogramme pourles expressionsbien parentheseesutili-