Département d’Informatique DUT Informatique S1 Année 2014/2015 Algorithmique et programmation Correction du partiel d’algorithmique et programmation 18 décembre 2014 Durée : 2 heures. Aucun document autorisé. Indications – le sujet comporte deux pages ; – lire intégralement le sujet avant de commencer ; – répondre aux questions de manière précise et concise ; – numéroter les copies s’il y en a plusieurs ; – laisser une marge de 2,5 cm minimum sur le bord gauche de chaque page ; 1 Fusion Soit deux tableaux de nombres réels, les valeurs de chacun de ces tableaux sont supposées triées par ordre croissant. Écrire un algorithme qui fusionne ces deux tableaux en un troisième tableau. Ce troisième tableau devra contenir exactement les valeurs des tableaux d’origine, et ces valeurs devront elles aussi être triées par ordre croissant. Par exemple, la fusion de 1,0 1,4 2,1 5,2 7,2 8,1 9,9 1,0 1,4 2,0 2,1 2,2 2,5 et de 2,0 2,2 2,5 2,9 3,9 4,8 5,2 6,0 4,8 5,2 5,2 6,0 7,2 7,7 8,1 9,9 7,7 donnera 2,9 3,9 Correction Données Deux tableaux de réels triés, ainsi que leurs longueurs. Résultat Un tableau de réels, résultat de la fusion des deux tableaux donnés, trié. Idée Les deux tableaux sont parcourus en même temps, et la plus petite valeur est ajoutée au fur et à mesure au tableau résultat, et cela jusqu’à avoir consommé toutes les valeurs d’un des tableaux source. Ensuite, les valeurs restantes dans l’autre tableau sont recopiées inconditionnellement. Lexique des variables longA (entier) tabA (tableau [longA] de réels) longB (entier) tabB (tableau [longB] de réels) tabC (tableau [longA + longB] de réels) i (entier) j (entier) k (entier) longueur du tableau tabA premier tableau longueur du tableau tabB deuxième tableau tableau résultat indice dans tabA indice dans tabB indice dans tabC 1 DONNÉE DONNÉE DONNÉE DONNÉE RÉSULTAT INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE Algorithme i←0 j←0 k←0 tant que i < longA ∧ j < longB faire si tabA[i] < tabB[j] alors tabC[k] ← tabA[i] i←i+1 sinon tabC[k] ← tabB[j] j ←j+1 fsi k ←k+1 ftant tant que i < longA faire tabC[k] ← tabA[i] i←i+1 k ←k+1 ftant tant que j < longB faire tabC[k] ← tabB[j] j ←j+1 k ←k+1 ftant 2 Tris 1. Écrire une fonction permettant de trier un tableau d’entiers par valeurs croissantes. Donner le nom de l’algorithme de tri utilisé. 2. Réécrire la fonction en l’adaptant pour un tableau de chaînes de caractères. Mettez en évidence ce qui change entre les deux versions. Pour comparer deux chaînes de caractères, on suppose qu’on dispose d’une fonction chCompare() qu’il n’est pas demandé d’écrire : fonction chCompare(in s1 : chaîne, in s2 : chaîne) : ret entier Compare les deux chaînes passées en paramètre suivant l’ordre lexicographique. Retourne un nombre négatif si s1 < s2, zéro si s1 = s2, ou un nombre positif si s1 > s2. Correction Cf. cours pour le premier point. Pour le second point, il faut changer : – le type des éléments du tableau (entier → chaîne) ; – les type de la variable permettant de stocker une valeur (valeur, min, tmp, . . ., selon l’algorithme choisi) ; – l’opération de comparaison entre deux valeurs, en la remplaçant par un appel à la fonction chCompare(). 3 Recherche dichotomique 1. Qu’est-ce que la recherche dichotomique, dans quels cas peut-elle s’appliquer ? Expliquez son principe. 2. Écrire, en langage algorithmique, une fonction permettant de rechercher un élément dans un tableau de nombres réels en utilisant le principe de la recherche dichotomique. Vous donnerez deux versions : une version récursive et une version itérative. 3. Pour chacune des deux fonctions écrites précédemment, donner une trace d’exécution pour la recherche successive des valeurs 30, 0 et 21 dans un tableau de réels contenant les valeurs 1, 5, 9, 12, 15, 21, 29. 1 5 Le tableau. 9 12 15 2 21 29 Correction Cf. cours pour les deux premiers points. Cf. TD pour le dernier point. Tableau: [ 1, 5, 9, 12, 15, 21, 29 ] Recherche de 30 =============== -> rechDichoRec(tab, 0, 6, 30): milieu = 3, tab[milieu] = 12 -> rechDichoRec(tab, 4, 6, 30): milieu = 5, tab[milieu] = 21 -> rechDichoRec(tab, 6, 6, 30): milieu = 6, tab[milieu] = 29 -> rechDichoRec(tab, 7, 6, 30): deb > fin <- -1 <- -1 <- -1 <- -1 -> rechDichoIter(tab, min (0) <= max (6), min (4) <= max (6), min (6) <= max (6), min (7) > max (6) <- -1 0, 6, 30): milieu = 3, tab[milieu] = 12 milieu = 5, tab[milieu] = 21 milieu = 6, tab[milieu] = 29 Recherche de 0 =============== -> rechDichoRec(tab, 0, 6, 0): milieu = 3, tab[milieu] = 12 -> rechDichoRec(tab, 0, 2, 0): milieu = 1, tab[milieu] = 5 -> rechDichoRec(tab, 0, 0, 0): milieu = 0, tab[milieu] = 1 -> rechDichoRec(tab, 0, -1, 0): deb > fin <- -1 <- -1 <- -1 <- -1 -> rechDichoIter(tab, min (0) <= max (6), min (0) <= max (2), min (0) <= max (0), min (0) > max (-1) <- -1 0, 6, 0): milieu = 3, tab[milieu] = 12 milieu = 1, tab[milieu] = 5 milieu = 0, tab[milieu] = 1 Recherche de 21 =============== -> rechDichoRec(tab, 0, 6, 21): milieu = 3, tab[milieu] = 12 -> rechDichoRec(tab, 4, 6, 21): milieu = 5, tab[milieu] = 21 <- 5 <- 5 -> rechDichoIter(tab, 0, 6, 21): min (0) <= max (6), milieu = 3, tab[milieu] = 12 min (4) <= max (6), milieu = 5, tab[milieu] = 21 <- 5 4 Carré magique Un carré magique est un carré de nombres tel que les sommes des nombres sur chacune de ses lignes, colonnes et diagonales sont les mêmes. 4.1 Vérification Écrire un algorithme permettant de vérifier si un tableau 2D de nombres est un carré magique. Correction 3 Données Un tableau carré de nombres entier avec sa longueur de côté. Résultat Un booléen indiquant si on a affaire à un carré magique. Idée On commence par calculer les sommes sur les diagonales. Si elles sont égales, le carré est supposé magique. Dans ce cas, les sommes sur chacune des lignes et chacune des colonnes sont calculées et comparées à la somme sur la diagonale. Si une des sommes ne correspond pas, le carré n’est pas magique, et l’algorithme s’arrête. Si l’algorithme s’arrête après avoir parcouru toutes les lignes et toutes les colonnes, le carré est magique. Lexique des cote carre magique sDiag sADiag sLig sCol i j variables (entier) (tableau [cote, cote] d’entiers) (booléen) (entier) (entier) (entier) (entier) (entier) (entier) côté du carré tableau d’entiers à tester le carré est-il magique ? somme sur la diagonale somme sur l’antidiagonale somme sur une ligne somme sur une colonne indice pour le parcours indice pour le parcours DONNÉE DONNÉE RÉSULTAT INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE Algorithme sDiag ← 0 sADiag ← 0 pour i de 0 à cote − 1 faire sDiag ← sDiag + carre[i, i] sADiag ← sADiag + carre[i, cote − 1 − i] fpour magique ← sDiag = sADiag i←0 tant que magique ∧ i < cote faire sLig ← 0 sCol ← 0 pour j de 0 à cote − 1 faire sLig ← sLig + carre[i, j] sCol ← sCol + carre[j, i] fpour si sLig 6= sDiag ∨ sCol 6= sDiag alors magique ← faux fsi i←i+1 ftant 4.2 Génération Voici le principe d’un algorithme permettant de générer un carré magique de côté N (N impair), en plaçant chacun des nombres de 1 à N 2 . On peut remarquer que les sommes sont alors égales à (N (N 2 + 1))/2. (i) placer le premier nombre (1) au milieu de la première colonne. (ii) placer le nombre suivant dans la case en haut à gauche. Si on dépasse du tableau, placer le nombre sur la colonne ou la ligne opposée. (iii) recommencer l’étape (ii) N fois. On tombe alors juste avant la case d’origine. (iv) si le carré n’est pas terminé, placer le nombre suivant sur la même ligne, une colonne à droite et continuer à l’étape (ii). Exemple avec N = 5, les sommes sont égales à 65 : 65 15 8 1 24 17 65 16 14 7 5 23 65 22 20 13 6 4 65 3 21 19 12 10 65 9 2 25 18 11 65 65 65 65 65 65 65 Écrire un algorithme générant, pour N un nombre impair donné, un carré magique de côté N . 4 Correction Données Longueur du côté du carré souhaité. Résultat Tableau d’entiers formant un carré magique. Lexique des variables cote (entier) carre (tableau [cote, cote] d’entiers) lig (entier) col (entier) n (entier) i (entier) j (entier) Algorithme lig ← (cote − 1)/2 col ← 0 n←1 pour i de 1 à cote faire pour j de 1 à cote faire lig ← (lig + cote) mod cote col ← (col + cote) mod cote carre[lig, col] ← n n←n+1 lig ← lig − 1 col ← col − 1 fpour lig ← lig + 1 col ← col + 2 fpour côté du carré le carré magique numéro de ligne numéro de colonne valeur à entrer compteur compteur DONNÉE RÉSULTAT INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE INTERMÉDIAIRE // rectification des indices : // on ajoute ‘cote’ pour rester dans le domaine positif 5