TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2...

26
Institut Galil´ ee Algorithmique, arbres et graphes Ann´ ee 2006-2007 L2 TD Tous Exercice 1 (R´ ecursivit´ e). 1. Que calcule la fonction suivante (donn´ ee en pseudo-code et en C)? Fonction Toto(n ) si n =0 alors retourner 1; sinon retourner n × Toto(n - 1); /* Fonction toto en C */ unsigned int toto(unsigned int n){ if (n == 0) return 1; return n * toto(n - 1); } 2. En remarquant que n 2 =(n - 1) 2 +2n - 1 ´ ecrire une fonction r´ ecursive (en C ou en pseudo- code) qui calcule le carr´ e d’un nombre entier postif. 3. ´ Ecrire une fonction r´ ecursive qui calcule le pgcd de deux nombres entiers positifs. 4. Que calcule la fonction suivante ? Fonction Tata(n ) si n 1 alors retourner 0; sinon retourner 1+ Tata ( n 2 ) ; /* Fonction tata en C */ unsigned int tata(unsigned int n){ if (n <= 1) return 0; return 1 + tata(n / 2); } Correction 1. 1. Factorielle. 2. Adaptation facile de la pr´ ec´ edente : unsigned int carre(unsigned int n){ if (n == 0) return 0; return carre(n - 1) + 2 * n - 1; } 3. On utilise pgcd(a, b)= a si b = 0 et pgcd(a, b) = pgcd(b, a mod b). unsigned int pgcd(unsigned int a, unsigned int b){ if (a < b) return pgcd(b, a); if (b == 0) return a; return pgcd(b, a % b); } 4. Pour n> 0, la fonction Tata(n) calcule log n en base 2. Exercice 2 (Tours de Hano¨ ı). On se donne trois piquets, p 1 , p 2 , p 3 et n disques perc´ es de rayons diff´ erents enfil´ es sur les piquets. On s’autorise une seul op´ eration : eplacer-disque(p i , p j ) qui d´ eplace le disque du dessus du piquet p i vers le dessus du piquet p j . On s’interdit de poser un disque d sur un disque d si d est plus grand que d . On suppose que les disques sont tous rang´ es sur le premier piquet, p 1 , par ordre de grandeur avec le plus grand en dessous. On doit d´ eplacer ces n disques vers le troisi` eme piquet p 2 . On cherche un algorithme (en pseudo-code ou en C) pour r´ esoudre le probl` eme pour n quelconque. 1

Transcript of TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2...

Page 1: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Institut Galilee Algorithmique, arbres et graphesAnnee 2006-2007 L2

TD Tous

Exercice 1 (Recursivite).

1. Que calcule la fonction suivante (donnee en pseudo-code et en C) ?

Fonction Toto(n)

si n = 0 alorsretourner 1;

sinonretourner n×Toto(n− 1);

/* Fonction toto en C */

unsigned int toto(unsigned int n)if (n == 0) return 1;return n * toto(n - 1);

2. En remarquant que n2 = (n−1)2 +2n−1 ecrire une fonction recursive (en C ou en pseudo-code) qui calcule le carre d’un nombre entier postif.

3. Ecrire une fonction recursive qui calcule le pgcd de deux nombres entiers positifs.

4. Que calcule la fonction suivante ?

Fonction Tata(n)

si n ≤ 1 alorsretourner 0;

sinonretourner 1 + Tata

(⌊n2

⌋);

/* Fonction tata en C */

unsigned int tata(unsigned int n)if (n <= 1) return 0;return 1 + tata(n / 2);

Correction 1.

1. Factorielle.

2. Adaptation facile de la precedente :

unsigned int carre(unsigned int n)if (n == 0) return 0;return carre(n - 1) + 2 * n - 1;

3. On utilise pgcd(a, b) = a si b = 0 et pgcd(a, b) = pgcd(b, a mod b).

unsigned int pgcd(unsigned int a, unsigned int b)if (a < b) return pgcd(b, a);if (b == 0) return a;return pgcd(b, a % b);

4. Pour n > 0, la fonction Tata(n) calcule blog nc en base 2.

Exercice 2 (Tours de Hanoı).On se donne trois piquets, p1, p2, p3 et n disques perces de rayons differents enfiles sur les piquets.On s’autorise une seul operation : Deplacer-disque(pi, pj) qui deplace le disque du dessus dupiquet pi vers le dessus du piquet pj. On s’interdit de poser un disque d sur un disque d′ si dest plus grand que d′. On suppose que les disques sont tous ranges sur le premier piquet, p1, parordre de grandeur avec le plus grand en dessous. On doit deplacer ces n disques vers le troisiemepiquet p2. On cherche un algorithme (en pseudo-code ou en C) pour resoudre le probleme pour nquelconque.

1

Page 2: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

L’algorithme consistera en une fonction Deplacer-tour qui prend en entree l’entier n et troispiquets et procede au deplacement des n disques du dessus du premier piquet vers le troisieme piqueta l’aide de Deplacer-disque en utilisant si besoin le piquet intermediaire. En C on utilisera lesprototypes suivants sans detailler le type des piquets, piquet_t ni le type des disques.

void deplacertour(unsigned int n, piquet_t p1, piquet_t p2, piquet_t p3);void deplacerdisque(piquet_t p, piquet_t q); /* p --disque--> q */

1. Indiquer une succession de deplacements de disques qui aboutisse au resultat pour n = 2.2. En supposant que l’on sache deplacer une tour de n− 1 disques du dessus d’un piquet p vers

un autre piquet p′, comment deplacer n disques ?3. Ecrire l’algorithme en pseudo-code ou en donnant le code de la fonction deplacertour.4. Combien de deplacements de disques fait-on exactement (trouver une forme close en fonction

de n) ?5. Est-ce optimal (le demontrer) ?

Correction 2.1. Facile :

deplacerdisque(p1, p2);deplacerdisque(p1, p3);deplacerdisque(p2, p3);

2. En trois coups de cuilleres a pot : on deplace la tour des n− 1 disques du dessus du premierpiquet vers le deuxieme piquet (en utilisant le troisieme comme piquet de travail), puis ondeplace le dernier disque du premier au troisieme piquet et enfin on deplace a nouveau latour de n− 1 disques, cette fois ci du deuxieme piquet vers le troisieme piquet, en utilisantle premier piquet comme piquet de travail.

3. Ce qui precede nous donne immediatement la structure d’une solution recursive :

void deplacertour(unsigned int n, piquet_t p1, piquet_t p2, piquet_t p3)if (n > 0)/* tour(n) = un gros disque D et une tour(n - 1) */deplacertour(n - 1, p1, p3, p2); /* tour(n - 1): p1 -> p2 */deplacerdisque(p1, p3); /* D: 1 -> 3 */deplacertour(n - 1, p2, p1, p3); /* tour(n - 1): p2 -> p3 */

4. On fait un = 2un−1 + 1 appels avec u0 = 0. On pose vn = un + 1 Ce qui donne vn = 2vn−1

avec v0 = 1. On obtient vn = 2n d’ou la forme close un = 2n − 1.5. Par recurrence. Ca l’est pour n = 0. On suppose que ca l’est pour une tour de n−1 elements.

Supposons qu’on ait une serie de deplacements quelconque qui marche pour une tour de nelements. Il faut qu’a un moment m on puisse deplacer le disque du dessous. On doit doncavoir un piquet vide p pour y poser ce disque et rien d’autre d’empile sur le premier piquet (ouse trouve le “gros disque”). Le cas ou p est le troisieme piquet nous ramene immediatement anotre algorithme. Dans ce cas, entre le debut des deplacements et le moment m ainsi qu’entrejuste apres le moment m et la fin des deplacements on deplace deux fois en entier une tourde taille n− 1. Notre hypothese de recurrence etablie que pour un seul de ces deplacementscomplet d’une tour on effectue au moins 2n−1 − 1 deplacements de disques. En ajoutant ledeplacement du gros disque on obtient alors que le nombre total de deplacements de disquesest minore par 2 × (2n−1 − 1) + 1 c’est a dire par 2n − 1. Reste le cas ou p est le secondpiquet. Dans ce cas, il doit y avoir un moment ulterieur m′ ou on effectue le deplacementvers le troisieme piquet (le second ne contient alors que le gros disque). On conclue alorscomme dans le cas precedent, en remarquant de plus que les etapes entre m a m′ sont uneperte de temps.

2

Page 3: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Exercice 3 (Le robot cupide).Toto le robot se trouve a l’entree Nord-Ouest d’un damier rectangulaire de N ×M cases. Il doitsortir par la sortie Sud-Est en descendant vers le Sud et en allant vers l’Est. Il a le choix achaque pas (un pas = une case) entre : descendre verticalement ; aller en diagonale ; ou se deplacerhorizontalement vers l’Est. Il y a un sac d’or sur chaque case, dont la valeur est lisible depuis laposition initiale de Toto. Le but de Toto est de ramasser le plus d’or possible durant son trajet.

On veut ecrire en pseudo-code ou en C, un algorithme Robot-cupide(x, y) qui, etant donnesle damier et les coordonnees x et y d’une case, rend la quantite maximum d’or (gain) que peutramasser le robot en se deplacant du coin Nord-Ouest jusqu’a cette case. En C, on pourra consi-derer que le damier est un tableau bidimensionnel declare globalement et dont les dimensions sontconnues.

