PT – IC STRUCTURE DE PILE
I. Structures de données
1) Généralités
En informatique, il est souvent important de commencer par se poser la question de comment organiser les
données que l’on va exploiter. L’objet informatique général qui permet de stocker des données s’appelle une
structure de donnée, caractérisée par les opérations qu’elle permet, et le coût de ces opérations. D’un point
de vue théorique, les principales sont :
Le tableau : C’est une structure de taille fixe, qui contient un certain nombre d’objets identiques. On accède
à n’importe quel élément en temps constant, mais on ne peut pas insérer ni supprimer d’élément;
La liste (ou liste chaînée) : Dans cette structure, chaque élément se termine par un lien vers l’élément sui-
vant. L’intérêt est que l’insertion ou la suppression d’un élément se fait en temps constant, alors que l’accès
à un élément se fait en O(n) où nest la taille de la liste;
Les ensembles : Ces structures permettent de faire rapidement des opérations comme l’intersection, la réunion
ou le test d’appartenance.
La pile : C’est l’objet du chapitre : on la détaillera plus loin.
En Python, le tableau correspond à un array du module numpy. Par contre, les list de Python sont des objets
qui tiennent à la fois du tableau (on accède directement à n’importe quel élément), de la liste chaînée (les
éléments n’ont pas besoin d’être tous identiques, et on peut changer la taille en temps amorti constant) et,
comme on va le voir, de la pile.
2) La structure de pile
Cette structure correspond exactement à l’idée intuitive que l’on s’en fait : une pile d’assiette (ou de papiers,
ou de cartes...) posée sur une table. En particulier, on ne peut accéder qu’au dernier élément que l’on a empilé,
qu’on appelle le sommet de la pile. ↑↓
C
B
A
Par exemple, si on empile successivement A, puis B, puis C, on obtient la situation ci-contre. On a
alors le choix entre deux opérations : empiler un quatrième objet D ou dépiler C. Si on veut accéder à
l’élément A, il faut commencer par dépiler C, puis B.
Ce type de structure de donnée est fondamental en informatique. Au niveau du langage machine, il sert à
gérer les appels à une fonction et le passage de paramètre. Plus proche de l’utilisateur, on le retrouve dans
tous les contextes ou on a un bouton « annuler » ou « revenir à la page précédente ».
On résume souvent le comportement d’une pile sous la forme « dernier arrivé, premier sorti » ou en anglais
« Last In, First Out » que l’on résume par l’acronyme LIFO. Il existe aussi une structure de file d’attente où le
premier arrivé est le premier sorti (First In, First Out ou FIFO). On parle dans ce cas de structure de file, mais
ce n’est pas directement au programme. On rencontre ces structures par exemple dans les serveurs d’impres-
sion d’une imprimante réseau, on dans un parcours d’arbre en largeur (mais là encore on sort du cadre du
programme).
II. Opérations sur une pile
Une pile est caractérisée par quatre opérations qui doivent prendre un temps constant (autrement dit avoir
une complexité en O(1)), indépendamment de la taille de la pile :
creerPile() : renvoie une nouvelle pile vide;
empiler(p, x) : empile x sur la pile p;
depiler(p) : dépile et renvoie le sommet de la pile p;
estVide(p) : indique si la pile p est vide.
1/4 DELAY – Paul Constans
PT – IC STRUCTURE DE PILE
D’autre fonction sont souvent utiles, même si elles ne sont pas totalement indispensables :
taille(p) : renvoie le nombre d’éléments de la pile p;
sommet(p) : renvoie le sommet de la pile p.
Exercice 1 : Écrire les fonctions précédentes. On simulera la pile par une list python.
def creerPile():
"""Renvoie une nouvelle pile vide."""
return []
def empiler(p, x):
"""Empile x sur la pile p."""
p.append(x)
def depiler(p):
"""Dépile et renvoie le sommet de la pile p."""
return p.pop()
def taille(p):
"""Renvoie le nombre d’éléments de la pile p."""
return len(p)
def estVide(p):
"""Renvoie True si la pile p est vide, False sinon."""
return taille(p) == 0
def sommet(p):
"""Renvoie le sommet de la pile p."""
return p[-1]
Remarque : Le fait d’implémenter une pile par une liste python permettrait d’autres opérations que celles
citées plus haut (par exemple accéder directement à n’importe quel élément). Dans toutes la suite, on s’inter-
dira d’accéder à une pile autrement qu’avec ces fonctions (sans quoi on ne travaille plus sur des piles!) En TP,
on commencera les scripts en important ces fonctions que l’on mettra dans une bibliothèque pile.py
Exercice 2 :
1. Écrire une fonction copierPile(p) qui prend en argument une pile pet renvoie une copie de psans modi-
fier p. Évaluer la complexité en espace (c’est à dire le coût en mémoire) et le nombre d’opérations effectuées
par cette fonction.
def copierPile(p):
"""Renvoie une copie de la liste p."""
pTmp =creerPile()
while not estVide(p): # On commence par une copie inversée de p
val =depiler(p)
empiler(pTmp, val)
pRes =creerPile()
while not estVide(pTmp): # puis on reconstruit p et sa copie
val =depiler(pTmp)
empiler(pRes, val)
empiler(p, val)
return pRes
2/4 DELAY – Paul Constans
PT – IC STRUCTURE DE PILE
En notant nla taille de la pile p, la place utilisée en mémoire est de 2nemplacements si on considère que
le fait de dépiler libère de la place, ou de 3nsinon.
Pour la complexité, on a 3nappels à empiler et 2nappels à depiler. Ces fonctions étant par définition en
O(1), on a un complexité en O(n).
2. Écrire une fonction inverserPile(p) qui prend en argument une pile pet retourne une autre pile dont
les éléments sont ceux de p, mais dans l’ordre inverse. pne doit pas être modifiée.
def inverserPile(p):
"""Renvoie une copie inversée de la pile p."""
pTmp =copierPile(p) # Sans cette précaution, on viderait la pile p
pRes =creerPile()
while not estVide(pTmp):
val =depiler(pTmp)
empiler(pRes, val)
return pRes
III. Applications
Les questions marquées (*) sont plus difficiles, ou moins fondamentales, et peuvent être gardées pour la fin.
1) Analyse des mots bien parenthésés
Vous avez remarqué que sous la plupart des EDI, l’ajout de parenthèse fermante surnuméraire est signalé,
et que les paires de parenthèses correspondantes sont surlignés. L’objectif de cette section est d’écrire un
programme qui vérifie si une chaîne de caractères ne contenant que des parenthèses est bien parenthésée. Par
exemple, ’()(())’ est correct, mais ’)(’ ne l’est pas. On se propose de plus d’indiquer, pour chaque parenthèse
ouvrante, la position de la parenthèse fermante correspondante. Par exemple, pour ’()(())’, on indiquera les
couples (0,1), (2,5) et (3,4).
L’idée de l’algorithme est de parcourir la chaîne de gauche à droite. Pour chaque caractère :
si c’est une parenthèse ouvrante, empiler son indice;
si c’est une parenthèse fermante, deux cas possibles :
si la pile est vide, c’est que cette parenthèse ne correspond à aucune parenthèse ouvrante est donc la
chaîne est mal parenthésée;
sinon, on dépile l’indice de la parenthèse ouvrante correspondante, et on affiche le couple d’indices.
Arrivé à la fin de la chaîne de caractères, la chaîne est bien parenthésée à condition que la pile soit vide.
Exercice 3 :
1. Écrire la fonction bienParenthese(s) correspondant à l’algorithme ci-dessus.
def bienParenthese(s):
"""Indique si la chaîne s est bien parenthésée, et affiche les indices des
paires de parenthèses correspondantes."""
p=creerPile()
i= 0
for car in s:
if car == ’(’:
empiler(p, i)
elif car == ’)’:
if estVide(p):
return False
3/4 DELAY – Paul Constans
PT – IC STRUCTURE DE PILE
else:
j=depiler(p)
print((i, j))
i+= 1
return estVide(p)
2. Adapter la fonction précédente pour qu’elle accepte des chaînes de caractères comprenant des paren-
thèses et d’autres caractères n’influant pas sur le résultat. Par exemple ’(2+3)-(4*(5-2)+1)’ est bien paren-
thésée, mais pas ’(5+1)*7)’. Rien à changer!!
3. (*) Adapter la fonction précédente pour qu’elle traite les mots constitués de plusieurs couples de symboles
ouvrant ou fermant (’(’, ’)’ ou ’[’, ’]’ ou ’{’, ’}’). Un mot est alors bien parenthésé si le symbole fermant cor-
respond au symbole ouvrant. Par exemple ’{()}[]’ est bien parenthésée, mais pas ’{(})’.
def bienParentheses(s):
"""Indique si la chaîne s est bien parenthésée, et affiche les indices des
paires de symboles correspondantes."""
def ouvrant(c):
"""Renvoie le symbole ouvrant correspondant à c."""
if c== ’)’:
return ’(’
if c== ’]’:
return ’[’
if c== ’}’:
return ’{’
p=creerPile()
i= 0
for car in s:
if car in ’([{’:
empiler(p, i)
elif car in ’)]}’:
if estVide(p):
return False
else:
j=depiler(p)
if ouvrant(car) == s[j]:
print((j, i))
else:
return False
i+= 1
return estVide(p)
4/4 DELAY – Paul Constans
1 / 4 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !