Vous êtes sur la page 1sur 29

Compléments d’algorithmique

(1) Types composés


Types composés
Un type composé est un type dont les variables contiennent plusieurs valeurs.
On ne peut pas utiliser des variables d’un type composé directement dans un
write, read, un calcul tel qu’une addition, etc.
Un tableau est un type composé.
Types composés : Tableaux (rappels)
Un tableau est un type composé dans lequel toutes les valeurs sont du même
type. Chaque valeur est repérée par un ou plusieurs indices compris entre des
bornes choisies à la déclaration du type.

Exemple :
type Damier = array[1..7, 1..6] of integer;

Pour accéder à un élément d’un tableau, il faut donner autant d’indices qu’il en
figure dans la déclaration du type, et chaque valeur doit être comprise dans
l’intervalle correspondant.

Exemple :
var d:Damier;
Begin
readln(d); readln(d[5,2]);
Types composés : Enregistrements
Un enregistrement est un type composé dans lequel les valeurs peuvent être de
types différents. Chacune de ces valeurs est appelée champ. Chaque champ est
repéré par un nom.
Un enregistrement permet de définir un type qui regroupe des données
(éventuellement de types différents) qui forment un tout et que l’on désire
manipuler comme une variable.

Exemple:
Informations sur un étudiant :
• Numéro INE  Entier
• Nom  Chaine de caractères
• Prénom  Chaine de caractères
• Notes  Tableau de réels
Types composés : Enregistrements

Syntaxe :
type <nomtype> =
record
<nom_du_champ1> : <type_du_champ1>;
<nom_du_champ2> : <type_du_champ2>;
...
<nom_du_champ2> : <type_du_champ2>;
end;

Exemple :
type Etudiant =
record
ine : integer;
nom : string[20];
prenom : string[20];
notes : array[1..10] of real;
end;
Types composés : Enregistrements

Accès aux valeurs :


On désigne le champ d’un enregistrement en utilisant le point :
<nom_variable>.<nom_champ>

Exemple :
Program exEnregistrement;
procedure saisie(var e: etudiant);
begin
writeln(’Num INE?’); readln(e.ine);
writeln(’Nom?’); readln(e.nom);
writeln(’Prénom?’); readln(e.prenom);
end;
var e: etudiant
begin
saisie(e);
writeln(’Nom : ’, e.nom);
writeln(’Saisir la premiere note : ’);
readln(e.notes[1]);
end.
Compléments d’algorithmique

(2) Récursivité
Récursivité
Comment calculer la factorielle d’un entier n donné ?
n! = 1 × 2 × . . . × (n − 1) × n

Définition récursive :
0! = 1
n! = (n − 1)! × n (pour n > 0)

Pour définir la fonction factorielle, on utilise la fonction factorielle.ompléments

Exemple (Factorielle de 4) :
4! = 3! × 4
4! = (2! × 3) × 4
4! = ((1! × 2) × 3) × 4
4! = (((0! × 1) × 2) × 3) × 4
4! = (((1 × 1) × 2) × 3) × 4
4! = 24
Récursivité
Un algorithme (ou un sous-programme) est dit récursif quand il contient un (ou plusieurs)
appel(s) à lui-même.
La récursivité peut être indirecte dans le cas où un sous programme sp1 fait appel à un sous
programme sp2 qui fait lui-même appel à sp1.

Dans quel cas utiliser la récursivité :


On peut décomposer le problème en sous-problèmes de même nature et plus court à traiter.
Dans la décomposition en sous-problèmes, on doit toujours arriver à un cas où on peut
résoudre le problème sans faire un appel récursif. Ce cas est appelé cas d’arrêt.
Si un sous-programme fait dans tous les cas un appel récursif, l’exécution ne se
termine jamais.