A BC D

1. Considerons quatre cases du damier comme ci-dessus et supposons que l’on connaisse le gainmaximum du robot pour les cases A, B et C, quel sera le gain maximum pour la case D ?

2. Ecrire l’algorithme.

3. Si le robot se deplace d’un coin a l’autre d’un damier carre 4×4 combien de fois l’algorithmecalcule t-il le gain maximum sur la deuxieme case de la diagonale ? Plus generalement, lors ducalcul du gain maximum sur la case x, y combien y a-t’il d’appels au calcul du gain maximumd’une case i, j (i ≤ x, j ≤ y).

Correction 3.

1. Le gain maximum en D est la valeur en D plus le maximum entre : le gain maximum enA ; le gain maximum en B et le gain maximum en A. On peut oublier de considerer legain en A, puisqu’avec des valeurs non negatives sur chaque case, c’est toujours au moinsaussi interessant, partant de A, de passer par B ou C pour aller en D plutot que d’y allerdirectement.

2. On considere que les coordonnees sont donnees a partir de zero.

int robot_cupide(int x, int y)

/* Cas de base */if ( (x == 0) && (y == 0) ) then return Damier[x][y];

/* Autres cas particuliers */if (x == 0) then return Damier[x][y] + robot_cupide(x, y - 1);if (y == 0) then return Damier[x][y] + robot_cupide(x - 1, y);

/* Cas general x, y > 0 */return Damier[x][y] + max(robot_cupide(x - 1, y),

robot_cupide(x, y - 1));

3. Un appel a robot_cupide(3, 3) entraınera six appels a robot_cupide(1, 1). Partant dela derniere case (Sud-Est) du damier, on peut inscrire, en remontant, sur chaque case dudamier le nombre d’appels au calcul du gain sur cette case.

. . . . . . . . . 1

. . . 6 3 14 3 2 11 1 1 1

3

Page 4: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

On retrouve alors le triangle de Pascal a une rotation pres. Rien d’etonnant du fait del’identite binomiale : (

n

p

)=(

n− 1p− 1

)+(

n

p− 1

). (1)

Le nombre d’appels a Robot-cupide(i, j) fait lors du calcul du gain maximum sur la case(x, y) est (

x + y − i− j

x− i

).

Il y a donc un nombre important de repetitions des memes appels recursifs.Une version iterative stockant les gains max dans un nouveau tableau (gain[n][m] variable

globale) permet d’eviter ces repetitions inutiles.

int robot_cupide(int x, int y)int i, j;

gain[0][0] = Damier[0][0];

/* Bord Nord */for (i = 1; i <= x; i++)

gain[i][0] = Damier[i][0] + gain[i - 1][0];

/* Bord Ouest */for (j = 1; j <= y; j++)

gain[0][j] = Damier[0][j] + gain[0][j - 1];

/* Autres cases */for (j = 1; j <= y; j++)

for (i = 1; i <= x; i++) gain[i][j] = Damier[i][j]

