TD 5 : Les piles. PC* - Lycée Thiers 2015/2016



Documents pareils
Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

STAGE IREM 0- Premiers pas en Python

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Génie Logiciel avec Ada. 4 février 2013

Exercices types Algorithmique et simulation numérique Oral Mathématiques et algorithmique Banque PT

1 Recherche en table par balayage

Cours de Systèmes d Exploitation

Université Bordeaux 1, Licence Semestre 3 - Algorithmes et struct...

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Algorithmique et Programmation, IMA

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

#include <stdio.h> #include <stdlib.h> struct cell { int clef; struct cell *suiv; };

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

TD3: tableaux avancées, première classe et chaînes

Utilisation d objets : String et ArrayList

INTRODUCTION AUX SYSTEMES D EXPLOITATION. TD2 Exclusion mutuelle / Sémaphores

Programmation linéaire

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Chapitre 4 : Exclusion mutuelle

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

Cours 7 : Utilisation de modules sous python

Les structures de données. Rajae El Ouazzani

ARDUINO DOSSIER RESSOURCE POUR LA CLASSE

Initiation à l algorithmique

Découverte de Python

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

Cours de C++ François Laroussinie. 2 novembre Dept. d Informatique, ENS de Cachan

Java Licence Professionnelle CISII,

# let rec concat l1 l2 = match l1 with [] -> l2 x::l 1 -> x::(concat l 1 l2);; val concat : a list -> a list -> a list = <fun>

Chapitre 2 Devine mon nombre!

ÉPREUVE COMMUNE DE TIPE Partie D

Intégration et probabilités TD1 Espaces mesurés Corrigé

Recherche dans un tableau

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

Architecture des Systèmes d Information Architecture des Systèmes d Information

Introduction à MATLAB R

Le théorème de Perron-Frobenius, les chaines de Markov et un célèbre moteur de recherche

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Cette application développée en C# va récupérer un certain nombre d informations en ligne fournies par la ville de Paris :

Chapitre 5 : Flot maximal dans un graphe

I. Introduction aux fonctions : les fonctions standards

Corrigé des exercices sur les références

Programmation C++ (débutant)/instructions for, while et do...while

TP 1. Prise en main du langage Python

Perl Orienté Objet BioPerl There is more than one way to do it

Manuel d utilisation 26 juin Tâche à effectuer : écrire un algorithme 2

Programmer en JAVA. par Tama

Jean-Philippe Préaux

SNT4U16 - Initiation à la programmation TD - Dynamique de POP III - Fichiers sources

Développement décimal d un réel

Fibonacci et les paquerettes

Initiation à la Programmation en Logique avec SISCtus Prolog

Exercices Types Algorithmique et simulation numérique Oral Mathématiques et Algorithmique Banque PT Propositions de réponses

Cours d initiation à la programmation en C++ Johann Cuenin

Programmation Orientée Objet Java

Exclusion Mutuelle. Arnaud Labourel Courriel : arnaud.labourel@lif.univ-mrs.fr. Université de Provence. 9 février 2011

Cours Informatique Master STEP

Les algorithmes de base du graphisme

Le langage C. Séance n 4

Les arbres binaires de recherche


Cours de Programmation Impérative: Zones de mémoires et pointeurs

Arbres binaires de recherche

Premiers Pas en Programmation Objet : les Classes et les Objets

Simulation de variables aléatoires

Module Administration BD Chapitre 1 : Surcouche procédurale dans les SGBDS

Initiation à LabView : Les exemples d applications :

Licence Sciences et Technologies Examen janvier 2010

Initiation à la programmation en Python

PHP et mysql. Code: php_mysql. Olivier Clavel - Daniel K. Schneider - Patrick Jermann - Vivian Synteta Version: 0.9 (modifié le 13/3/01 par VS)

AWS avancé. Surveiller votre utilisation d EC2

Algorithmique et Programmation

MIS 102 Initiation à l Informatique

Exercices INF5171 : série #3 (Automne 2012)

1. Structure d'un programme FORTRAN 95

* très facile ** facile *** difficulté moyenne **** difficile ***** très difficile I : Incontournable T : pour travailler et mémoriser le cours

Projet d informatique M1BI : Compression et décompression de texte. 1 Généralités sur la compression/décompression de texte

Raisonnement par récurrence Suites numériques

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

Corrigé des TD 1 à 5

De même, le périmètre P d un cercle de rayon 1 vaut P = 2π (par définition de π). Mais, on peut démontrer (difficilement!) que