Exemple (Factorielle) :
ompléments
Le calcul de la factorielle (n!) peut être décomposé en :
Une multiplication
Un problème de même nature et plus court à traiter : (n − 1)!Condition
Au bout d’un certain nombre de décompositions, on arrive toujours à 0!. Or on peut calculer 0!
sans faire de décomposition.éments
Récursivité en Pascal
Aucune syntaxe particulière n’est requise : un appel récursif est réalisé de la même
manière qu’un appel traditionnel à un sous-programme.

Exemple (Factorielle) :
function fact(n: integer): longint;
begin
if n = 0
then fact := 1
else fact := n * fact(n-1);
end;
e (Factorielle)
longint est un type entier codé sur 32 bits alors qu’un integer est codé sur 16 bits.
integer : de -32 768 à 32 767
longint : de -2 147 483 648 à 2 147 483 647
Récursivité en Pascal

Exemple d’exécution :
fact(4) 
4*fact(3) 
3*fact(2) 
2*fact(1) 
1*fact(0) 
1
1*1 
2*1 
3*2 
4*6 
24 
Récursivité : exponentiation
Pour calculer xn, on utilise les propriétés:
x0 = 1
xn = x.x(n−1) (si n > 0)

function puissance(x: real; n: integer): real;


begin
if n = 0
then puissance := 1
else puissance := x * puissance(x, n-1);
end;
Récursivité : Recherche du minimum dans un tableau
Problème : Rechercher le minimum dans un tableau d’entiers.
Comment l’écrire en récursif ?
Décomposer un problème en un problème plus simple :
Le minimum parmi n valeurs est le minimum entre :
- le minimum parmi les n-1 premières valeurs, et
- la nième valeur le minimum

1 2 3 … n-1 n

17 28 11 … 45 18

Si le minimum a du tableau privé d’un élément est inférieur à la valeur b de cet


élément restant (indice n : 18), alors le minimum du tableau est a, sinon c’est b.
Cas d’arrêt : Résolution triviale pour un tableau de taille 1
la valeur minimale parmi 1 valeur est cette unique valeur (pas d’appel récursif).
Récursivité : Recherche du minimum dans un tableau

program minimumtableau;
const TabMax = 10;
type Tab = array[1..TabMax] of integer;
{retourne le minimum parmi les n premieres valeurs de t}
function minTableau(t: Tab; n: integer): integer;
var min1: integer;
begin
if n = 1
then minTableau := t[1]
else
begin
min1 := minTableau(t, n-1);
if min1 < t[n]
then minTableau := min1
else minTableau := t[n];
end;
end;
Fonctions / procédures récursives
Une fonction récursive a souvent la forme suivante :
si condition de cas d’arrêt
alors retourner calcul simple sans appel récursif
sinon appel récursif sur un problème plus simple calcul faisant intervenir
le résultat de l’appel récursif.
retourner résultat du calcul

Un sous-programme récursif n’est pas nécessairement une fonction. Dans le cas


d’une procédure, rien n’est retourné, seuls des calculs sont effectués.
Algorithme récursif / itératif
Équivalence récursif / itératif :
Tout ce qui peut être écrit en récursif peut être écrit en itératif, et
inversément.
Quand utiliser la récursivité ?
Quand la décomposition est simple à trouver et à comprendre.
Quand ne pas utiliser la récursivité ?
Quand il existe une solution itérative simple et intuitive.
Quand la profondeur de la récursivité est trop grande (dépassement
possible de la pile d’exécution)
Exemple : recherche du minimum dans un tableau de 100 000 éléments
En récursif : 100 000 appels.
En itératif : un simple parcours (boucle) des éléments.
La solution itérative est préférable.
Algorithme récursif / itératif
L’appel récursif doit toujours porter sur un problème plus court à traiter, qui se
rapproche d’un cas d’arrêt.
Exemple – Utilisation de la propriété xn = xn+1/x pour calculer une puissance ?

function puissance(x: real; n: integer): real;


begin
if n = 0
then puissance := 1
else puissance := puissance(x, n+1)/x;
end;

Cette fonction ne se termine jamais pour un appel avec n>0.


Récursivité : Somme des éléments d’un tableau

