Informatique UV21 Exercices corrigés sur les boucles

Documents pareils
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

Organigramme / Algorigramme Dossier élève 1 SI

Examen Médian - 1 heure 30

Licence Sciences et Technologies Examen janvier 2010

Cours d algorithmique pour la classe de 2nde

Corrigé des TD 1 à 5

Recherche dans un tableau

Algorithmique et Programmation, IMA

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Propagation sur réseau statique et dynamique

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

Factorisation Factoriser en utilisant un facteur commun Fiche méthode

Introduction à MATLAB R

Cours Informatique Master STEP

Sub CalculAnnuite() Const TITRE As String = "Calcul d'annuité de remboursement d'un emprunt"

Résolution d équations non linéaires

Initiation à la programmation en Python

UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux.

Probabilités. Rappel : trois exemples. Exemple 2 : On dispose d un dé truqué. On sait que : p(1) = p(2) =1/6 ; p(3) = 1/3 p(4) = p(5) =1/12

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

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

Algorithmique et structures de données I

Algorithmique et programmation : les bases (VBA) Corrigé

# 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>

Par combien de zéros se termine N!?

Solutions du chapitre 4

Continuité et dérivabilité d une fonction

Programmer en JAVA. par Tama

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

Notions fondamentales du langage C# Version 1.0

Représentation des Nombres

MATLAB : COMMANDES DE BASE. Note : lorsqu applicable, l équivalent en langage C est indiqué entre les délimiteurs /* */.

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

Java Licence Professionnelle CISII,

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

Définitions. Numéro à préciser. (Durée : )

Feuille TD n 1 Exercices d algorithmique éléments de correction

Reconstruction de bâtiments en 3D à partir de nuages de points LIDAR


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

Les structures de données. Rajae El Ouazzani

Fonctions homographiques

Initiation à la Programmation en Logique avec SISCtus Prolog

Cours de Systèmes d Exploitation

Exo7. Limites de fonctions. 1 Théorie. 2 Calculs

Résolution de systèmes linéaires par des méthodes directes

= constante et cette constante est a.

Algorithmique & programmation

Chapitre 3. Quelques fonctions usuelles. 1 Fonctions logarithme et exponentielle. 1.1 La fonction logarithme

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

Algorithmes récursifs

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Souad EL Bernoussi. Groupe d Analyse Numérique et Optimisation Rabat http ://

I. Cas de l équiprobabilité

Chapitre 2. Eléments pour comprendre un énoncé

TRIGONOMETRIE Algorithme : mesure principale

IMAGES NUMÉRIQUES MATRICIELLES EN SCILAB

Le calcul formel dans l enseignement des mathématiques

Pourquoi l apprentissage?

Programmation linéaire

Cours 1 : Introduction Ordinateurs - Langages de haut niveau - Application

Chapitre 2 Devine mon nombre!

STAGE IREM 0- Premiers pas en Python

Initiation à LabView : Les exemples d applications :

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Vers l'ordinateur quantique

Chap 4: Analyse syntaxique. Prof. M.D. RAHMANI Compilation SMI- S5 2013/14 1

MIS 102 Initiation à l Informatique

1 Recherche en table par balayage

Arithmétique binaire. Chapitre. 5.1 Notions Bit Mot

V- Manipulations de nombres en binaire

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

COMMANDES SQL... 2 COMMANDES DE DEFINITION DE DONNEES... 2

Représentation d un entier en base b

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

avec des nombres entiers

Travaux Pratiques de Commande par ordinateur 1 TRAVAUX PRATIQUES

Les algorithmes de base du graphisme

Exo7. Matrice d une application linéaire. Corrections d Arnaud Bodin.

La fonction exponentielle

Baccalauréat ES Polynésie (spécialité) 10 septembre 2014 Corrigé

L ALGORITHMIQUE. Algorithme

Compression Compression par dictionnaires

TP 2 Réseaux. Adresses IP, routage et sous-réseaux

Comparaison de fonctions Développements limités. Chapitre 10

Encryptions, compression et partitionnement des données

Baccalauréat L spécialité, Métropole et Réunion, 19 juin 2009 Corrigé.

La persistance des nombres

LES REGLEMENTS AVEC SOCIEL.NET DERNIERE MISE A JOUR : le 14 juin 2010

Architecture des ordinateurs TD1 - Portes logiques et premiers circuits

FctsAffines.nb 1. Mathématiques, 1-ère année Edition Fonctions affines

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

Cours de C. Petits secrets du C & programmation avancée. Sébastien Paumier

Contexte. Pour cela, elles doivent être très compliquées, c est-à-dire elles doivent être très différentes des fonctions simples,

Chp. 4. Minimisation d une fonction d une variable