Programme Compte bancaire (code)

Programmation linéaire et Optimisation. Didier Smets

Chapitre 10. Les interfaces Comparable et Comparator 1

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Théorie des Langages

LA PHYSIQUE DES MATERIAUX. Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. jabbour@cril.univ-artois.fr

Architecture des ordinateurs

Classes et Objets en Ocaml.

TP3 : Manipulation et implantation de systèmes de fichiers 1

Déroulement. Evaluation. Préambule. Définition. Définition. Algorithmes et structures de données 28/09/2009

Programmation avec des objets : Cours 7. Menu du jour

Informatique III: Programmation en C++

Chp. 4. Minimisation d une fonction d une variable

Traduction des Langages : Le Compilateur Micro Java

chapitre 4 Nombres de Catalan

1 Définition et Appel d une fonction. V. Phan Luong. Cours 4 : Fonctions

Claude Delannoy. 3 e édition C++

Transcription:

2015/2016

Exercice 1 : Pile renversée Corrigé

Consignes Pour tous les exercices de cette planche on aura préalablement écrit l implémentation des piles à capacité limitée ou illimitée vue en cours, et l on ne s autorisera à n utiliser sur les piles que leurs seules primitives : creer pile(), depiler(), empiler(,), top(,), taille(), est vide() On travaillera au choix avec des piles à capacité limitée ou illimitée. (Indication : il est légèrement plus simple d utiliser des piles à capacité illimitée, on n a pas à s occuper de leur capacité). Le corrigé utilise les piles à capacité limitée ; il s adapte presque immédiatement aux piles à capacité illimitée en ignorant tout ce qui concerne la capacité des piles.

Exercice 1 : créer une pile renversée Exercice 1. 1. Ecrire une fonction renverse(pile) prenant en argument une pile et qui retourne la pile obtenue en inversant l ordre des éléments de pile. La pile pile pourra être vidée. 2. Même question, sauf qu à la fin l argument pile doit être inchangé.

Exercice 1 : créer une pile renversée - a) On s autorise à vider pile. def renverse(pile): n = taille(pile) pile2 = creer pile(n) # supprimer n pour une pile illimitée while not(est vide(pile2)): empiler(pile2,depiler(pile)) return pile2

Exercice 1 : créer une pile renversée - b) A la fin pile doit être inchangée. On stocke les résultats dépilés dans une pile tampon, que l on utilisera à la fin pour reconstituer le contenu de pile. def renverse1(pile): n = taille(pile) pile2 = creer pile(n) pile3 = creer pile(n) # pour stoker les éléments dépilés while not(est vide(pile)): lu = depiler(pile) empiler(pile2,lu) empiler(pile3,lu) while not(est vide(pile3)): # Reremplir pile empiler(pile,depiler(pile3)) return pile2

Exercice 2. Ecrire une fonction supprime(pile,p) qui supprime dans la pile pile son p-ième élément compté en partant du sommet (indication : il faudra utiliser une deuxième pile). Si p dépasse la taille de la pile la fontion retournera False, et sinon retournera True.

- On utilise une deuxième pile pour stocker les p 1 premiers éléments dépilés avant de supprimer le p-ième élément puis de rempiler ces p 1 éléments. def suprime(pile,p): if taille(pile) < p: return False pile2 = creer pile(p-1) # supprimer p-1 si pile illimitée for i in range(p-1): empiler(pile2,depiler(pile)) depiler(pile) for i in range(p-1): empiler(pile,depiler(pile2))) return True

Exercice 3. Ecrire une fonction echange(pile,p,q) qui échange dans la pile pile ses p-ième et q-ième éléments, comptés en partant du sommet. Si p ou q dépasse la taille de la pile la fonction retournera False, et sinon retournera True.

- def echange(pile,p,q): assert isinstance(p,int) and isinstance(q,int) if taille(pile)<p or taille(pile)<q: # Cas d impossibilité return False if p == q: return True # Ici rien à faire if p > q: # pour que p soit inférieur à q p,q = q,p pile2 = creer pile(p) pile3 = creer pile(q-p) for i in range(p): empiler(pile2,depiler(pile)) for i in range(q-p): empiler(pile3,depiler(pile)) empiler(pile,depiler(pile2)) empiler(pile2,depiler(pile3)) for i in range(q-p-1): empiler(pile,depiler(pile3)) for i in range(p): empiler(pile,depiler(pile2)) return True