Problème : Écrire (en récursif) un sous-programme qui calcule la somme


des éléments d’un tableau de réels.
Appel récursif : L’opérateur + ne peut être utilisé qu’avec deux réels.
La somme des valeurs d’un tableau de n éléments est égale à la
somme des valeurs des n-1 premiers éléments ajoutée à la valeur du
nième élément.
Cas d’arrêt : Dans un tableau de taille 1, la somme des éléments est
égale à la valeur de l’unique élément.Compléments
Récursivité : Somme des éléments d’un tableau
Somme (Récursif) :
function sommeTab(t: Tab; n: integer): real;
begin
if n = 1
then sommeTab := t[1]
else sommeTab := sommeTab(t, n-1) + t[n];
end;

Somme (Itératif) :
function sommeTab2(t: Tab; n: integer): real;
var i: integer; somme: real;
begin
somme := 0;
for i := 1 to n do
somme := somme + t[i];
sommeTab2 := somme;
end;
Récursivité : Moyenne des éléments d’un tableau
En itératif, pour calculer la moyenne des éléments après le calcul de la somme des
éléments, il suffit de diviser la somme par le nombre d’éléments.
Comment procéder dans un programme récursif ?

Exemple incorrect :
function moyenneTab(t: Tab; n: integer): real;
begin
if n = 1
then moyenneTab := t[1]
else moyenneTab := (moyenneTab(t, n-1) + t[n]) / n;
end;

Cette fonction est incorrecte car la division par n est réalisée à chaque appel
récursif et donc avec une valeur de n différente.
Récursivité : Moyenne des éléments d’un tableau
En itératif, pour calculer la moyenne des éléments après le calcul de la somme des
éléments, il suffit de diviser la somme par le nombre d’éléments.
Comment procéder dans un programme récursif ?

Exemple correct :
function moyenneTab(t: Tab; n: integer): real;
begin
if n = 1
then moyenneTab := t[1]
else moyenneTab := ((n-1) * moyenneTab(t, n-1) + t[n]) / n;
end;

 Dans ce cas de figure, un algorithme itératif est préférable


Récursivité : Recherche dans un tableau trié
Problème : Chercher si une valeur entière donnée apparaît parmi les éléments d’un
tableau dont les éléments sont triés par ordre croissant.

1 2 3 4 5 6 7 8 9 10
5 8 11 17 24 28 46 53 58 62

Algorithme simple : Parcourir tous les éléments du tableau jusqu’à ce que l’on
trouve la valeur cherchée.
Inconvénient : si le tableau est très grand, la recherche peut prendre du temps.
Recherche dans un tableau trié : Dichotomie
Le tableau étant trié, on peut écrire une fonction de recherche plus efficace, qui
considère « plus d’une case » à chaque étape.
t
La dichotomie est un processus de recherche dans lequel l’ensemble de valeurs
sur lequel porte la recherche est coupé en deux à chaque étape, la recherche
continuant sur un seul de ces sous-ensembles.

Exemple : on cherche à déterminer si 28 appartient au tableau précédent.


Au début de la recherche, on recherche 28 entre les indices 1 et 10.
On coupe l’intervalle en deux : (1 + 10) div 2 = 5.
On regarde la valeur de l’élément central (à l’indice 5) pour déteminer si l’on continue la recherche
avant ou après cet élément (à moins que l’élément en question soit l’élément recherche, ou bien que
l’intervalle ne puisse plus être décomposé).

1 2 3 4 5 6 7 8 9 10
5 8 11 17 24 28 46 53 58 62
Recherche dans un tableau trié : Dichotomie
1 2 3 4 5 6 7 8 9 10
5 8 11 17 24 28 46 53 58 62
t