Exo7. Calculs de déterminants. Fiche corrigée par Arnaud Bodin. Exercice 1 Calculer les déterminants des matrices suivantes : Exercice 2.

Transcription:

Informatique UV21 Exercices corrigés sur les boucles Exercice 1 Proposer un algorithme permettant de tester si une chaîne de caractères (contenue dans une variable s) est un palindrome. Le résultat (vrai/faux) sera stocké dans une variable booléenne b. Un palindrome est une chaîne de caractères qui se lit de la même manière de gauche à droite et de droite à gauche. Par exemple, "kayak" est un palindrome mais "baobab" n en est pas un. Correction : Analyse : on est donc amené à comparer les lettres d un mot. Pour "baobab" par exemple, nous comparons la première et la 6eme (et dernière), puis la 2eme et la 5eme, puis la 3eme et la 4eme. Le mot est un palindrome si pour toutes les comparaisons on a la même lettre, ce qui n est pas le cas pour "baobab". Plus généralement, notons n la longueur (le nombre de lettres) du mot. Il s agit donc de comparer les lettres de position 1 et n, puis 2 et n-1, puis 3 et n-2, etc. Autrement dit, il s agit de comparer les lettres de position i et n+1-i pour i=1,2,3, Question : où faut-il s arrêter? Il suffit de s arrêter «au milieu» du mot. Pour "baobab", qui contient 6 lettres, on s arrête pour i=3 (comparaison des lettres 3 et 6+1-3=4). Pour "kayak" (de longueur impaire), on s arrête pour i=2 (comparaison des lettres 2 et 4). Il est donc inutile de comparer quand i dépasse (strictement) n/2. Solution 1 : boucle pour Première variante (la plus naturelle) : on initialise b à vrai, et on le met à faux si l on trouve une position où le test ne marche pas (le mot n est pas un palindrome). Deuxième variante (ça marche aussi ) : on compte le nombre de tests qui sont justes. Si tous n les tests sont justes on met b à vrai, sinon b vaut faux. Il y a 2 tests (iquo(n,2) en Maple) attention à ne pas se tromper avec les cas n pair et n impair...

Variante 1 Variante 2 c:=0: for i from 1 to n/2 do for i from 1 to n/2 do if s[i]<>s[n+1-i] then if s[i]=s[n+1-i] then c:=c+1: if c=iquo(n,2) then b:=true else fi : Remarques : - on peut faire une boucle de 1 à n (au lieu de n/2), cela marcherait tout aussi bien (en changeant le test en conséquence dans la variante 2). Simplement, on ferait des tests inutiles car on ferait chaque test 2 fois. - Dès que l on a trouvé un test faux, il est inutile de continuer (le mot n est pas un palindrome). On pourrait rajouter une instruction break: après (version 1). Cette instruction fait «sortir» de la boucle. Là encore, cela économise des tests inutiles. Erreur classique à éviter : Le programme suivant ne fonctionne pas. for i from 1 to n/2 do if s[i]<>s[n+1-i] then else En effet, si le test est vrai, il ne faut pas remettre b à vrai! Si b était déjà vrai, ça ne change rien, mais si b était faux, cela signifie qu un test avait montré que le mot n est pas un palindrome, b doit rester faux! Exemple d exécution avec "rosser". Avant la boucle, b vaut vrai. Quand i=1, on compare les lettres de position 1 et 6, le test est faux et b vaut vrai. Quand i=2, on compare "o" et "e" donc b devient faux. Quand i=3, on compare "s" et "s" donc b redevient vrai! Solution 2 : boucle tant que Il est également possible d utiliser non pas une boucle pour mais une boucle tant que. Voici les deux variantes transformées en boucle tant que.

Variante 1 Variante 2 c:=0: i:=1: i:=1: while i<=n/2 do while i<=n/2 do if s[i]<>s[n+1-i] then if s[i]=s[n+1-i] then c:=c+1: i:=i+1: i:=i+1: if c=iquo(n,2) then b:=true else fi : Remarques : - Ne pas oublier d initialiser i (i:=1:) et de le mettre à jour à chaque passage dans la boucle (i:=i+1:). - Ne pas mettre la mise à jour (i:=i+1:) dans le test (entre et ). Il faut mettre à jour à chaque passage. - On pourrait remplacer le test i<=n/2 par (i<=n/2 and b). Cela permettrait de sortir de la boucle quand b est faux et, comme précédemment, d éviter des tests inutiles. Autre solution : On peut aussi réécrire le mot à l envers, puis comparer le mot obtenu avec le mot initial. Par exemple, si le mot est "baobab", l écriture inversée est "baboab". On va alors tester les lettres des mots "baobab" et "baboab" une par une, et répondre faux si une lettre au moins diffère, vrai si toutes les lettres sont les mêmes. s2:="": for i from 1 to length(s) do s2:=cat(s[i],s2): for i from 1 to n do if s[i]<>s2[i] then La première boucle consiste à créer l image inversée du mot s (variable s2). Comme précédemment, on pourrait faire en réalité faire une boucle uniquement de 1 à n/2, cela éviterait des tests inutiles.