Adapter l algorithme vu en cours pour déterminer si un mot est bien parenthésé pour englober les cas des 3 types de parenthèses (), [], {}.

- avec 3 + 1 piles def parenthesage(mot): pile1 = creer pile(len(mot)) # création de la pile () pile2 = creer pile(len(mot)) # création de la pile [] pile3 = creer pile(len(mot)) # création de la pile {} pile0 = creer pile(len(mot)) # création de la pile mémoire" for char in mot: # Parcours du mot if char == ( : # Si ( empiler(pile1,0); empiler(pile0,1) # on empile pile1 et on mémorise elif char == [ : # Si [ empiler(pile2,0); empiler(pile0,2) # on empile pile2 et on mémorise elif char == { : # Si { empiler(pile3,0); empiler(pile0,3) # on empile pile3 et on mémorise elif char == ) : # Si ) if est vide(pile1) or depiler(pile0)!= 1: return False else: depiler(pile1) elif char == ] : # Si ] if est vide(pile2) or depiler(pile0)!= 2: return False else: depiler(pile2) elif char == } : # Si } if est vide(pile3) or depiler(pile0)!= 3: return False else: depiler(pile3) return est vide(pile1) and est vide(pile2) and est vide(pile3)

- avec 1 pile Ou encore utiliser une seule liste et empiler les différentes parenthèses ouvrantes : def parenthesage(mot): pile = creer pile(len(mot)) # création de la pile for char in mot: # Parcours du mot if char == ( : # Si ( empiler(pile, ( ) # on empile ( elif char == [ : # Si [ empiler(pile, [ ) # on empile [ elif char == { : # Si { empiler(pile, { ) # on empile { elif char == ) : # Si ) if est vide(pile) or depiler(pile)!= ( : return False elif char == ] : # Si ] if est vide(pile) or depiler(pile)!= [ : return False elif char == } : # Si } if est vide(pile) or depiler(pile)!= { : return False return est vide(pile) Cette approche est moins pratique que la précédente si l on souhaite adapter le programme pour qu il retourne aussi les positions des différentes parenthèses.

Exercice 7. Exercice 4. On se bornera aux seules parenthèses ( et ). 1. Adapter l algorithme vu en cours pour tester si une chaine est bien parenthésée, de sorte que : il retourne False pour une chaine non correctement parenthésée, il retourne la position des parenthèses pour une chaine bien parenthésée ; par exemple avec pour argument 2*(1+(3-1)) l algorithme retournera la liste : [(6,10),(3,11)].

Exercice 5. On adapte le programme vu en cours pour qu il empile les positions des parenthèses ouvrantes rencontrées. def parentheses(mot): pile = creer pile(len(mot)) result = [ ] for i in range(len(mot)): if mot[i] == ( : empiler(pile, i+1) elif mot[i] == ) : if est vide(pile): return False result.append((depiler(pile), i+1)) if est vide(pile): return result else: return False

Exercice 5. : 2ème version Plutôt que de parcourir la séquence par indice on peut mettre à profit l instruction : for i, c in enumerate(seq) qui implémente une boucle for où : c parcourt les éléments de la séquence seq, tandis que i parcourt les indices correspondants. def parentheses(mot): pile = creer pile(len(mot)) result = [ ] for i, c in enumerate(mot): if c == ( : empiler(pile,i+1) elif c == ) : if est vide(pile): return False result.append((depiler(pile),i+1)) if est vide(pile): return result else: return False

Corrigé Exercice 6. Résolution d un labyrinthe On se donnera un labyrinthe carré par un tableau carré de type ndarray (numpy). Un 0 symbolisera un passage, un 1 un mur. On prendra par exemple : import numpy as np T = np.array([ [0,0,1,0,1,0], [0,1,1,0,0,0], [0,0,0,0,1,1], pour : [1,1,1,0,1,0], [0,0,1,0,0,0], [0,0,0,0,1,0] ]) De chaque case on peut se déplacer sur une case libre voisine horizontalement ou verticalement. Entrée et sortie du labyrinthe seront des cases données par leurs indices, par exemple (0, 0) et (5, 5).