+ max(gain[i - 1][j], gain[i][j - 1];

// affiche(x, y); <--- pour afficher...return gain[x][y];

Ce n’etait demande mais on peut chercher a afficher la suite des deplacements effectues par lerobot. On peut remarquer que le tableau des gains maximaux, c’est a dire le tableau gain apresexecution de la fonction precedente (robot iteratif), permet de retrouver la case d’ou l’on venaitquelle que soit la case ou l’on se trouve (parmi les provenances possibles, c’est celle ayant la valeurmaximum). Il est donc facile de reconstruire le trajet dans l’ordre inverse. Pour l’avoir dans le bonordre, on peut utiliser une fonction recursive d’affichage qui montre chaque coup a la remontee dela recursion c’est a dire apres s’etre appelee.

Le tableau gain[n][m] contient les gains maximaux.

void affiche(int i, int j)if (i == 0 && j == 0)

printf("depart");return;

if (i == 0)

affiche(i, j - 1); // <--| noter l’ordre de ces deux

4

Page 5: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

printf(", aller a droite"); // <--| instructions. (idem suite)return;

if (j == 0)

affiche(i - 1, j);printf(", descendre");return;

if (gain[i - 1][j] > gain[i][j - 1])

affiche(i - 1, j);printf(", descendre");

else

affiche(i, j - 1);printf(", aller a droite");

Exercice 4 (Exponentiation rapide).L’objectif de cet exercice est de decouvrir un algorithme rapide pour le calcul de xn ou x est unnombre reel et n ∈ N. On cherchera a minimiser le nombres d’appels a des operations arithmetiquessur les reels (addition, soutraction, multiplication, division) et dans une moindre mesure sur lesentiers.

1. Ecrire une fonction de prototype double explent(double x,unsigned int n) qui calculexn (en C, ou bien en pseudo-code mais sans utiliser de primitive d’exponentiation).

2. Combien de multiplication sur des reels effectuera l’appel explent(x, 4) ?

3. Calculer a la main et en effectuant le moins d’operations possibles : 34, 38, 316, 310. Danschaque cas combien de multiplications avez-vous effectue ?

4. Combien de multiplications suffisent pour calculer x256 ? Combien pour x32+256 ?

On note bk−1 . . . b0 pour l’ecriture en binaire des entiers positifs, ou b0 est le bit de poids faible etbk−1 est le bit de poids fort. Ainsi

10011 = 1× 24 + 0× 23 + 0× 22 + 1× 21 + 1× 20 = 19.

De meme que pour l’ecriture decimale, bk−1 est en general pris non nul (en decimal, on ecrit1789 et non 00001789 – sauf sur le tableau de bord d’une machine a voyager dans le temps).

5. Comment calculer x10011 en minimisant le nombre de multiplications ?

6. Plus generalement pour calculer xbk−1...b0 de combien de multiplications sur les reels aurez-vous besoin (au maximum) ?

Rappels. Si n est un entier positif alors n mod 2 (en C : n % 2) donne son bit de poids faible. Ladivision entiere par 2 decale la representation binaire vers la droite : 10111/2 = 10110/2 = 1011.

7. Ecrire une fonction (prototype double exprapide(double x, unsigned int n)) qui cal-cule xn, plus rapidement que la precedente.

8. Si on compte une unite de temps a chaque operation arithmetique sur les reels, combiend’unites de temps sont necessaires pour effectuer x1023 avec la fonction explent ? Et avecla fonction exprapide ?

9. Meme question, en general, pour xn (on pourra donner un encadrement du nombre d’opera-tions effectuees par exprapide).

5

Page 6: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Correction 4.

1. Une solution :

double explent(double x, unsigned int n)double acc = 1;int j;for (j = 0; j < n; j++)acc = acc * x;

return acc;

2. L’appel effectuera quatre multiplications (une de plus que naıvement – multiplication par 1,pour des questions d’homogeneite).

3. On calcule ainsi : 34 = (3 × 3)2 = 92 = 9 × 9 = 81. On effectue donc deux multiplications.Quand on travaille a la main on ne fait pas deux fois 3 × 3. Pour 38 = ((3 × 3)2)2 oneffectue trois multiplications, pour 316 quatre. Pour 310 on peut faire 38 × 32 c’est a dire3 + 1 + 1 = 5 multiplications. Mais si on remarque qu’il est inutile de calculer deux fois 32

(une fois pour faire 38 et une fois pour 32), on obtient que quatre multiplications suffisent.

4. On calcule :

x256 =

((((x2

)2)2)2)22

22

et

x32+256 =

((((x2)2)2

)2)2

×(((

x32)2)2

)2

Ce qui donne respectivement huit et 5 + 1 + 3 = 9 multiplications.

5. On se ramene a des calculs ou les exposants sont des puissances de deux :

x10011 = x1 × x10 × x10000

= x× x2 ×(((

x2)2)2

)2

.

On ne calcule qu’une fois x2. On obtient donc 0 + 1 + 3 + 2 = 6, six multiplications sontsuffisantes.

6. On decompose, au pire en k facteurs (relies par k− 1 multiplications) : Πk−1j=0x(2j). Et il faut

k− 1 multiplications pour obtenir la valeur de tous les k facteurs : j multiplications pour lejeme facteur fj−1 = x(2(j−1)) et une de plus (mise au carre) pour passer au j + 1ieme. Cequi fait 2k − 2 multiplications dans le pire cas.

7. Une solution :

double exprapide(double x, unsigned int n)double acc = 1;while ( n != 0 )if ( n % 2 ) acc = acc * x;n = n / 2; // <-- Arrondi par partie entiere inferieurex = x * x;

return acc;

6

Page 7: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

8. Il faut 1023 multiplications pour la version lente, et exactement 2×10−1 = 19 multiplicationspour la version rapide. L’algo est donc de l’ordre de 50 fois plus efficace sur cette entree siseules les multiplications comptent.

9. Le nombre d’operations sur les reelles (en fait des multiplications) est n dans le cas lent. Dansle cas rapide, si k est la partie entiere superieure de log2 n alors le nombre de multiplicationsest entre k et 2× k − 1. La borne basse est atteinte lorsque n est une puissance de 2 (dansce cas n = 2k). La borne haute est atteinte lorsque le developpement en binaire de n necontient que des 1 (dans ce cas n = 2k − 1).Ainsi les complexites en temps de l’agorithme lent et de l’algorithme rapide sont respective-ment en Θ(n) et en Θ(log n), ou n est l’exposant.

Exercice 5 (rue Z).Vous etes au numero zero de la rue Z, une rue infinie ou les numeros des immeubles sont desentiers relatifs. Dans une direction, vous avez les immeubles numerotes 1, 2, 3, 4, . . . et dansl’autre direction les immeubles numerotes −1, −2, −3, −4, . . . . Vous vous rendez chez un amiqui habite rue Z sans savoir a quel numero il habite. Son nom etant sur sa porte, il vous suffit depasser devant son immeuble pour le trouver (on suppose qu’il n’y a des immeubles que d’un cote et,par exemple, la mer de l’autre). On notera n la valeur absolue du numero de l’immeuble que vouscherchez (bien entendu n est inconnu). Le but de cet objectif est de trouver un algorithme pourvotre deplacement dans la rue Z qui permette de trouver votre ami a coup sur et le plus rapidementpossible.

1. Montrer que n’importe quel algorithme sera au moins en Ω(n) pour ce qui est de la distanceparcourue.

2. Trouver un algorithme efficace, donner sa complexite en distance parcourue sous la formed’un Θ(g). Demontrer votre resultat.

Correction 5. Au minimum, il faut bien se rendre chez notre ami, donc parcourir une distancede n immeubles, ce qui donne bien Ω(n). Ceci suppose que l’on sache dans quel direction partir.Autrement dit, meme si on suppose un algorithme capable d’interroger un oracle qui lui dit oualler, la complexite minimale est Ω(n).

Nous n’avons ni oracle ni carnet d’adresses. Pour etre sur d’arriver, il faut passer devantl’immeuble numero n et devant l’immeuble numero −n. On essaye differents algorithmes.

Pour le premier, on se deplace aux numeros suivants : 1, −1, 2, −2, 3, −3, . . . , k, −k, etc. Lesdistances parcourues a chaque etape sont 1, 2, 3, 4, 5, 6, . . . , 2k − 1, 2k, etc. Ainsi, si notre amihabite au numero n, respectivement au numero −n, on va parcourir une distance de :

2n−1∑i=1

i =(2n− 1)(2n)

2respectivement

2n∑i=1

i =(2n + 1)(2n)

2

en nombre d’immeubles. Cette distance est quadratique en n.Effectuer le parcours 1, −2, 3, −4, 5 etc. donnera encore un algorithme quadratique en distance.

La raison est simple : entre un ami qui habite en n ou −n et un qui habite en n + 1 ou −(n + 1)notre algorithme va devoir systematiquement parcourir une distance supplementaire de l’ordre den.

Essayons le parcours : 1, −1, 2, −2, 4, −4, 8, −8, . . . , 2k, −2k, etc.Si uk compte le temps mis pour aller en 2k et −2k (une unite par immeuble) alors :

uk = 2k+1 + 2k + 2k−1 + uk−1

u0 = 3

7

Page 8: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

En depliant, on a :

uk = 2k+1+2k+2k−1

+2k+2k−1+2k−2

+2k−1+2k−2+2k−3

...

24 +23 +22

23 +22+21

22+21+20+u0

D’ou l’on deduit que :

uk = 2k+1 + 2× 2k + 3× (k−1∑i=0

2i)− 21 − 2× 20 + u0

uk = 7× 2k − 4 = 7n− 4

Ceci pour n = 2k. Pour 2k ≤ n ≤ 2k+1, le temps mis sera majore par 7 × 2k+1 − 4 expressionelle-meme majoree par 7× (2× n)− 4 puisque 2k ≤ n. Ce qui donne un temps mis pour aller en(n,−n) majore par 14n− 4.

Donc la distance parcourue est strictement majoree par 14× n ce qui montrer que la distanceparcourue est cette fois en O(n). Conclusion, ce dernier algorithme est en Θ(n) et, en complexiteasymtotique c’est un algorithme optimal. Si notre ami habite tres loin on a economise quelquesannees de marche.

Une alternative peut etre de doubler la distance parcourue a chaque demi tour : 1, −1, 3, −5,11, ce parcours forme une suite (uk)k∈N de terme general :

uk =i=k∑i=0

(−2)i =(−2)k − 1−2− 1

.

On s’arrete lorsque |uk| ≥ n. On en deduit, apres calcul, que k = Θ(log n) et que, la aussi, le tempsest en Θ(n).

Exercice 6 (Drapeau, Dijkstra).Les elements d’un tableau (indice a partir de 0) sont de deux couleurs, rouges ou verts. Pour testerla couleur d’un element, on se donne une fonction Couleur(T , j) qui rend la couleur du j + 1ieme element (d’indice j) du tableau T . On se donne egalement une fonction Echange(T , j, k)qui echange l’element d’indice i et l’element d’indice j et une fonction Taille(T ) qui donne lenombre d’elements du tableau.

En C, on utilisera les fonctions :– int couleur(tableau_t T, unsigned int j) rendant 0 pour rouge et 1 pour vert ;– echange(tableau_t T, unsigned int j, unsigned int k) ;– unsigned int taille(tableau_t T)

ou le type des tableaux tableau_t n’est pas explicite.

1. Ecrire un algorithme (pseudo-code ou C) qui range les elements d’un tableau en mettant lesverts en premiers et les rouges en dernier. Contrainte : on ne peut regarder qu’une seule foisla couleur de chaque element.

2. Meme question, meme contrainte, lorsqu’on ajoute des elements de couleur bleue dans nos ta-bleaux. On veut les trier dans l’ordre rouge, vert, bleu. On supposera que la fonction couleurrend 2 sur un element bleu.

8

Page 9: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Correction 6.

1. Une solution :

void drapeau2(tableau_t t)int j, k;j = 0; /* les elements 0, ..., j - 1 de t sont rouges */k = taille(t) - 1;/* les elements k + 1, ..., n - 1 sont verts */while ( j < k )if ( couleur(t, j) == 0)/* Si t[j] est rouge, il est a la bonne place */j++;

else /* Si t[j] est vert on le met avec les verts */echange(t, j, k);/* Cet echange fait du nouveau t[k] un vert. On regardera la

couleur de l’ancien t[k] a l’etape suivante */k--;

/* fin du while :

On sort avec j = k sans avoir regarde la couleur de l’element acette place. Aucune importance. */

2. Une solution :

drapeau3(tableau_t t)int i, j, k;i = 0; /* Les elements 0, ..., i - 1 sont rouges */j = 0; /* Les elements i, ..., j - 1 sont verts */k = taille(t) - 1; /* Les elements k + 1, ..., n - 1 sont bleus */while ( j <= k )switch ( couleur(t, j) )case 0: /* ----------- rouge ---------------------------------*/

/* t[j] doit etre mis avec les rouges. */if ( i < j ) /* Si il y a des verts */echange(t, i, j); /* on doit le deplacer, */

/* sinon il est a la bonne place. */i++; /* Il y a un rouge de plus. */j++; /* Le nombre de verts reste le meme. */break;

case 1: /* ----------- vert --------------------------------- */j++; /* t[j] est a la bonne place. */break;

case 2: /* ----------- bleu --------------------------------- */echange(t, j, k); /* t[j] est mis avec les bleus. */k--; /* Le nombre de bleus augmente. */

Exercice 7 (Tri selection).Soit un tableau indice a partir de 0 contenant des elements deux a deux comparables. Par exemple

9

Page 10: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

des objets que l’on compare par leurs masses. On dispose pour cela d’une fonction

Comparer(T , j, k) qui rend :

−1 si T [j] > T [k]1 si T [j] < T [k]0 lorsque T [j] = T [k] (meme masses).

1. Ecrire un algorithme Minimum qui rend le premier indice auquel apparaıt le plus petit ele-ment du tableau T .

2. Combien d’appels a la comparaison effectue votre fonction sur un tableau de taille N ?

On dispose egalement d’une fonction Echanger(T , j, k) qui echange T [j] et T [k]. On se donneaussi la possibilite de selectionner des sous-tableaux d’un tableau T a l’aide d’une fonction Sous-Tableau. Par exemple T ′ = Sous-Tableau(T , j, k) signifie que T ′ est le sous-tableau de T detaille k commencant en j : T ′[0] = T [j], . . . , T ′[k − 1] = T [j + k − 1].

3. Imaginer un algorithme de tri des tableaux qui utilise la recherche du minimum du tableau.L’ecrire sous forme iterative et sous forme recursive.

4. Demontrer a l’aide d’un invariant de boucle que votre algorithme iteratif de tri est correct.5. Demontrer que votre algorithme recursif est correct. Quelle forme de raisonnement tres cou-

rante en mathematiques utilisez-vous a la place de la notion d’invariant de boucle ?6. Combien d’appels a la fonction Minimum effectuent votre algorithme iteratif et votre al-

gorithme recursif sur un tableau de taille N ? Combien d’appels a la fonction Comparercela represente t-il ? Combien d’appels a Echanger ? Donner un encadrement et decrire untableau realisant le meilleur cas et un tableau realisant le pire cas.

7. Vos algorithmes fonctionnent-ils dans le cas ou plusieurs elements du tableau sont egaux ?

Correction 7.

1. On ecrit une fonction iterative, qui parcourt le tableau de gauche a droite et maintient l’indicedu minimum parmi les elements parcourus.

int iminimum(tableau_t t) /* t ne doit pas etre vide */int j, imin;imin = 0;for (j = 1; j < taille(t); j++)/* Si T[imin] > T[j] alors le nouveau minimum est T[j] */if ( 0 > comparer(t, imin, j) ) imin = j;

return imin;

2. On fait exactement taille(tab)− 1 = N − 1 appels.3. On cherche le minimum du tableau et si il n’est pas deja a la premiere case, on echange sa

place avec le premier element. On recommence avec le sous-tableau commencant au deuxiemeelement et de longueur la taille du tableau de depart moins un. ca s’ecrit en iteratif commececi :

1 void triselection(tableau_t tab)2 int n, j;3 for (n = 0; n < taille(tab) - 1; n++) 4 j = iminimum(sous_tableau(tab, n, taille(tab) - n));5 if (j > 0) echanger(tab, n + j, n);6 7

et en recursif comme ceci :

10

Page 11: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

1 void triselectionrec(tableau_t tab)2 int j;3 if ( taille(tab) > 1 )4 j = iminimum(tab);5 if (j > 0) echanger(tab, j, 0);6 triselectionrec(soustableau(tab, 1, taille(tab) - 1));7 8

4. Traitons le cas iteratif.

On pose l’invariant : le tableau a toujours le meme ensemble d’elements mais ceuxindices de 0 a n−1 sont les n plus petits elements dans le bon ordre et les autres sont indicesde n a N − 1 (ou on note N pour taille(tab)).

Initialisation. Avant la premiere etape de boucle n = 0 et la propriete est trivialementvraie (il n’y a pas d’element entre 0 et n− 1 = −1).

Conservation. Supposons que l’invariant est vrai au debut d’une etape quelconque. Ilreste a trier les elements de n a la fin. On considere le sous-tableau de ces elements. A laligne 4 on trouve le plus petit d’entre eux et j prend la valeur de son plus petit indice dansle sous-tableau (il peut apparaıtre a plusieurs indices). L’indice de cet element e dans letableau de depart est n + j. Sa place dans le tableau trie final sera a l’indice n puisque lesautres elements du sous-tableau sont plus grands et que dans le tableau general ceux avantl’indice n sont plus petits. A la ligne 5 on place l’element e d’indice n + j a l’indice n (si jvaut zero il y est deja on ne fait donc pas d’echange). L’element e′ qui etait a cette placeest mis a la place desormais vide de e. Ainsi, puisqu’on procede par echange, les elementsdu tableau restent inchanges globalement. Seul leur ordre change. A la fin de l’etape n estincremente. Comme l’element que l’on vient de placer a l’indice n est plus grand que leselements precedents et plus petits que les suivants, l’invariant de boucle est bien verifie al’etape suivante.

Terminaison. La boucle termine lorsque on vient d’incrementer n a N − 1. Dans ce casl’invariant nous dit que : (i) les elements indices de 0 a N − 2 sont a leur place, (ii) quel’element indice N − 1 est plus grand que tout ceux la, (iii) que nous avons la tous leselements du tableau de depart. C’est donc que notre algorithme resout bien le probleme dutri.Pour le cas recursif on raisonne par recurrence (facile). On travaille dans l’autre sens quepour l’invariant : on suppose que le tri fonctionne sur les tableaux de taille n−1 et on montrequ’il marche sur les tableaux de taille n.

5. Pour le tri iteratif : on appelle la fonction iminimum autant de fois qu’est executee la boucle(3-6), c’est a dire N − 1 fois. Le premier appel a iminimum se fait sur un tableau de tailleN , puis les appels suivant se font en decrementant de 1 a chaque fois la taille du tableau,le dernier se faisant donc sur un tableau de taille 2. Sur un tableau de taille K iminimumeffectue K − 1 appels a des comparaisons cmptab. On ne fait pas de comparaison ailleursque dans iminimum. Il y a donc au total

∑Nk=2 k − 1 =

∑N−1k=1 k = N(N−1)

2 appels a cmptab.Chaque execution de la boucle (3-6) peut donner lieu a un appel a echangetab. Ceci fait apriori entre 0 et N − 1 echanges. Le pire cas se realise, par exemple, lorsque l’entree est untableau dont l’ordre a ete inverse. Dans ce cas on a toujours j > 0 puisque, a la ligne 4, leminimum n’est jamais le premier element du sous tableau passe en parametre. Le meilleurcas ne survient que si le tableau passe en parametre est deja trie (dans ce cas j vaut toujours0).

11

Page 12: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

La version recursive fournit une formule de recurrence immediate donnant le nombre decomparaisons un pour une entree de taille n, qui se reduit immediatement :

u1 = 0un = un−1 + 1

⇐⇒ un = n− 1.

Donc N − 1 comparaisons pourun tableau de taille N . On fait au plus un echange a chaqueappel et le pire et le meilleur cas sont realises comme precedemment. Cela donne entre 0 etN − 1 echanges.

6. Reponse oui (il faut relire les demonstrations de correction). De plus on remarque qu’avec lamaniere dont a ete ecrite notre recherche du minimum, le tri est stable. Un tri est dit stablelorsque deux elements ayant la meme cle de tri (ie egaux par comparaison) se retrouventdans le meme ordre dans le tableau trie que dans le tableau de depart. Au besoin on peuttoujours rendre un tri stable en augmentant la cle de tri avec l’indice de depart. Par exempleen modifiant la fonction de comparaison de maniere a ce que dans les cas ou les deux clessont egales on rende le signe de k − j.

Exercice 8 (Interclassement).Soient deux tableaux d’elements comparables t1 et t2 de tailles respectives n et m, tous les deuxtries dans l’ordre croissant.

1. Ecrire un algorithme d’interclassement des tableaux t1 et t2 qui rend le tableau trie de leurselements (de taille n + m).

2. Dans le pire des cas, combien de comparaisons faut-il faire au minimum, quel que soit l’algo-rithme choisi, pour reussir l’interclassement lorsque n = m ? Votre algorithme est-il optimal ?(Demontrer vos resultats).

Correction 8.

1. On ecrit en C. On ne s’occupe pas de l’allocation memoire, on suppose que le tableau danslequel ecrire le resultat a ete alloue et qu’il est passe en parametre.

/* ------------------------------------------------------------------------ *//* Interclassement de deux tableaux avec ecriture dans un troisieme tableau *//* ------------------------------------------------------------------------ */void interclassement(tableau_t t1, tableau_t t2, tableau_t t)int i, j, k;i = 0;j = 0;k = 0;for (k = 0; k < taille(t1) + taille(t2); k++)if ( j == taille(t2) )/* on a fini de parcourir t2 */for (; k < taille(t1) + taille(t2); k++)t[k] = t1[i];

i++;break; /* <-------- sortie de boucle */

if ( i == taille(t1) )/* on a fini de parcourir t1 */for (; k < taille(t1) + taille(t2); k++)t[k] = t2[j];

j++;break; /* <-------- sortie de boucle */

12

Page 13: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

if ( t1[i] <= t2[j] )/* choix de l’element suivant de t : */t[k] = t1[i]; /* - dans t1; */i++;

else t[k] = t2[i]; /* - dans t2. */j++;

2. En pire cas, notre algorithme effectue n + m− 1 comparaisons.Pour trouver un minorant du nombre de comparaisons, quel que soit l’algorithme on raisonnesur le tableau trie t obtenu en sortie. Dans le cas ou n = m, il contient 2n elements. Onconsidere l’origine respective de chacun de ses elements relativement aux deux tableauxdonnes en entree. Pour visualiser ca, on peut imaginer que les elements ont une couleur, noirs’ils proviennent du tableau t1, blanc s’ils proviennent du tableau t2. On se restreint auxentrees telles que dans t l’ordre entre deux elements est toujours strict (pas de repetitionsdes cles de tri).

Lemme 1. Quel que soit l’algorithme, si deux elements consecutifs t[i], t[i+1] de t ontdes provenances differentes alors ils ont necessairement ete compares.

Preuve. Supposons que ce soit faux pour un certain algorithme A. Alors, sans perte degeneralites (quitte a echanger t1 et t2), il existe un indice i tel que : t[i] est un element dutableau t1, disons d’indice j dans t1 ; t[i+1] est un element du tableau t2, disons d’indice kdans t2 ; ces deux elements ne sont pas compares au cours de l’interclassement. (Remarque :i est egal a j + k). On modifie les tableaux t1 et t2 en echangeant t[i] et t[i+1] entre cesdeux tableaux. Ainsi t1[j] est maintenant egal a t[i+1] et t2[k] est egal a t[i]. Que faitA sur cette nouvelle entree ? Toute comparaison autre qu’une comparaison entre t1[j] ett2[k] donnera le meme resultat que pour l’entree precedente (raisonnement par cas), idempour les comparaisons a l’interieur du tableau t. Ainsi l’execution de A sur cette nouvelleentree sera identique a l’execution sur l’entree precedente. Et t1[j] sera place en t[i] tandisque t2[k] sera place en t[i + 1]. Puisque maintenant t1[j] est plus grand que t2[k], Aest incorrect. Contradiction.Ce lemme donne un minorant pour le nombre de comparaisons egal au nombre d’alternanceentre les deux tableaux dans le resultat. En prenant un tableau t trie de taille 2n on construitdes tableaux en entree comme suit. Dans t1 on met tous les elements de t d’indices pairset dans t2 on met tous les elements d’indices impairs. Cette entree maximise le nombred’alternance, qui est alors egal a 2n− 1. Par le lemme, n’importe quel algorithme fera alorsau minimum 2n − 1 comparaisons sur cette entree (et produira t). Notre algorithme aussi.Donc du point de vue du pire cas et pour n = m notre algorithme est optimal. Des resultatsen moyenne ou pour les autres cas que n = m sont plus difficiles a obtenir pour le nombrede comparaisons. On peut remarquer que pour n = 1 et m quelconque notre algorithmen’est pas optimal en nombre de comparaisons (une recherche dichotomique de la place del’element de t1 serait plus efficace).Par contre, il est clair que le nombre minimal d’affectations sera toujours n + m, ce quicorrespond a notre algorithme.

Exercice 9 (Notation asymptotique (devoir 2006)).

1. Ces phrases ont elles un sens (expliquer) :– le nombre de comparaisons pour ce tri est au plus Ω(n3) ;– en pire cas on fait au moins Θ(n) echanges.

2. Est-ce que 2n+1 = O(2n) ? Est-ce que 22n = O(2n) ?

13

Page 14: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

3. Demontrer :

si f(n) = O(g(n)) et g(n) = O(h(n)) alors f(n) = O(h(n)) (2)si f(n) = O(g(n)) alors g(n) = Ω(f(n)) (3)si f(n) = Ω(g(n)) alors g(n) = O(f(n)) (4)si f(n) = Θ(g(n)) alors g(n) = Θ(f(n)) (5)

Correction 9. Pas de correction.

Exercice 10 (Notation asymptotique (partiel mi-semestre 2006)).

3 pt

1. Est-ce que (n + 3) log n− 2n = Ω(n) ? (1,5 pt)2. Est-ce que 22n = O(2n) ? (1,5 pt)

Correction 10.

1. On montre qu’il existe une constante positive c et un rang n0 a partir duquel (n + 3) log n−2n ≥ cn.

(n + 3) log n− 2n ≥ n(log n− 2) (∀n > 0)pour n ≥ 8, log n− 2 ≥ log 8− 2 = 1

Donc ∀n ≥ n0 = 8, (n + 3) log n− 2n ≥ 1× n.

2. On montre que c’est faux, par l’absurde. Supposons que ce soit vrai, alors :

∃c > 0,∃n0 ∈ N,∀n ≥ n0, 22n ≤ c× 2n.

Donc par croissance du log, pour n ≥ n0 et n > 0 :

2× n ≤ log c + n

ce qui donne n ≤ log c

L’ensemble des entiers naturels n’etant pas borne et c etant une constante, ceci est unecontradiction.

Exercice 11.Montrer que :

log(n!) = Ω(n log n) (6)

Correction 11.

Solution 1 Soit n > 0. Si n est pair alors n = 2k avec k > 0. Dans ce cas :

(2k)! ≥ (2k)× . . .× k ≥ k × . . .× k︸ ︷︷ ︸k+1 termes

≥ kk

Donc log((2k)!) ≥ k log k, c’est a dire log(n!) ≥ 12n log(n/2).

Si n est impair, alors n = 2k + 1 avec k ≥ 0. Dans ce cas :

(2k + 1)! ≥ (2k + 1)× . . .× (k + 1) ≥ (k + 1)× . . .× (k + 1)︸ ︷︷ ︸k+1 termes

= (k + 1)k+1

14

Page 15: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Donc log((2k + 1)!) ≥ (k + 1) log(k + 1) et donc log(n!) ≥ 12n log(n/2).

Ainsi pour n > 0 on a

log(n!) ≥ 12n log(n/2).

Pour n ≥ 4, n/2 ≥√

n, et ainsi log(n/2) ≥ log(√

n) = 12 log n.

Finalement, pour n ≥ 4,

log(n!) ≥ 14n log n.

Ce qui montre bien que log(n!) = Ω(n log n).

Solution 2 On a (faire un dessin)

log(n!) =n∑

k=2

log k ≥∫ n

1

log tdt.

Donc log(n!) ≥ [t log t]n1 = n log n − n + 1. Pour n ≥ 4, log n − 1 ≥ 12 log n. Ainsi pour n ≥ 4,

log(n!) ≥ 12n log. Ce qui conclue.

Solution 3 On suppose que n > 0. On ecrit

log(n!) =n∑

k=1

log k

Et comme pour la sommation∑n

k=1 k on somme deux fois :

2 log(n!) =n∑

k=1

log k +n∑

k=1

log(n + 1− k)

=n∑

k=1

log(k(n + 1− k))

Mais lorsque 1 ≤ k ≤ n, k(n + 1− k) est maximal pour k = n+12 et minimal pour k = 1 et k = n

(on raisonne sur (a + b)(a− b) avec a = n+12 et b = k − a).

Ainsi pour tout 1 ≤ k ≤ n, log(k(n + 1− k)) ≥ log(n).On en deduit qu’a partir du rang n = 1 :

log(n!) ≥ n log n

2.

Ce qui montre bien que log(n!) = Ω(n log n).

Exercice 12 (Complexite en moyenne du tri bulle (devoir 2006)).Le but de cet exercice est de determiner le nombre moyen d’echanges effectues au cours d’un tribulle.

On considere l’implementation suivante du tri bulle :

0 void tribulle(tableau_t *t)1 int n, k, fin;2 for (n = taille(t) - 1; n >= 1; n--) 3 /* Les elements d’indice > n sont a la bonne place. */4 fin = 1;5 for (k = 0; k < n; k++)

15

Page 16: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

6 if ( 0 > comparer(t[k], t[k + 1]) ) /* t[k] > t[k + 1] */7 echangertab(t, k, k + 1);8 fin = 0;9

10 11 if (fin) break; /* Les elements entre 0 et n - 1 sont bien ordonnes */12 13

On considere le tableau passe en entree comme une permutation des entiers de 0 a n − 1 quele tri remettra dans l’ordre 0, 1, 2, . . . , n− 1. Ainsi, pour n = 3, on considere qu’il y a 6 entreespossibles : 0, 1, 2 ; 0, 2, 1 ; 1, 0, 2 ; 1, 2, 0 ; 2, 0, 1 et 2, 1, 0.

On fait l’hypothese que toutes les permutations sont equiprobables.Une inversion dans une entree a0, . . . , an−1 est la donnee de deux indices i et j tels que i < j

et ai > aj.

1. Combien y a t-il d’inversions dans la permutation 0, 1 . . . , n − 1 ? Et dans la permutationn− 1, n− 2, . . . , 0 ?

2. Montrer que chaque echange dans le tri bulle elimine exactement une inversion.

3. En deduire une relation entre le nombre total d’inversions dans toutes les permutations de0, . . . , n− 1 et le nombre moyen d’echanges effectues par le tri bulle sur une entree de taillen.

L’image miroir de la permutation a0, a1 . . . , an−1 est la permutation an−1, an−2, . . . , a0.

4. Montrer que l’ensemble des permutations de 0, . . . , n− 1 est en bijection avec lui-meme parimage miroir.

5. Si (i, j) est une inversion dans la permutation a0, a1 . . . , an−1, qu’en est-il dans son imagemiroir ? Reciproquement ? En deduire le nombre moyen d’inversions dans une permutationdes entiers de 0 a n− 1 et le nombre moyen d’echanges effectues par le tri bulle.

Correction 12. Pas de correction voir celle du partiel 2006 (tri gnome similaire).

Exercice 13 (Complexite en moyenne du tri gnome (partiel mi-semestre 2006)).Le but de cet exercice est d’ecrire le tri gnome en C et de determiner le nombre moyen d’echangeseffectues au cours d’un tri gnome. 7 pt

Rappel du cours. Dans le tri gnome, on compare deux elements consecutifs : s’ils sontdans l’ordre on se deplace d’un cran vers la fin du tableau (ou on s’arrete si la fin estatteinte) ; sinon, on les intervertit et on se deplace d’un cran vers le debut du tableau(si on est au debut du tableau alors on se deplace vers la fin). On commence par ledebut du tableau.

1. Ecrire une fonction C de prototype void trignome(tableau_t t) effectuant le tri gnome. (2,5 pt)

Une inversion dans une entree a0, . . . , an−1 est la donnee d’un couple d’indices (i, j) tel que i < jet ai > aj.

Rappel. Un echange d’elements entre deux indices i et j dans un tableau est une operation quiintervertit l’element a l’indice i et l’element a l’indice j, laissant les autres elements a leur place.

2. Si le tri gnome effectue un echange entre deux elements, que peut on dire de l’evolution dunombre d’inversions dans ce tableau avant l’echange et apres l’echange (demontrer) ? (2,5 pt)

On suppose que le nombre moyen d’inversions dans un tableau de taille n est n(n−1)4 .

3. Si un tableau t de taille n contient f(n) inversions, combien le tri gnome effectuera d’echangessur ce tableau (demontrer) ? En deduire le nombre moyen d’echanges effectues par le trignome sur des tableaux de taille n. (2 pt)

16

Page 17: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Correction 13.

1.1 void trignome(tableau_t *t)2 int i = 0; // On part du debut du tableau t3 while ( i < taille(t) - 1 )// Tant qu’on a pas atteint la fin de t4 if ( cmptab(t, i, i + 1) < 0 )// Si (i, i + 1) inversion alors :5 echangetab(t, i, i + 1); // 1) on reordonne par echange;6 if (i > 0) i--;// 2) on recule, sauf si on etait7 else i++; // au debut, auquel cas on avance.8 9 else i++; // Sinon, on avance.

10 11

2. La seule hypothese est, qu’au cours de l’execution du tri grome (sur une entree non specifiee),a une certaine etape, un echange a eu lieu. Soit t′ le tableau juste avant cet echange, t′′ letableau juste apres cet echange, et i0 la valeur de la variable i au moment de l’echange. Unechange ne se produit que lorsque t[i] > t[i + 1] et il s’agit d’un echange entre t[i] et t[i + 1].Ainsi, dans t′, on avait t′[i0] < t′[i0+1] et t′′ est egal a t′ dans lequel on a procede a l’echangeentre les elements d’indices i0 et i0 + 1. Cet echange elimine exactement une inversion. Eneffet :– dans t′, (i0, i0 + 1) est une version, pas dans t′′

– les autres inversions sont preservees :– lorsque i < j et i, j tous deux differents de i0 et i0 + 1, (i, j) est une inversion dans t′

ssi c’est une inversion dans t′′ ;– lorsque i < i0 alors : (i, i0) est une inversion dans t′ ssi (i, i0 + 1) est une inversion dans

t′′ et (i, i0 + 1) est une inversion dans t′ ssi (i, i0) est une inversion dans t′′ ;– lorsque i0 + 1 < j alors : (i0, j) est une inversion dans t′ ssi (i0 + 1, j) est une inversion

dans t′′ et (i0 + 1, j) est une inversion dans t′ ssi (i0, j) est une inversion dans t′′ ;– et ceci prend en consideration toutes les inversions possibles dans t′ et t′′.

3. Nous venons de voir que tout echange au cours du tri gnome elimine exactement une inver-sion. Le nombre d’echanges effectues au cours du tri gnome de t est donc la difference entrele nombre d’inversions au depart, f(n), et le nombre d’inversions a fin du tri. Mais le tableaufinal est trie et un tableau trie ne contient aucune inversion. Donc le nombre d’echange estsimplement f(n).Le nombre d’echanges est egal au nombre d’inversions dans le tableau inital. Donc le nombremoyen d’echanges sur des tableaux de taille n est n(n−1)

4 .

Exercice 14 (Tris en temps lineaire 1).On se donne un tableau de taille n en entree et on suppose que ses elements sont des entierscompris entre 0 et n− 1 (les repetitions sont autorisees).

1. trouver une methode pour trier le tableau en temps lineaire, Θ(n), en fonction de n.

2. Meme question si le tableau en entree contient des elements numerotes de 0 a n− 1. Autre-ment dit, chaque element possede une cle qui est un entier entre 0 et n− 1 mais il contientaussi une autre information (la cle est une etiquette sur un produit, par exemple).

3. lorsque les cles sont des entiers entre −n et n, cet algorithme peut-il etre adaptee en un trien temps lineaire ? Et lorsque on ne fait plus de supposition sur la nature des cles ?

Correction 14.

1. Premiere solution, dans un tableau annexe on compte le nombre de fois que chaque entierapparaıt et on se sert directement de ce tableau pour produire en sortie autant de 0 quenecessaire, puis autant de 1, puis autant de 2, etc.

17

Page 18: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

void trilin1(int t[], int n)int j, k;int *aux;aux = calloc(n * sizeof(int)); //<---- allocation et mise a zeroif (aux == NULL) perror("calloc aux trilin1");for (j = 0; j < n; j++) aux[t[j]]++; // decomptek = 0;for (j = 0; j < n; j++)

while ( aux[j] > 0 ) t[k] = j;k++;aux[j]--;

// fin du while// fin du forfree(aux);

La boucle de decompte est executee n fois. Si on se contente de remarquer que aux[j]est majore par n, on va se retrouver avec une majoration quadratique. Pour montrer quel’algorithme fonctionne en temps lineaire, il faut etre plus precis sur le contenu du tableauaux. Pour cela il suffit de montrer que la somme des elements du tableau aux est egale a n(a cause de la boucle de decompte). Ainsi le nombre de fois ou le corps du while est executeest exactement n.

2. Si les elements de t ont des donnees satellites, on procede differemment : on compte dans untableau auxiliaire ; on passe a des sommes partielles pour avoir en aux[j] un plus l’indicedu dernier element de cle j ; puis on deplace les elements de t vers un nouveau tableau encommencant par la fin (pour la stabilite) et en trouvant leur nouvel indice a l’aide de aux.

tableau_t *trilin2(tableau_t *t)int j, k;int *aux;tableau_t out;aux = calloc(n * sizeof(int)); //<---- allocation et mise a zeroif (aux == NULL) perror("calloc aux trilin2");out = nouveautab(taille(t)); // <----- allocationfor (j = 0; j < n; j++) aux[cle(t, j)]++;for (j = 1; j < n; j++) aux[j] = aux[j - 1] + aux[j];for (j = n - 1; j >= 0; j--)

aux[cle(t, j)]--;*element(out, aux[cle(t, j)]) = element(t, j);

free(aux);return out;

3. Tant que l’espace des cles est lineaire en n l’algorithme sera lineaire. Dans le cas general,l’espace des cles est non borne on ne peut donc pas appliquer cette methode.

Exercice 15 (Tri par base (partiel mi-semestre 2006)).Soit la suite d’entiers decimaux 141, 232, 045, 112, 143. On utilise un tri stable pour trier cesentiers selon leur chiffre le moins significatif (chiffre des unites), puis pour trier la liste obtenue 10 ptselon le chiffre des dizaines et enfin selon le chiffre le plus significatif (chiffre des centaines).

Rappel. Un tri est stable lorsque, a chaque fois que deux elements ont la meme cle, l’ordreentre eux n’est pas change par le tri. Par exemple, en triant (2, a), (3, b), (1, c), (2, d) par chiffrescroissants, un tri stable place (2, d) apres (2, a).

18

Page 19: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

1. Ecrire les trois listes obtenues. Comment s’appelle cette methode de tri ? (1 pt)On se donne un tableau t contenant N entiers entre 0 et 10k − 1, ou k est une constante entiere.Sur le principe de la question precedente (ou k = 3 et N = 5), on veut appliquer un tri par base,en base 10 a ces entiers.

On se donne la fonction auxiliaire :

int cle(int x, int i)int j;for (j = 0; j < i; j++)x = x / 10; // <- arrondi par partie entiere inferieure.

return x % 10;

2. Que valent cle(123, 0), cle(123, 1), cle(123, 2) (inutile de justifier votre reponse) ?Plus generalement, que renvoie cette fonction ? (1,5 pt)

On suppose que l’on dispose d’une fonction auxiliaire de tri void triaux(tableau_t t, int i)qui reordonne les elements de t de maniere a ce que

cle(t[0], i) ≤ cle(t[1], i) ≤ . . . ≤ cle(t[N - 1], i).

On suppose de plus que ce tri est stable.3. Ecrire l’algorithme de tri par base du tableau t (utiliser la fonction triaux). On pourra

considerer que k est un parametre entier passe a la fonction de tri. (2 pt)4. Si le temps d’execution en pire cas de triaux est majore asymptotiquement par une fonction

f(N) de parametre la taille de t, quelle majoration asymptotique pouvez donner au tempsd’execution en pire cas de votre algorithme de tri par base ? (1 pt)

5. Demontrer par recurrence que ce tri par base trie bien le tableau t. Sur quelle variable faitesvous la recurrence ? Ou utilisez vous le fait que triaux effectue un tri stable ? (3 pt)

6. La fonction triaux utilise intensivement la fonction a deux parametres cle. Si on chercheun majorant f(N) au temps d’execution de triaux, peut on considerer qu’un appel a cleprend un temps borne par une constante ? (1 pt)

7. Decrire en quelques phrases une methode pour realiser la fonction triaux de maniere a cequ’elle s’execute en un temps lineaire en fonction de la taille du tableau (on pourra utiliserune structure de donnee). (1,5 pt)

Correction 15.1. Liste 1 : 141, 232, 112, 143, 045. Liste 2 : 112, 232, 141, 143, 045. Liste 3 : 045, 112, 141,

143, 232. Ce tri s’appelle un tri par base.2. On a cle(123, 0) = 3 ; cle(123, 1) = 2 ; cle(123, 2) = 1. Cette fonction prend un

nombre n et un indice i en entree et renvoie le i + 1 ieme chiffre le moins significatif del’expression de n en base 10. Autrement dit, si n s’ecrit bk−1 . . . b0 en base 10, alors cle(n, i)renvoie bi si i est inferieur a k − 1 et 0 sinon.

3.1 void tribase(tableau_t t, int k)2 int i;3 for (i = 0; i < k; i++)// k passages4 triaux(t, i);5 6 7

4. Sur un tableau de taille N , le tri base effectue k appels a triaux et chacun de ces appelsse fait aussi sur un tableau de taille N . Les autres operations (controle de boucle) sontnegligeables. Chacun de ces appels est majore en temps par f(N). Dans le pire cas, le tempsd’execution du tri gnome est donc majore par kf(N).

19

Page 20: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

5. Etant donne un entier n d’expression bk−1 . . . b0 en base 10, pour 0 ≤ i ≤ k−1, on lui associel’entier ci(n) d’expression bi . . . b0 (les i + 1 premiers digits les moins significatifs de n).On demontre par recurrence sur i qu’en i+1 etapes de boucle le tri gnome range les elementsdu tableau t par ordre croissant des valeurs de ci. Cas de base. Pour i = 0 (premiere etapede boucle) le tri gnome a fait un appel a triaux et celui-ci a range les elements de t parordre croissant du digit le moins significatif. Comme c0 donne ce digit le moins significatif,l’hypothese est verifiee. On suppose l’hypothese verifie apres l’etape de boucle i (i + 1 emeetape). En une etape supplementaire par l’appel a triaux, les elements de t sont trie selonleur digit d’indice i + 1 (i + 2 eme digit). Soient t[j] et t[k] deux elements quelconques dutableau apres cette etape, avec j < k. Comme le tri auxilliaire, triaux est stable si t[j] ett[k] ont meme digits d’indice i + 1 alors ils sont ranges dans le meme ordre qu’a l’etapeprecedente. Mais par hypothese a l’etape precedente ces deux elements etaient ranges selondes ci croissants, il sont donc ranges par ci+1 croissants. Si les digits d’indices i+1 de t[j] ett[k] different alors celui de t[k] est le plus grand et ainsi ci+1(t[j]) < ci+1(t[k]). Dans les deuxcas t[j] et t[k] sont ranges par ci+1 croissants. Ainsi l’hypothese est verifiee apres chaqueetape de boucle.Lorsque i = k − 1, pour tout indice j du tableau ci(t[j]) = t[j] ainsi le tableau est bien triea la fin du tri gnome.La recurrence est faite sur i qui va de 0 a k − 1 (on peut aussi considerer qu’elle porte surk). La stabilite de triaux a servi a demonter le passage de l’etape i a l’etape i + 1 de larecurrence.

6. L’execution de la fonction cle demande i + 1 etapes de boucle. Comme, lors d’un appel atriaux, i est borne par k, le temps d’execution de cle est lineaire en k (). Mais k est considerecomme une constante. Le temps d’execution de cle peut don etre considere comme bornepar une constante ().

7. Pour realiser triaux en temps lineaire, il suffit de faire un tri par denombrement, avecdonnees satellites. Il est alors pratique d’utiliser une structure de pile : on cree dix piles videsnumerotees de 0 a 9, on parcours t du debut a la fin en empilant chaque element sur la pilede numero la valeur de la cle (son i + 1 eme digit). Ceci prend N etapes. Lorsque c’est finion depile en commencant par la pile numerote 9 et en stockant les elements depiles dans ten commencant par la fin. Ceci prend encore N etapes.

Exercice 16 (Plus grande sous-suite equilibree).On considere une suite finie s = (si)0≤i≤n−1 contenant deux types d’elements a et b. Une sous-suiteequilibree de s est une suite d’elements consecutif de s ou l’element a et l’element b apparaissentexactement le meme nombre de fois. L’objectif de cet exercice est de donner un algorithme rapidequi prend en entree une suite finie s ayant deux types d’elements et qui rend la longueur maximaledes sous-suites equilibrees de s.

Par exemple, si s est la suite aababba alors la longueur maximale des sous-suites equillibreesde s est 6. Les suites aababb et ababba sont deux sous-suites equilibrees de s de cette longueur.

Pour faciliter l’ecriture de l’algorithme, on considerera que :– la suite en entree est donnee dans un tableau de taille n, avec un element par case ;– chaque cellule de ce tableau est soit l’entier 1 soit l’entier −1 (et non pas a et b).

1. Ecrire une fonction qui prend deux indices i et j du tableau, tels que 0 ≤ i < j < n, et rend1 si la sous-suite (sk)i≤k≤j est equilibree, 0 sinon.

2. Ecrire une fonction qui prend en entree un indice i et cherche la longueur de la plus grandesous-suite equilibree commencant a l’indice i.

3. En deduire une fonction qui rend la longueur maximale des sous-suites equilibrees de s.

4. Quel est la complexite asymptotique de cette fonction, en temps et en pire cas ?

5. Ecrire une fonction qui prend en entree le tableau t des elements de la suite s et cree untableau d’entiers aux, de meme taille que t et tel que aux[k] =

∑kj=0 sj.

20

Page 21: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

6. Pour que (sk)i≤k≤j soit equilibree que faut-il que aux[i] et aux[j] verifient ?

Supposons maintenant que chaque element de aux est en fait une paire d’entiers, (cle, donnee),que la cle stockee dans aux[k] est

∑kj=0 sj et que la donnee est simplement k.

7. Quelles sont les valeurs que peuvent prendre les cles dans aux ?

8. A votre avis, est-il possible de trier aux par cles croissantes en temps lineaire ? Si oui,expliquer comment et si non, pourquoi.

9. Une fois que le tableau aux est trie par cles croissantes, comment l’exploiter pour resoudrele probleme de la recherche de la plus grande sous-suite equilibree ?

10. Decrire de bout en bout ce nouvel algorithme. Quelle est sa complexite ?

11. Ecrire completement l’algorithme.

Correction 16. Pas de correction.

Exercice 17 (Listes Chaınees).Soit la structure liste definie en C par :

typedef struct cellule_selement_t element;struct cellule_s *suivant;

cellule_t;typedef cellule_t * liste_t;

1. Ecrire un algorithme recursif (et iteratif) qui permet de fusionner deux listes triees dansl’ordre croissant et retourne la liste finale. On pourra utiliser la fonctioncmpListe(liste t l1, liste t l2);qui retourne 1 si le premier element de l1 est inferieur au premier element de l2, 0 s’ils sontegaux et -1 sinon.

2. Ecrire un algorithme qui permet d’eliminer toutes les repetitions dans une liste chaınee.

Correction 17.

1. liste_t entrelacement(liste_t liste1,

liste_t liste2)

if (liste1 == NULL) return liste2;

if (liste2 == NULL) return liste1;

if ( cmpListe(liste1, liste2)>=0 )

liste1->suivant = entrelacement(

liste1->suivant, liste2);

return liste1;

else

liste2->suivant = entrelacement(

liste1, liste2->suivant);

return liste2;

liste_t entrelacIter(liste_t liste1,

liste_t liste2)

liste_t out, finale;

if(liste1==NULL)

return liste2;

if(liste2==NULL)

return liste1;

if(cmpListe(liste1, liste2)>=0)

out=liste1;

liste1=liste1->suivant;

else

out=liste2;

liste2=liste2->suivant;

finale=out;

while((liste1!=NULL)&&

(liste2!=NULL) )

if(cmpListe(liste1, liste2)>=0)

out->suivant=liste1;

liste1=liste1->suivant;

else

out->suivant=liste2;

liste2=liste2->suivant;

out=out->suivant;

21

Page 22: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

if(liste1==NULL)

out->suivant=liste2;

else

out->suivant=liste1;

return finale;

2. void elimineRepetition(liste_t liste)

liste_t courant, aux, suiv;

courant=liste;

while(courant!= NULL)

aux=courant;

do

suiv=aux->suivant;

if((suiv!=NULL) &&

(suiv->element==courant->element))

aux->suivant=suiv->suivant;

free(suiv);

else

aux=suiv;

while(aux!=NULL);

courant=courant->suivant;

Exercice 18 (Primitives de pile). 1. Definir une structure pile a l’aide d’un tableau d’elements(de type element t) de hauteur maximum N . On considerera que N est une constante donnee.

2. Ecrire les fonctions suivantes :– pile t creerPile() ; qui cree une pile vide,– int pileVide(pile t pile) ; qui retourne 1 si la pile est vide et 0 sinon,– element t depiler(pile t pile) ; qui retourne le dernier element apres l’avoir retire de la pile,– void empiler(pile t pile, element t elt) ; qui empile l’element elt,– element t dernierElement(pile t pile) ; qui retourne le dernier element empile,– void viderPile(pile t pile) ; qui vide la pile,– unsigned int hauteurPile(pile t pile) ; qui retourne la hauteur de la pile,

Correction 18.1. typedef struct

element_t tab[N];

unsigned int hauteur;

pile_s;

typedef pile_s * pile_t;

2. pile_t creerPile()

pile_t pile = (pile_t)malloc(sizeof(pile_s));

pile->hauteur=0;

return pile;

int pileVide(pile_t pile)

if(pile->hauteur==0)

return 1;

else

return 0;

element_t depiler(pile_t pile)

if(hauteurPile(pile)==0)

printf("Erreur de pile\n"); exit(-1);

pile->hauteur--;

return pile->tab[pile->hauteur];

void empiler(pile_s pile, element_t elt)

if(hauteurPile(pile)>=N)

printf("Memoire de pile insuffisante\n");

exit(-1);

pile->tab[pile->hauteur++]=elt;

element_t dernierElement(pile_t pile)

if(hauteurPile(pile)==0)

printf("Erreur de pile\n"); exit(-1);

return pile->tab[pile->hauteur-1];

void viderPile(pile_t pile)

pile->hauteur=0;

unsigned int hauteurPile(pile_t pile)

return pile->hauteur;

22

Page 23: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

Exercice 19 (Deplacement de pile).On se donne trois piles P1, P2 et P3. La pile P1 contient une suite de nombres entiers positifs. Pourla suite de l’exercice, on utilisera la structure et les operations definies dans l’exercice precedentavec des elements de type entier.

1. Ecrire un algorithme pour deplacer les entiers de P1 dans P2 de facon a avoir dans P2 tousles nombres pairs au dessus des nombres impairs.

2. Ecrire un algorithme pour copier dans P2 les nombres pairs contenus dans P1. Le contenu deP1 apres execution de l’algorithme doit etre identique a celui avant execution. Les nombrespairs doivent etre dans P2 dans l’ordre ou ils apparaissent dans P1.

Correction 19.1. void pilePaireImpaire(pile_t P1,

pile_t P2, pile_t P3)

int aux;

viderPile(P2);

viderPile(P3);

while(pileVide(P1)==0)

aux=depiler(P1);

if( (aux&1)==1)

empiler(P2, aux);

else

empiler(P3, aux);

while(pileVide(P3)==0)

aux=depiler(P3);

empiler(P2, aux);

2. void pilePaire(pile_t P1,

pile_t P2, pile_t P3)

int aux;

viderPile(P2);

viderPile(P3);

while(pileVide(P1)==0)

aux=depiler(P1);

empiler(P3, aux);

while(pileVide(P3)==0)

aux=depiler(P3);

empiler(P1, aux);

if( (aux&1)==0)

empiler(P2, aux);

Exercice 20 (Test de bon parenthesage).Soit une expression mathematique dont les elements appartiennent a l’alphabet suivant :

A = 0, . . . , 9,+,−, ∗, /, (, ), [, ].

Ecrire un algorithme qui, a l’aide d’une unique pile d’entiers, verifie la validite des parentheseset des crochets contenus dans l’expression. On supposera que l’expression est donnee sous formed’une chaıne de caracteres terminee par un zero. L’algorithme retournera 0 si l’expression estcorrecte ou −1 si l’expression est incorrecte.

Correction 20.

int verifieParenthese(char *expr)

int i, aux;

pile_t p=creerPile();

for(i=0; expr[i]!=0; i++)

switch(expr[i])

case ’(’ :

empiler(p,1); break;

case ’[’ :

empiler(p,2); break;

case ’)’ :

if(pileVide(p)==1)

return -1;

else

aux=depiler(p);

if(aux!=1)

return -1;

break;

case ’]’ :

if(pileVide(p)==1)

return -1;

else

aux=depiler(p);

if(aux!=2)

return -1;

break;

default:

23

Page 24: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

if(pileVide(p)==0)

return -1:

return 0;

Exercice 21 (Calculatrice postfixe).On se propose de realiser une calculatrice evaluant les expressions en notation postfixe. L’alphabetutilise est le suivant : A = 0, . . . , 9,+,−, ∗, / (l’operateur − est ici binaire). Pour un opera-teur n-aire P et les operandes O1, . . . , On, l’expression, en notation postfixe, associee a P sera :O1, . . . , OnP . Ainsi, la notation postfixe de l’expression (2∗5)+6+(4∗2) sera : 2 5 ∗ 6 + 4 2 ∗ +.On suppose que l’expression est valide et que les nombres utilises dans l’expression sont des entierscompris entre 0 et 9. De plus, l’expression est donnee sous forme de chaınes de caracteres termineepar un zero. Par exemple (2 ∗ 5) + 6 + (4 ∗ 2) sera donnee par la chaıne “25 ∗ 6 + 42 ∗+”.Ecrire un algorithme qui evalue une expression postfixe a l’aide d’une pile d’entiers. (On pourrautiliser la fonction int ctoi(char c)return (int)(c-’0’) ; pour convertir un caractere en entier).

Correction 21.

int calculePostfixe(char *expr)

int i, op1, op2;

pile_t p=creerPile();

for(i=0; expr[i]!=0; i++)

switch(expr[i])

case ’+’ :

op2=depiler(p);

op1=depiler(p);

empiler(p, op1+op2);

break;

case ’-’ :

op2=depiler(p);

op1=depiler(p);

empiler(p, op1-op2);

break;

case ’*’ :

op2=depiler(p);

op1=depiler(p);

empiler(p, op1*op2);

break;

case ’/’ :

op2=depiler(p);

op1=depiler(p);

empiler(p, op1/op2);

break;

default :

op1=ctoi(expr[i]);

empiler(p, op1);

return depiler(p);

Exercice 22 (Primitives de file).On souhaite implementer une file a l’aide d’un tableau circulaire.

1. Definir une structure file a l’aide d’un tableau circulaire d’elements (de type element t) detaille N . Comment doit-on choisir N pour que la navigation dans le tableau circulaire seramene a des operations tres elementaires en informatique ?

2. Ecrire les fonctions suivantes :– file t creerFile() ; qui cree une file vide,– int fileVide(file t file) ; qui retourne 1 si la file est vide et 0 sinon,– element t defiler(file t file) ; qui retourne le premier element apres l’avoir retire de la file,– void enfiler(file t file, element t elt) ; qui enfile l’element elt,– element t premierElement(file t file) ; qui retourne le premier element enfile,– void viderFile(file t file) ; qui vide la file,– unsigned int tailleFile(file t file) ; qui retourne la taille de la file.

Correction 22. On choisira N sous forme de puissance de deux. Ainsi, une operation de typex modulo N se resumera a une operation “et” logique : x & (N − 1).Avec un tableau circulaire, la file pleine et la file vide remplissent la meme condition : indexe dedebut = indexe de fin. Il faudra donc soit maintenir une case vide soit avoir un champ taille dansla structure file. Dans la suite, on maintiendra une case vide pour differencier la file pleine de lafile vide.

24

Page 25: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

1. typedef struct

element_t tab[N];

unsigned int debut;

unsigned int fin;

file_s;

typedef file_s * file_t;

2. file_t creerFile()

file_t file = (file_t)malloc(sizeof(file_s));

file->debut=0;

file->fin=0;

return file;

int fileVide(file_t file)

if(file->debut==file->fin)

return 1;

else

return 0;

element_t defiler(file_t file)

element_t val;

if(fileVide(file)==1)

printf("Erreur de file\n"); exit(-1);

val=file->tab[file->debut];

file->debut=(file->debut+1)&(N-1);

return val;

void enfiler(file_t file, element_t elt)

if(tailleFile(file)>=(N-1))

printf("Memoire de file insuffisante\n");

exit(-1);

file->tab[file->fin]=elt;

file->fin=(file->fin+1) & (N-1);

element_t premierElement(file_t file)

if(tailleFile(file)==0)

printf("Erreur de file\n"); exit(-1);

return file->tab[file->debut];

void viderFile(file_t file)

file->debut=0;

file->fin=0;

unsigned int tailleFile(file_t file)

unsigned int taille;

taille=((file->fin+N)-file->debut)&(N-1);

return taille;

Exercice 23 (Tri avec files).On se donne une file d’entiers que l’on voudrait trier avec le plus grand element en fin de file. Onn’est autorise a utiliser que fileVide et les operations suivantes :

– defilerEnfiler : Defile le premier element de la premiere file et l’ajoute a la deuxieme file.– comparer : Retourne 1 si le premier element de la premiere file est plus grand ou egal au

premier element de la deuxieme file et 0 sinon.

1. A partir des primitives de la structure file, proposer un algorithme pour chacune des deuxdernieres operations (fileVide ayant ete definie dans l’exercice precedent).

2. Donner un algorithme de tri qui utilise seulement ces trois operations et 3 files. La pile f1

contiendra les entiers a trier, f2 contiendra les entiers tries apres execution et la file f3

pourra servir de file auxiliaire. On pourra, aussi, utiliser la fonction void permuteFile(file tf1, file t f2) qui permute le contenu des deux files.

3. Le tri est-il stable ?

Correction 23.

1. void defilerEnfiler(file_t f1, file_t f2)

if(fileVide(f1)==0)

enfiler(f2, defiler(f1));

int comparer(file_t f1, file_t f2)

if( (fileVide(f1)==0) ||

(fileVide(f2)==0) )

printf("Erreur de file\n");

25

Page 26: TD Tous - mindsized.org · Institut Galil´ee Algorithmique, arbres et graphes Ann´ee 2006-2007 L2 TD Tous Exercice 1 (R´ecursivit´e). 1. Que calcule la fonction suivante (donn´ee

exit(-1);

if(premierElement(f1) >=

premierElement(f2))

return 1;

return 0;

2. void trieFile(file_t f1,

file_t f2, file_t f3)

while(fileVide(f1)==0)

while( (fileVide(f2)==0)&&

(comparer(f1,f2)==1))

defilerEnfiler(f2,f3);

defilerEnfiler(f1,f3);

while(fileVide(f2)==0)

defilerEnfiler(f2,f3);

permuteFile(f2,f3);

3. Soit a1 et a2 deux elements (de cles egaux) appartenant a la file f1 avec a1 situe avant a2.A une iteration p, a1 est trie dans f2 et a2 se trouve en tete de file dans f1. La deuxiemeboucle while va deplacer tous les elements de la tete de file jusqu’a l’element a1 (non inclus)de f2 vers f3. L’element a2 etant egale a a1, comparer(f1, f2) retournera 1, par consequenta1 sera aussi deplace vers f3. A la fin de la deuxieme boucle a2 sera place dans f3. Ainsi, a2

sera place apres a1 dans la file triee. On peut en conclure que le tri est stable.

26