Exercice 2 On considère des dépenses effectuées dans différents postes budgétaires. A chaque dépense est associée le nom du fournisseur, sous forme de liste de deux éléments (nom du fournisseur et montant de la dépense), par exemple [``Dupont'', 877]. Nous considérons alors la liste de ces dépenses, donc une liste de listes LL. Un même fournisseur pourra apparaître plusieurs fois. Par exemple: [["Dupont", 87],["Ets Moulin", 233],["Martin", 877],["Durand", 82],["Dupont", 4269],["Dupont", 321],["Martin", 921]] Donner un algorithme permettant de construire la liste récapitulative contenant les dépenses totales faites auprès de chaque fournisseur, et de l'afficher. Dans l'exemple, cela doit donner:[["dupont", 4677],["Ets Moulin", 233],["Martin", 1798],["Durand", 82]] Correction : Dans la liste des dépenses, on ne connaît pas ni l ordre des fournisseurs, ni le nombre de fois ou chacun d eux apparaît. L objectif étant de «résumer» la liste (sommer les dépenses pour chaque fournisseur), il faudra prendre en compte chaque sous-liste donc la structure algorithmique à utiliser est une boucle. Il existe plusieurs structures pour faire des boucles. La question à se poser pour choisir concerne la connaissance ou non du nombre de cycles de la boucle. Soit ce nombre est connu et il faudra mettre en œuvre une boucle pour ou ce nombre n est pas connu et il faudra mettre en œuvre une boucle répéter ou tant que. Dans notre cas, puisqu on doit prendre en compte chaque sous liste, on connaît le nombre d itérations, il s agira d une boucle pour. On peut donc pour le moment résumer la solution à : > # partie relative au traitement du ieme fournisseur de la # liste LL Remarque : 1) le premier élément d une liste est à la position 1 et le dernier à la position nops(liste). 2) La variable i utilisée dans la boucle ne doit pas être modifiée dans la partie relative au traitement d un fournisseur. La valeur de cette variable est gérée par la boucle et vous assure d accéder à tous les fournisseurs. La boucle étant définie, le second problème concerne le traitement de la i éme dépense. Le problème est qu il faut pour la i ème dépense prendre en compte le résultat du traitement des i-1 premières dépenses (pour savoir notamment s il y a déjà eu des dépenses relatives au fournisseur de la i ème dépense). Pour pouvoir le faire, il faut avoir enregistré le résultat des traitements précédents. La seule solution est d enregistrer les résultats précédents dans une nouvelle liste que nous appellerons resultat.

Sur l exemple, la liste résultat vaudra successivement : - i=1 : [["Dupont", 87]] - i=2 : [["Dupont", 87],["Ets Moulin", 233]] - i=3 : [["Dupont", 87],["Ets Moulin", 233],["Martin", 877]] - i=4 : [["Dupont", 87],["Ets Moulin", 233],["Martin", 877],["Durand", 82]] - i=5 : [["Dupont", 4356],["Ets Moulin", 233],["Martin", 877], ["Durand", 82]] - i=6 : [["Dupont", 4356],["Ets Moulin", 233],["Martin", 1798], ["Durand", 82]] - i=7 : [["Dupont", 4677],["Ets Moulin", 233],["Martin", 1798],["Durand", 82]] Erreur classique : La liste résultat doit être initialisée. La difficulté est de savoir quand cette initialisation doit être faîte. Le code ci-dessous est faux : > resultat = [] ; # partie relative au traitement du ieme fournisseur de la # liste LL prenant en compte les résultats des i-1 # fournisseurs enregistrés dans resultat. Quel que soit le traitement dans la partie non encore décrite, cette solution ne peut être que fausse. A toutes les itérations, la variable résultat est initialisée à NULL effaçant le résultat enregistré au cycle précédent. Pour vous en convaincre, il suffit d afficher la valeur de résultat juste avant end do. > resultat = [] ; # Traitement illustratif : resultat := op(resultat), LL[i] ; print(resultat); end do: Dans cet exemple, les éléments de LL devraient être ajoutés les uns après les autres mais le mauvais placement de l initialisation provoque l effacement des valeurs enregistrées. La solution est donc de n initialiser resultat qu une seule fois, avant la boucle. L algorithme correct est donc : > resultat = []; # partie relative au traitement du ieme fournisseur de la # liste LL prenant en compte les résultats des i-1 # fournisseurs enregistrés dans resultat. A présent, il faut traiter chaque nouvelle dépense en fonction du contenu de la liste résultat. Nous avons 2 cas : soit le fournisseur a déjà été pris en compte et est donc enregistré dans résultat (cas i=5,6,7 dans l exemple), soit c est un nouveau fournisseur du point de vue de resultat (cas i=1,2,3,4 dans l exemple). A présent il faut donc savoir si le fournisseur est déjà enregistré dans résultat ou pas. La seule solution est de parcourir la liste résultat et de regarder élément par élément si le nom du fournisseur correspond à celui qui est recherché. De nouveau, il faut prévoir une boucle et donc s interroger sur sa nature. Connaît-on le nombre de cycles (d itérations)?