Corrigé Exercice 6. Résolution d un labyrinthe Le but de l exercice est d écrire une fonction qui détermine un chemin de l entrée à la sortie du labyrinthe par une recherche en profondeur utilisant une pile. Le principe est : Chaque case sera symbolisée par le couple (i,j) de ses indices dans le tableau. Lorsqu une case aura été déjà visité, sa valeur dans le tableau sera mise à -1. Une fonction voisin() prendra en paramètre le tableau et les indices d une case et retournera la liste de ses cases voisines libres et non déjà visitées. De chaque case on se déplacera sur une telle case voisine libre et non déjà visitée. Une pile à capacité illimitée constituera le fil d ariane : on empilera les cases visitées successivement. Dès qu une case n aura plus aucune case voisine non déjà visitée on la dépilera, pour poursuivre le trajet à partir de la case précédente.

Corrigé Exercice 6. Résolution d un labyrinthe 1. Ecrire la fonction voisin() comme décrite ci-dessus. 2. Ecrire la fonction trajet() prenant en paramètre le tableau du labyrinthe, et les couples d indices de l entrée et de la sortie, et qui retourne la pile des cases successivement visitées constituant un trajet de l entrée à la sortie. 3. La tester sur le tableau ci-dessus avec pour entrée (0,0) et sortie (5,5).

Corrigé Exercice 6. Résolution d un labyrinthe On utilise des piles à capacités illimitées. 1) def voisins(t,v): V = [] N = np.shape(t)[0] i,j = v[0],v[1] for a in (-1,1): if 0<= i+a <N: if T[i+a,j] == 0: V.append((i+a,j)) if 0<= j+a <N: if T[i,j+a] == 0: V.append((i,j+a)) return V

Corrigé Exercice 6. Résolution d un labyrinthe from copy import deepcopy def labyrinthe(t,entree,sortie): T = deepcopy(t) P = creer pile() Recherche = True v = entree empiler(p,v) while Recherche: vois = voisins(t,v) if vois == []: depiler(p) if est vide(p): return False v = top(p) else: i,j = vois[0] T[i,j] = -1 empiler(p,(i,j)) v = (i,j) if v == sortie: Recherche = False return P

Corrigé Exercice 6. Résolution d un labyrinthe In [1]: labyrinthe(t,(0,0),(5,5)) Out[1]: [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (2, 3), (3, 3), (4, 3), (4, 4), (4, 5), (5, 5)] import numpy as np T = np.array([ [0,0,1,0,1,0], [0,1,1,0,0,0], [0,0,0,0,1,1], [1,1,1,0,1,0], [0,0,1,0,0,0], [0,0,0,0,1,0] ]) pour :

Annexe. 1. Montrer qu une chaine de caractère est bien parenthésée si et seulement si : le nombre de parenthèses ouvrantes ( égale le nombre de parenthèses fermantes ), et Dans chacun de ses préfixes le nombre de parenthèses ouvrantes est supérieur ou égal au nombre de parenthèses fermantes. On pourra procéder par récurrence forte sur la longueur de la chaine. 2. En déduire la correction de l algorithme vu en cours pour déterminer si une chaine de caractère est ou non bien parenthésée.

Annexe. 1. Montrons par récurrence forte sur la longueur de la chaine que : une chaine de caractère est bien parenthésée si et seulement si : (Propriété (P)) : (Propriété (P1)) : le nombre de parenthèse ouvrante égale le nombre de parenthèse ouvrante, et (Propriété (P2)) : dans chacun de ses préfixes le nombre de parenthèses ouvrantes est supérieur ou égal au nombre de parenthèses fermantes. Rappelons qu avec les parenthèses ( et ) un mot est bien parenthésé si : 1. Il ne contient aucune parenthèse ( ou ), ou 2. Il est de la forme (m) avec m un mot bien parenthésé, ou 3. Il est la concaténation m1.m2 de 2 mots m1, m2 bien parenthésés. (plutôt que de chaine de caractère, on parlera de mot.)

Annexe. Initialisation. Le mot vide ε est bien parenthésé, et vérifie (P) puisqu il ne contient aucune parenthèse, de même que tous ses préfixes (c est à dire lui-même ε). L équivalence est trivialement vérifiée pour le mot de longueur nulle. Hérédité. Soit un entier N > 0. Supposons que l équivalence est vérifiée pour tout mot de longueur < N. On montre séparément les deux implications et. Implication directe. Soit w un mot de longueur N bien parenthésé. 1er cas : si w ne contient aucune parenthèse. Alors il en est de même de tous ses préfixes, et trivialement w vérifie la propriété (P). Ce cas est réglé. 2ème cas : Si w est de la forme w = (u) avec u un mot bien parenthésé de longueur N 2. Par hypothèse de récurrence u contient autant de ( que de ). Or w contient 1 ( de plus et 1 ) de plus que u, ainsi w contient autant de ( que de ) : w vérifie (P1).