t[5] = 24. Cette valeur est strictement inférieure à la valeur recherchée (28).
Comme le tableau est trié dans l’ordre croissant, aucune valeur comprise entre t[1] et t[4] ne
peut être supérieure à 24, ni par conséquent égale à 28.
On continue donc la recherche dans l’intervalle 6..10.
On calcule l’indice central de cet intervalle : (6 + 10) / 2 = 8.
t[8] = 53. Cette valeur est strictement supérieure à la valeur recherchée.
La recherche continue donc dans l’intervalle 6..7.
On calcule l’indice central de cet intervalle : (6 + 7) / 2 = 6.
t[6] = 28. La valeur cherchée est trouvée.
Si, par exemple, t[6] avait été strictement supérieur à 28, la recherche aurait pu être stoppée
(l’intervalle suivant est ∅) avec comme résultat que la valeur cherchée n’appartient pas à t.
Recherche dans un tableau trié : Dichotomie
Algorithme :
Appel récursif : Lors de la recherche d’une valeur v dans un intervalle
[i1 , i2] d’un tableau t, on calcule le milieu de l’intervalle m = (i1+ i2) / 2 et
on relance la recherche sur :
[i1 , m-1] dans le cas où t[m] > v
[m+1 , i2] dans le cas où t[m] < v
Cas d’arrêt :
Retourne vrai si t[m] = v
Retourne faux si l’intervalle est vide (i1 > i2)mpléments
Recherche dans un tableau trié : Dichotomie

function recherche(t:Tab; v:integer; i1,i2:integer):boolean;


{retourne vrai si v apparait dans t entre les indices i1 et i2}
var milieu: integer;
begin
if i1 > i2
then recherche := false
else
begin
milieu := (i1 + i2) div 2;
if t[milieu] = v
then recherche := true
else if t[milieu] > v
then recherche := recherche(t, v, i1, milieu-1)
else recherche := recherche(t, v, milieu+1, i2);
end;
end;
Recherche dans un tableau trié : Dichotomie

1 2 3 4 5 6 7 8 9 10
5 8 11 17 24 28 46 53 58 62
t

Exemple :
recherche(t, 28, 1, 10)
i1 = 1 ; i2 = 10 ; milieu = 5 ; t[milieu] = 24
recherche(t, 28, 6, 10)
i1 = 6 ; i2 = 10 ; milieu = 8 ; t[milieu] = 53
recherche(t, 28, 6, 7)
i1 = 6 ; i2 = 7 ; milieu = 6 ; t[milieu] = 28
retourne true
retourne true
retourne true
Recherche dans un tableau trié : Dichotomie
1 2 3 4 5 6 7 8 9 10

t 5 8 11 17 24 28 46 53 58 62

Exemple :
recherche(t, 65, 1, 10)
i1 = 1 ; i2 = 10 ; milieu = 5 ; t[milieu] = 24
recherche(t, 65, 6, 10)
i1 = 6 ; i2 = 10 ; milieu = 8 ; t[milieu]=53
recherche(t, 65, 9, 10)
i1 = 9 ; i2 = 10 ; milieu = 9 ; t[milieu]=58
recherche(t, 65, 10, 10)
i1 = 10 ; i2 = 10 ; milieu = 10 ; t[milieu]=62
recherche(t, 65, 11, 10)
retourne false
retourne false
retourne false
retourne false
retourne false
Recherche dans un tableau trié : Dichotomie
Meilleure méthode de recherche dans un tableau trié ?
Dans un tableau de n éléments, la recherche simple s’effectue en n étapes
au plus.
Dans la recherche par dichotomie, chaque étape coupe l’intervalle en deux.
La recherche s’effectue alors en log2(n) étapes au plus.

Taille du Simple Dichotomie


Tableau (n) (log2(n))
10 10 4
1 000 1 000 10
100 000 100 000 17

Sur des petits tableaux, une recherche par dichotomie n’est guère plus rapide (jusqu’à 10 étapes
contre 4 pour n = 10, mais quelques calculs supplémentaires pour déterminer les intervalles).
Sur des grands tableaux, la dichotomie est largement plus rapide (jusqu’à 100 000 étapes contre 17
pour n = 100 000).

Vous aimerez peut-être aussi