La réponse est non car le nombre de cycles dépend du succès de la recherche d un fournisseur : 1) le fournisseur recherché est nouveau alors on regardera tous les éléments de la liste, le nombre de cycles est donc de nops(resultat) ; 2) le fournisseur n est pas nouveau et on doit arrêter la boucle dés qu on l a trouvé. Comme on ne sait pas a priori quand on s arrêtera on choisit une boucle tant que : resultat = [] ; while <test> do # recherche du fournisseur end do # partie relative au traitement du ieme fournisseur # sachant s il est connu ou pas. Remarque : <notation> signifie que c est une partie de la déclaration qui reste à remplir. La nouvelle boucle doit nous permettre de savoir si c est un nouveau fournisseur ou pas. Sorti de cette boucle on devra modifier la liste resultat en conséquence. La boucle while doit prendre fin dés qu on a trouvé le fournisseur ou qu on a atteint la fin de la liste resultat, ce dernier cas correspondant à un échec de la recherche (c est un nouveau fournisseur). Comment écrire le test : ( ( <test concernant l échec de la recherche>) and (<test concernant le nom du fournisseur>) ) La boucle continue tant que le test est vrai. <test concernant l échec de la recherche> : il y a succès tant qu on teste des éléments dans résultat dont la position est inférieur à la taille de résultat. Par conséquent, il faut une variable (que nous appellerons position) pour connaître la position de l élément auquel on accède. <test concernant le nom du fournisseur> : il y a succès si le nom recherché (premier élément du i ème élément de LL) est différent du nom du fournisseur courant (premier élément de chaque position ème élément). Donc on obtient : ( (position <= nops(resultat)) and (LL[j,1] <> resultat[position][1]) ) Remarque : les notations [j,1] et [j][1] sont équivalentes. Une variable ne peut pas être utilisée avant d avoir eu une valeur. Dans notre test, j est connue mais pas position. Il faut donc ajouter au programme une commande pour donner à position sa valeur initiale et une autre pour modifier sa valeur afin de tester un autre fournisseur. Nous obtenons donc le programme : > resultat := [LL[1]]; position := 1; while ( (position <= nops(resultat)) and (LL[i][1] <> resultat[position,1])) do position := position + 1; # partie relative au traitement du ieme fournisseur # sachant s'il est connu ou pas.

Donc on incrémente la valeur de position pour tester chaque fournisseur, jusqu à ce qu il soit trouvé ou que l on ai testé tous les fournisseurs de résultats. Sorti de la boucle on doit modifier résultat en fonction du succès de la recherche. Il y a donc deux questions à se poser : 1) comment sait on si la recherche a abouti ou pas? 2) comment modifie-t-on résultat selon le succès? Pour la première question, il faut se demander dans quel état, quelles sont les valeurs de mes variables en fonction du succès de la boucle. La seule information qu on l on ait vient de la valeur de la variable position qui dépend du succès de la boucle. Soit la recherche a abouti (un fournisseur a été trouvé), soit elle a échoué. Dans le premier cas, la valeur de position n est pas connue mais on peut déduire que sa valeur est inférieure à la taille de la liste résultat. Cette information est suffisante adapter son comportement. > resultat := []; position := 1; while ( (position <= nops(resultat)) and (LL[i][1] <> resultat[position,1])) do position := position + 1; if (position <= nops(resultat)) then # le fournisseur existe il faut modifier l'information # enregistrée dans resultat else # le fournisseur est nouveau, il faut l'ajouter à #résultat. end if; Enfin il faut modifier résultat. Si le fournisseur est connu on ajoute le montant à celui déjà enregistré resultat[position][2] := resultat[position,2] + LL[i,2] ; S il est inconnu, il faut l ajouter à la liste. resultat := [op(resultat),ll[i]]; L algorithme final est donc : > resultat := []; position := 1; while ( (position <= nops(resultat)) and (LL[i][1] <> resultat[position,1])) do position := position + 1; if (position <= nops(resultat)) then resultat[position,2] := resultat[position,2] + LL[i,2] ; else resultat := [op(resultat),ll[i]]; end if;