Si w est de la forme w = (u) avec u bien parenthésé. Soit w 0 un préfixe de w. Alors soit : w 0 est le mot vide ε, et ne contient aucune parenthèse, soit w 0 = (.u 0 où u 0 est un préfixe de u. Par hypothèse de récurrence u 0 contient au moins autant de ( que de ). Or w 0 = (.u 0 contient exactement 1 ( de plus que u 0 et autant de ). Ainsi w vérifie aussi la propriété (P2). Cela montre que lorsque w = (u) avec u bien parenthésé, alors w vérifie (P). 3ème cas. si w = u.v avec u et v deux mots de longueur non-nulle bien parenthésés. Alors u et v sont de longueur < N, et par hypothèse de recurrence vérifient (P). En particulier u et v contiennent tous deux autant de ( que de ), et donc il en est de même de w : w vérifie (P1). Montrons que w vérifie aussi (P2). Soit w 0 un préfixe de w. Deux cas sont possibles : w 0 est un préfixe de u, et donc, puisque u vérifie (P), il contient au moins autant de ( que de ). w 0 = u.v 0 où v 0 est un préfixe de v. Puisque v 0 contient au moins autant de ( que de ) tandis que u contient autant des 2, alors w 0 contient au moins autant de ( que de ). Ainsi w vérifie (P2) et donc (P). Ceci conclut la preuve de l implication directe.

Implication réciproque. Soit w un mot de longueur N vérifiant la propriété (P) ; il s agit de montrer que w est bien parenthésé. 1er cas. Si w ne débute pas par une parenthèse, w = c.w où c est un caractère autre que ( ou ). Alors w est de longueur N 1 et vérifie aussi (P). Par (HR), w est bien parenthésé, et par définition c aussi, et donc, toujours par définition, leur concaténation w est bien parenthésée. 2ème cas. w =).w est impossible : cela contredirait le fait que w vérifie (P) : en effet (P2) serait mis en défaut par le préfixe ). 3ème cas. Si w = (.w. Comme ci-dessus, si w ne se termine pas par une parenthèse alors on conclut aisément que w est bien parenthésé. De plus w ne peut pas se terminer par ( car puisque w contient autant de ( que de ) alors le préfixe de longueur N 1 de w contiendrait 1 ) de plus que de ( et contredirait le fait que w vérifie (P2).

Ainsi il ne reste plus qu à considérer le cas où w = (.u.). Puisque w vérifie (P1) alors u aussi. Soit u 0 un préfixe de u = u 0.u 1. Alors (.u 0 est un préfixe de w et contient donc au moins autant de ( que de ). Soit : u 0 contient au moins autant de ( que de ), soit : (.u 0 contient autant de ( que de ). Dans ce dernier cas : (.u 0 et u 1.) contiennent autant de ( que de ) et vérifient donc (P). Par (HR) (.u 0 et u 1.) sont bien parenthésés et par définition w, concaténation des deux, est bien parenthésé. On a la conclusion souhaitée. Ainsi soit w est bien parenthésé comme concaténation de deux mots bien parenthésés, soit tout préfixe de u contient au moins autant de ( que de ), c est à dire u vérifie (P 2), et donc (P). Par (HR) u est bien parenthésé. Alors par définition w = (u) l est aussi. Dans tous les cas w est bien parenthésé, ce qui prouve la réciproque et conclut la preuve.

Annexe. du programme def parenthesage(mot): compteur = 0 for char in mot: if char == ( : compteur += 1 elif char == ) : if compteur == 0: return False else: compteur -= 1 return (compteur == 0) # Parcours du mot # Si parenthèse ouvrante # on incrémente le compteur # Si parenthèse fermante # Et si aucun ( rencontré # Alors mal parenthésé # Sinon décrémentation # retourne True si le compteur=0 Un boucle for s achève toujours, il suffit donc de vérifier que le programme retourne le résultat attendu. Chaque passage dans la boucle correspond à l un des préfixes de mot. Et la condition compteur > 0 équivaut à avoir rencontré au moins autant de ( que de ) dans ce préfixe. Ainsi la sortie de la boucle sans retourner False équivaut à la condition (P2). La condition finale compteur == 0 correspond quant à elle à (P1). Donc l algorithme retourne True si et seulement si le mot vérifie (P), c est à dire s il est bien parenthésé.