Vous êtes sur la page 1sur 209

Descriptif du cours

Acquérir des connaissances de base


solides de l’algorithmique et de la
programmation afin de pouvoir solutionner
des problèmes liés à sa discipline.

Aborder la programmation avec aisance, la


conception d’algorithmes pour résoudre des
problèmes de nature scientifique et la
traduction de ces algorithmes en langage C.
objectifs du cours
Concevoir des algorithmes pour résoudre
des problèmes de nature scientifique;

Posséder une bonne connaissance du


langage C;

Acquérir la méthodologie indispensable


pour pouvoir aborder d’autres langages de
programmation avec aisance.
Introduction, calcul d’ordre asymptotique et
analyse des algorithmes

Points importants

Introduction à l’algorithmique;
Algorithmes et programmes;
Efficacité des algorithmes;
La notation grand O.
Introduction à l’algorithmique
Etudier l’algorithmique c’est apporter des
réponses à vos questions;

Science qui s’occupe de la conception de


méthodes pour la résolution de problèmes, de
l’étude de la complexité de ces méthodes et de la
réalisation concrète;

L’âme et l’esprit de l’informatique. Cette


science est le cœur de l’informatique.
Introduction à l’algorithmique

Historique :
L’étymologie du mot algorithme provient du
nom du mathématicien et astronome perso-
arabe Muhammed Ibn Musa Abu Djafar al-
Chwarismi.
Algorithmes et Programmes
Définition 1:
Un algorithme est suite finie d’opérations
élémentaires constituant un schéma de
calcul ou de résolution d’un problème. C’est
une séquence d’instructions permettant de
réaliser une tâche en un nombre fini
d’étapes.

Exemple : L’algorithme d’Euclide, une recette


de cuisine, etc.
Algorithmes et Programmes
Exercice 1 : Supposez que vous disposez d'un
robinet et de deux contenants non gradués :
- un contenant de 3 litres;
- un contenant de 5 litres.

Décrivez comment il est possible de mesurer un


volume de 4 litres.
Algorithmes et Programmes

Première solution
Remplissez le contenant de 5 litres.
Versez le contenu du contenant de 5 litres dans le contenant de 3
litres.
Videz le contenant de 3 litres.
Versez le contenu du contenant de 5 litres (2 litres) dans le
contenant de 3 litres.
Remplissez le contenant de 5 litres.
Versez le contenu du contenant de 5 litres dans le contenant de 3
litres jusqu'à ce que ce dernier soit
plein (1 litre).
Il reste alors 4 litres dans le contenant de 5 litres.
Algorithmes et Programmes
Deuxième solution
Algorithmes et Programmes

Bravo!
Vous venez d’écrire votre premier algorithme.
Algorithmes et Programmes
Exercice 2 : En informatique, l'on code l’information dans
des bits ou des séquences de bits.
Vous voulez aider un météorologue à coder l’information
dans le but d’un traitement automatique sur la direction du
vent.
De quelle direction souffle le vent ?

NB: Procéder par étape. Par exemple en décuplant la question en deux


autres qui permettent une réponse à deux volets.
1. Le vent souffle-t-il de l'une des directions suivantes : Nord ou Est (oui /
non)
2. Le vent souffle-t-il de l’une des directions suivantes : Est ou Ouest (oui /
non)
Algorithmes et Programmes
Solution
1. Le vent souffle-t-il de l'une des directions suivantes : nord ou
est (oui / non)
2. Le vent souffle-t-il de l’une des directions suivantes : est ou
ouest (oui / non)

En répondant SIMULTANEMENT aux deux questions, l‘on


obtient les résultats suivants:
Question 1 Question 2 Direction
Oui Oui Est
Oui Non Nord
Non Oui Ouest
Non Non Sud
Algorithmes et Programmes
Solution
1. Le vent souffle-t-il de l'une des directions suivantes : nord ou
est (oui / non)
2. Le vent souffle-t-il de l’une des directions suivantes : est ou
ouest (oui / non)

En supposant que 1 représente Oui et 0 non, l‘on obtient :


Question 1 Question 2 Bit 1 Bit 2 Direction Code
Oui Oui 1 1 Est 11
Oui Non 1 0 Nord 10
Non Oui 0 1 Ouest 01
Non Non 0 0 Sud 00
Algorithmes et Programmes

Solution:
1. Le vent souffle-t-il de l'une des directions suivantes : nord ou
est (oui / non)
2. Le vent souffle-t-il de l’une des directions suivantes : est ou
ouest (oui / non)

En supposant que 1 représente Oui et 0 non, l‘on obtient :


Direction Code
Sud 00
Ouest 01
Nord 10
Est 11
Algorithmes et Programmes
Définition 2:
Un programme est la réalisation
(l’implémentation) d’un algorithme au moyen
d’un langage donné (sur une architecture
donnée). Il s’agit de la mise en œuvre du
principe.

Série d’instructions pouvant s’exécuter en


séquence, ou en parallèle qui réalise
(implémente) un algorithme.
Algorithmes et Programmes

Définition 3:
La programmation est l’écriture effective d’un
programme dans un langage
compréhensible par la machine (ordinateur).
Algorithmes et Programmes
Propriétés caractéristiques d’un algorithme

Les entrées: un algorithme prend des valeurs d’entrées à partir d’ensembles


définis;
La sortie : constitue la solution du problème de départ et fournit des données
en sortie;
La finité : La description du procédé est d’une longueur finie;
La terminaison / finitude : l’algorithme doit produire la sortie souhaitée en un
nombre fini d’étapes, quelque soit l’entrée;
Le déterminisme : les mêmes entrées doivent produire les mêmes sorties;
L’effectivité : l’action de chaque instruction doit être effectivement calculable;
La généralité : l’algorithme s’applique à tous les problèmes d’une forme
désirée.
L’efficacité : Chaque étape de l’algorithme doit pouvoir s’exécuter dans un
temps fini.
Efficacité des algorithmes

Qu’entend-on au juste par algorithme efficace?

Il s’agit d’un algorithme dont la complexité


est au plus polynomiale : O(nd) peu importe
le degré. (Dans les faits, le degré du
polynôme devra être petit pour que
l’algorithme soit réellement efficace)
Efficacité des algorithmes

Il y a des problèmes importants pour lesquels


aucun algorithme à complexité polynomiale
n’a été trouvé: les problèmes NP-complets.

Exemples: problème du circuit hamiltonien


(HC), problème du voyageur de commerce
(TS), etc.
Notation grand O

Complexité d’un algorithme est une


estimation du nombre d’opérations de
base effectuées par l’algorithme en
fonction de la taille des données en entrée
de l’algorithme.

Complexité représentée par une fonction.


Notation grand O

Définition:
Soit f, g:R→R ou R→N,
f(x) est O(g(x)) i.e f(x) appartient à O(g(x)) si f
est éventuellement dépassée par un multiple
de g, c’est-à-dire s’il existe des constantes C
et k telles que :

∀𝑥 > 𝑘, 𝑓 𝑥 ≤ 𝐶|𝑔(𝑥)|
Notation grand O

Exemple:

Les nombres k et C sont appelés témoins de la


relation f(x) appartient à O(g(x)).
Notation grand O

Exemple:

Pour prouver que f (x) = 5x2 + 6x + 9


est O(x2), je peux fournir comme témoins
C = 7 et k = 4.1 ou C = 10 et k = 2.1 comme
l’indique la figure ci-dessus.
Notation grand O

Exemple:
Montrer que 7x2 est O(x2) en fournissant les
témoins.
Notation grand O

Théorème 1:
Notation grand O

Réponse :

Donc
Notation grand O

Théorème 1: exemple 2
Notation grand O

Théorème 1: exemple 3
Notation grand O

Théorème 2: Dans la liste de fonctions ci-


dessous, chaque fonction est grand O des
fonctions qui sont situées plus à droite mais
n’est pas grand O des fonctions situées plus
à gauche.
Notation grand O

Théorème 2:
Notation grand O

Théorème 3: (grand O de la somme)


Notation grand O
Théorème 4: (grand O du produit)
Notation grand O
Théorème 5: (grand O d’un polynôme)
Notation grand O
Théorème 5: (grand O d’un polynôme)
Exemple:
Notation grand O

Exercice 1:
Soit f(x)= x5 + 5x , trouvez une fonction g(x)
la plus simple, telle que f(x) appartient à
O(g(x)).
Notation grand O
Solution 1:
La fonction f est une somme. On peut
traduire le théorème de la somme comme la
fonction dont le grand O domine les autres
qui l’emporte. Dans le cas de f, 5x domine x5
i.e x5 est en O(5x). Ainsi, x5 + 5x est en
O(5x).
La fonction cherchée est donc g(x)= 5x
Notation grand O
Exercice 2 :

Soit
Trouvez une fonction g(x) la plus simple
possible telle que f(x) est en O(g(x))
Notation grand O
Solution 2 :
On sait est en O(x2) (théorème
1).
est en O(3x) (théorème 1).
est en O(log(x)) (théorème 1)
D’après le théorème 2, c’est 3x qui domine.
D’après le théorème de la somme,
est en O(3x). La fonction
cherchée est donc g(x)= 3x
Notation grand O

Exercice 3 :
Soit f(n)=(14n+ 3).log(n)+3n2 . Trouvez une
fonction g(n) la plus simple possible telle que
f(n) soit dans g(n).
Notation grand O
Solution 3 :
On sait que 14n+3 est en O(n). Par le théorème
du produit, (14n+3).log(n) est en O(n.log(n)).
On a 3n2 en O(n2 ), (14n+3).log(n) en
O(n.log(n)). Selon le théorème 2, n2 domine
n.log(n). Ainsi, d’après le théorème de la
somme, (14n+ 3).log(n)+3n2 est en O(n2).
La fonction est donc g(n)=n2
Notions élémentaires de
programmation
Que réalise un programme informatique en général?

Réponse :
• Lit des données en entrée;
• Effectue des calculs (sur ces données);
• Ecrit des données en sortie (résultats).
Notions élémentaires de
programmation
Exemple suivant le langage C:
• Lit des données en entrée (clavier) avec la
fonction scanf;

• Effectue des calculs et stocke les résultats


dans une variable;

• Ecrit des données en sortie (écran) avec la


fonction printf.
Notions de bases en programmation

La programmation correspond à l'ensemble


des activités techniques reliées à
l'élaboration d'un programme informatique.

Elle comprend donc les activités de


conception, d'écriture, de test et de
maintenance de programmes.
Notions de bases en programmation

Quelles sont les tâches d’un programmeur?

Réponse :
 Trouver une solution à un problème;
 Exprimer cette solution de façon structurée;
 Traduire cette solution en un langage
compréhensible par la machine;
 Tester le programme.
Notions de bases en programmation

Quels sont les outils nous permettant de


décrire un algorithme?

Réponse :
 L’ordinogramme (organigramme);
 Le pseudo-code.
Notions de bases en programmation

Ordinogramme: diagramme composé de


symboles (boîtes, flèches, etc.) qui permet
d’illustrer la séquence des instructions à réaliser
dans un algorithme.

Pseudo-code: langage qui combine des


éléments de langage de programmation et
de langage naturel et qui sert à décrire un
algorithme.
Notions de bases en programmation

 Les commentaires;
 Le programme principal;

 Les entrées/sorties;

 Les variables et les types;

 Les constantes.
Les commentaires

Qu’est-ce qu’un commentaire ?

Réponse :
Un commentaire est une information
ajoutée au code qui sert à en clarifier le
fonctionnement et qui n'a aucun effet sur
l'exécution.
Les commentaires

Quelle est la syntaxe des commentaires


en C ?

Réponse :
/* Le texte à placer en commentaires. */
ou encore
/* Le texte
à placer
en commentaires. */
Le programme principal

Un programme se compose toujours d'une ou


plusieurs procédures.

La procédure qui régit le fonctionnement d'un


programme se nomme programme principal.

N.B: notions de procédure et fonction seront vues


plus loin.
Le programme principal

syntaxe minimale de la définition d’un


programme en C:

int main(void)
{
Instruction 1, Instruction 2, etc.
}
Le entrées / sorties

Qu’est-ce qu’une entrée ?

Réponse :
Une entrée est une opération par laquelle
un programme acquiert une donnée de
l’utilisateur (lecture sur disque, lecture au
clavier, saisie d'un clic de souris, etc.).
Le entrées / sorties
syntaxe d’une entrée en C:
La fonction scanf permet de lire des données
avec les formats suivants (liste non
exhaustive) :
%d pour le type int (entier);
%u pour le type unsigned int (entier non signé);
%f pour le type float (réel);
%lf pour le type double;
%c pour le type char;
%s pour le type chaîne
Les entrées / sorties

Qu’est ce qu’une sortie ?

Réponse :
Une sortie est une opération par laquelle
un programme fournit une donnée à
l’utilisateur (écriture sur disque, affichage à
l'écran, son dans les haut-parleurs, etc.).
Les entrées / sorties
syntaxe d’une sortie en C:

La fonction printf permet d’afficher les


données à l’écran.
Les entrées / sorties
Exemple :

#include <stdio.h> /* pour pouvoir lire et écrire */


int main (void) /* programme principal */
{
float x; /* déclaration d’une variable x (nombre
réel) */
printf ("Veuillez entrer un nombre reel au clavier \n");
scanf ("%f", &x); /* lecture au clavier de la valeur de x */
/* affichage de x : */
printf("Vous avez tape %f, félicitations !", x);
return 0;
}
Les entrées / sorties
Exercice 1: créer une procédure nommée exercice1 qui
permet d’afficher le message « c’est déjà un succès »

Solution 1 :
#include <stdio.h>
void Exercice1 (void)
{
printf ("c’est déjà un succès ") ;
}
Les entrées / sorties
Exercice 2: Écrivez une procédure qui saisit une valeur
entière au clavier et affiche le carré de cette valeur à l'écran.

Solution 2 :
void carre (void)
{
int valeur_lue ;
printf ("Veuillez entrer un nombre :\n");
scanf ("%d", &valeur_lue);
printf ("la valeur calculée est %d", valeur_lue*valeur_lue)
;
}
Les entrées / sorties
Exercice 3: Écrivez une procédure qui :
- saisit le salaire horaire d'un employé;
- saisit le nombre d'heures travaillées par l'employé;
- calcule le salaire qui doit être versé à l'employé;
- affiche le salaire à l'écran. Par exemple, si l'utilisateur entre 23.50 et 40, la
procédure affiche le message suivant : l’employé doit recevoir 940 FCFA.

Solution 2 :
void salaire (void)
{
float salaire_horaire ;
float nb_heures ;
float salaire_a_verser ;
printf ("Entrez le salaire horaire : \n ");
scanf ("%f", &salaire_horaire);
printf ("Entrez le nombre d'heures : \n ");
scanf ("%f", &nb_heures);
salaire_a_verser = nb_heures * salaire_horaire ;
printf ("Salaire a verser est %f", salaire_a_verser) ;
}
Les variables

Qu’est-ce qu’une variable ?

Réponse:
Une variable est un identificateur, par exemple x
ou prénom, utilisé pour représenter une valeur.

Exemple: le nombre 23 ou la chaîne de caractères


« toto".
La valeur représentée par une variable peut être
modifiée durant l’exécution d’un programme.
Les variables

Qu’est-ce qu’une variable ?

Réponse :
D’un point de vue théorique, une variable
est un symbole que l’on utilise pour
représenter une valeur.
D’un point de vue pratique, une variable
est un espace mémoire où l’on peut ranger
une information.
Les variables
syntaxe d’une variable en C:
Une déclaration de variable a toujours la
forme :
type identificateur;
Ou
type identificateur=valeur;
Exemple:
float x, y=2.0; /* nombres réels. y a pour
valeur initiale 2.0 */
int n; /* nombre entier */
Les variables

Exercice: Que contiennent les variables x et y


suite à l'exécution du code ci-dessous
Int x, y ;
x=3
y=x+2
x=6

Solution:
x=3
y=5
x=6
Les principaux types en C

Qu’est ce qu’un type ?

Réponse :
Le type identifie la nature d'une donnée.
Le type d'une variable détermine sa taille,
les données qu'elle peut contenir et les
opérations permises sur cette variable.
Les principaux types en C
 type entier int: représentation des nombres
entiers;
 types réels float et double: permettent de
représenter des nombres réels avec une certaine
précision;
 type char: est un type caractère codé sur 1 octet.

C’est la plus petite donnée qui puisse être stockée


dans une variable.
 type unsigned: représentent uniquement des
valeurs positives (unsigned int et unsigned char).
Les constantes

Qu’est-ce qu’une constante ?

Réponse :
Une constante est un identificateur utilisé
pour représenter une valeur. Cette valeur
ne peut pas changer durant l’exécution
d’un programme.
Les constantes
On peut donner un nom à une constante par
un #define au début du programme (après
les #include):
Exemple:
#define PI 3.14159265358979323846 /* Constante de type
float */

/* Voici aussi une constante de type chaîne de caractères : */


#define MESSAGE1 "Erreur, vous devez mettre le #define
hors du main !"
Les instructions conditionnelles

Qu’est-ce qu’une instruction conditionnelle ?

Réponse :
Une instruction conditionnelle est une
instruction permettant de choisir les
instructions à réaliser en fonction de
l’évaluation d’une expression booléenne.
Les instructions conditionnelles

Quelle est la syntaxe d’une instruction


conditionnelle en C ?
Réponse :
if (expression de contrôle)
{
/* Instructions à exécuter si l’expression
est vraie. */
}
else
{
/* Instructions à exécuter si l’expression est
fausse. */
}
Les instructions conditionnelles

Syntaxe de plusieurs instructions conditionnelles


imbriquées :

if expression booléenne then


instruction(s)
else if expression booléenne then
Instruction(s)
...
else
Instruction(s)
end if
Où expression booléenne est une expression booléenne.
Les instructions conditionnelles

Les deux bouts de code suivants sont-ils


équivalents ?
if (expression1) if (expression1)
{ {
instruction1; instruction1;
} }
else if (expression2) if (expression2)
{ {
instruction2; instruction2;
} }
else if (expression3) if (expression3)
{ {
instruction3; instruction3;
} }
Les instructions conditionnelles

Voici un contre-exemple démontrant que ce


n’est pas identique :

Vous devez acheter du lait pour faire un


gâteau. La recette indique d’utiliser du
3.25%. Vous vous dites que s’il n’y a pas
de 3.25%, vous prendrez du 2% et qu’au
pire, s’il n’y a ni 3.25%, ni 2%, vous
prendrez du 1%.
Les instructions conditionnelles

On obtient alors les deux bouts de code


suivants :
if (il y a du 3.25%) if (il y a du 3.25%)
{ {
acheter du 3.25%; acheter du 3.25%;
} }
else if (il y a du 2%) if (il y a du 2%)
{ {
acheter du 2%; acheter du 2%;
} }
else if (il y a du 1%) if (il y a du 1%)
{ {
acheter du 1%; acheter du 1%;
} }
Les instructions conditionnelles

Supposons qu’il y avait du 3.25%, du 2% et


du 1%, alors :
if (il y a du 3.25%)
{
acheter du 3.25%;
}
else if (il y a du 2%) Dans ce cas, on
{ achètera uniquement
acheter du 2%;
}
du 3.25%.
else if (il y a du 1%)
{
acheter du 1%;
}
Les instructions conditionnelles

Supposons qu’il y avait du 3.25%, du 2% et


du 1%, alors :
if (il y a du 3.25%)
{
acheter du 3.25%;
}
Dans ce cas, on if (il y a du 2%)
achètera du 3.25%, {
acheter du 2%;
du 2% et du 1% ! }
if (il y a du 1%)
{
acheter du 1%;
}
Les instructions conditionnelles

Exemple: Ecrivez une procédure qui permet


de tester un nombre et affiche à l’écran s’il est
positif, négatif ou nul.
Les instructions conditionnelles
void tester_nombre()
{
int valeur_lue ; /* La valeur lue au clavier*/
printf ("Veuillez entrer un nombre :") ;
scanf ("%d", &valeur_lue);
/* On affiche à l'écran si le nombre est positif, négatif ou nul.*/
if (valeur_lue > 0)
{
printf ("Ce nombre est positif \n") ;
}
else
{
if (valeur_lue < 0)
{
printf ("Ce nombre est négatif \n");
}
else
{ printf ("Ce nombre est nul.\n"); }
}
}
Les instructions conditionnelles

Exercice :
a) Écrivez une procédure qui saisit l'âge d'un
individu au clavier et affiche à l'écran si la
personne est majeure ou non.

b) Écrivez une procédure qui lit deux valeurs


et affiche à l'écran la plus grande des deux
valeurs saisies.
Les instructions conditionnelles

Solution a):
#include <stdio.h>
#define age_majorite 18
void Majeur (void)
{
int age ;
printf ("veuillez entrer votre age:\n");
scanf ("%d", &age);
if (age >= age_majorite)
{
printf ("vous etes une personne majeure \n") ;
}
else
{
printf ("vous etes mineur") ;
}

}
Les instructions conditionnelles

Solution b):
void PlusGrand (void)
{
float premier_nombre, deuxieme_nombre ;
printf ("veuillez entrer un nombre: ");
scanf ("%f", &premier_nombre);
//printf("\n");
printf ("veuillez entrer un nombre:");
scanf ("%f", &deuxieme_nombre);

if (premier_nombre > deuxieme_nombre)


{
printf("le %f est supérieur au %f", premier_nombre, deuxieme_nombre) ;
}
else
{
if (premier_nombre == deuxieme_nombre)
{
printf ("le %f est égal au %f", premier_nombre, deuxieme_nombre);
}
else
{
printf ("le %f est supérieur au %f", deuxieme_nombre, premier_nombre);
}
}
}
Les instructions itératives

À quoi sert une instruction itérative ?

Réponse :
Une instruction itérative permet de répéter
une ou plusieurs instructions tant que
l’évaluation d’une expression booléenne
est vraie.
Les instructions itératives

Quels sont les 3 types de boucles en C ?

Réponse :
do...while
for
while
Les instructions itératives

Quelle différence y a-t-il entre le do…while


et les deux autres types de boucle ?

Réponse :
Le do…while est la seule boucle dont les
instructions sont toujours exécutées au
moins une fois.
Les instructions itératives

Syntaxe de la boucle while:

série d’instructions 1; /* début du programme


*/
tant que (condition)
faire série d’instructions 2; /* instructions
répétées */
fin tant que
série d’instructions 3; /* suite du programme
*/
Les instructions itératives

Exemple: Ecrire une fonction qui calcul nk où


n est un entier et k est un exposant entier saisi
au clavier.
Réponse :
int Puissance(int n,int k)
{
int i=0;/* initialisation obligatoire */
int resultat = 1;/* initialisation à 1 (calcul du produit) */
while (i < k) /* boucle tant que */
{
resultat = resultat*n;
i = i+1; /* progression obligatoire */
}
return resultat;
}
Les instructions itératives

Qu’affiche le code suivant ?


x = 2
While (x >= 0)
Printf("%d", x) 2 est plus grand
x = x - 1 que
1 est 0. grand
plus
L’expression
0 estque 0. à 0.
égal
Wend
L’expression
booléenne
-1 est plusest donc
petit que
vraie.
booléenne 0. est donc
vraie.
L’expression
booléenne est donc
fausse.
Réponse :
2, 1 et 0.
Les instructions itératives
Exercices :
a) Écrivez une procédure qui lit deux valeurs et affiche tous
les nombres se trouvant entre les deux valeurs lues. Par
exemple, si on lit les valeurs 4 et 8, la procédure affiche les
nombres 5, 6 et 7. Vous pouvez supposer que la première
valeur saisie est inférieure à la seconde.

b) Modifiez la procédure précédente de sorte que peu


importe l'ordre des valeurs lues, les valeurs affichées aillent
toujours de la plus petite à la plus grande valeur saisie. En
d'autres termes, si l'on saisit les valeurs 8 et 4, la procédure
affichera 5, 6 et 7. Il en sera de même si l'on saisit les valeurs
4 et 8.
Les instructions itératives
Solution a) :

void exercice_a(void)
{
int minimum, maximum, compteur ;
printf ("veuillez entrer un nombre: \n ");
scanf ("%d", &minimum);
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &maximum);
compteur=minimum + 1 ;
while (compteur < maximum) /* boucle tant que */
{
printf ("%d ", compteur);
compteur=compteur + 1 ;
}
}
Les instructions itératives
Solution b) :
void exercice_b(void)
{
int minimum, maximum, compteur, temp ; /* temp pour permuter les valeurs saisies */
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &minimum);
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &maximum);
if (minimum>maximum)
{
temp=minimum ;
minimum=maximum ;
maximum=temp ;
}
compteur=minimum + 1 ;
while (compteur < maximum) /* boucle tant que */
{
printf ("%d ", compteur);
compteur=compteur + 1 ;
}
}
Les instructions itératives

Quelle boucle préconise-t-on lorsque l’on


connaît le nombre de répétitions à réaliser
?

Réponse :
La boucle For.
Les instructions itératives
Syntaxe d’une boucle For :

for (initialisation ; condition ; progression)


{
série d’instructions;
}
Les instructions itératives
Le programme ci-dessus qui calcule peut être
réécrit:
int PuissanceBis(int n,int k)
{
int i; /* plus d’initialisation ici */
int resultat = 1; /* initialisation à 1 (calcul du produit) */
for (i=0 ; i < k ; i=i+1) /* boucle for */
{
resultat = resultat*n;
}
return resultat;
}
Les instructions itératives
Exercices:
a) Écrivez la boucle qui suit à l'aide d'une boucle For.
compteur = 18 ;
While (compteur >= 4)
printf(compteur)
compteur = compteur - 2
Wend

b) Écrivez une procédure qui lit deux valeurs et affiche tous les nombres
se trouvant entre les deux valeurs lues. Par exemple, si on lit les valeurs
4 et 8, la procédure affiche les nombres 5, 6 et 7. Vous pouvez supposer
que la première valeur est toujours inférieure à la seconde.
Petite contrainte supplémentaire : utilisez une boucle For.
Les instructions itératives
Exercices:

c) Modifiez la procédure précédente de sorte que peu


importe l'ordre des valeurs lues, les valeurs affichées aillent
toujours de la plus petite à la plus grande valeur saisie. En
d'autres termes, si l'on saisit les valeurs 8 et 4, la procédure
affichera 5, 6 et 7. Il en sera de même si l'on saisit les valeurs
4 et 8.
Les instructions itératives
Solutions:
b)
void exercice_bb(void)
{
int minimum, maximum, compteur ;
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &minimum);
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &maximum);

for (compteur=minimum+1 ; compteur < maximum ;


compteur=compteur+1)
{
printf ("%d ",compteur);
}
}
Les instructions itératives
Solutions:
c)
void exercice_cc(void)
{
int minimum, maximum, compteur, temp ; /* temp pour permuter les valeurs saisies */
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &minimum);
printf ("veuillez entrer un nombre:\n");
scanf ("%d", &maximum);
if (minimum>maximum)
{
temp=minimum ;
minimum=maximum ;
maximum=temp ;
}
compteur=minimum + 1 ;
for (compteur=minimum + 1 ; compteur < maximum ; compteur=compteur+1)
{
printf ("%d ", compteur);
}
}
Les opérateurs logiques
Quels sont les trois opérateurs logiques
en C ?

Réponse :
- && (la conjonction)
- || (la disjonction)
- ! (la négation)
Les opérateurs logiques
Évaluez l’expression suivante :
! (True && (False || ! (False && True)))

Réponse :
! (True && (False || (!False)))
! (True && (False || True))
! (True && True)
! True

False
Les opérateurs logiques
Que peut-on affirmer sur l’expression
suivante où x est une variable booléenne
dont la valeur est inconnue :
False && x

Réponse :
Qu’elle est fausse !
En effet, peu importe la valeur de x,
puisque l’opérande de gauche est faux,
l’expression sera toujours fausse.
Les opérateurs logiques
Que peut-on affirmer sur l’expression
suivante où x est une variable booléenne
dont la valeur est inconnue :
True || x

Réponse :
Qu’elle est vraie !
En effet, peu importe la valeur de x,
puisque l’opérande de gauche est vrai,
l’expression sera toujours vraie.
Les sous-programmes
Qu’est ce qu’un sous-programme?

Réponse :
Un sous-programme est un bloc de code qui
porte un nom et se compose d’une séquence
d’instructions réalisant une tâche précise.

Nous distinguons deux types de sous-


programmes :
- les procédures;
- les fonctions.
Les sous-programmes
Quels avantages y a-t-il à utiliser des
sous-programmes dans un programme ?
Réponse :
Permet la réutilisation de code.
Améliore la lisibilité du code.
Facilite le déverminage.
Les sous-programmes
Quelle différence y a-t-il entre procédure
et fonction?

Réponse : Une fonction retourne une valeur


tandis qu'une procédure ne retourne aucune
valeur.

La fonction peut être utilisée dans une


expression tandis qu'une procédure ne le peut
pas.
Les sous-programmes
La définition d'un sous-programme spécifie :

a) son nom;

b) la liste de ses paramètres (s'il y en a);

c) le type de sa valeur de retour (dans le cas


d'une fonction uniquement).
Les sous-programmes
Structure d’une fonction:

FONCTION NomFonction(Type1 nom1, type2 nom2,...):


TypeRetour
où :
• TypeRetour est le type de la valeur retournée par la fonction
;
• NomFonction est le nom de la fonction ;
• Type1, Type2... sont les types respectifs des paramètres ;
• nom1, nom2... sont les identificateurs respectifs des
paramètres.
Les sous-programmes
L’algorithme calculant 2n peut être restructuré à l’aide d’une fonction :

FONCTION DeuxPuiss(entier n): entier


début
entier i, puiss;
puiss ←1;
pour i←0 à n-1 pas 1 faire
puiss ←puiss * 2;
fin faire
retourner puiss;
fin

Algorithme
début
entier n, puiss;
lire(n);
puiss ←DeuxPuiss(n);
ecrire(puiss);
fin
Les sous-programmes
Une procédure aura un prototype de la forme
:

PROCEDURE NomProcedure(Type1 nom1, typ2


nom2,...)
Les sous-programmes
FONCTION DeuxPuiss(entier n): entier /* permet de calculer 2n d’un nombre */
début
entier i, puiss;
puiss ←1;
pour i←0 à n-1 pas 1 faire
puiss ←puiss * 2;
fin faire
retourner puiss;
fin

PROCEDURE Affiche(entier a) /* permet l’affichage d’une donnée de type entier*/


début
ecrire("l’entier vaut : ");
ecrire(a);
fin

Algorithme
début
entier n, puiss;
lire(n);
puiss ←DeuxPuiss(n);
Affiche(puiss);
Fin
Les sous-programmes
Exercices :
aaa) Écrivez une procédure qui lit un nombre et recommence
tant que celui-ci ne se trouve pas entre 1 et 9 inclusivement.
Elle affiche ensuite la valeur lue.

bbb) Écrivez une procédure qui compte combien de nombres


entre 1 et 100 sont des multiples de
17 ou de 23 et affiche ces nombres à l'écran.

ccc) Écrivez une procédure qui saisit un nombre entier n au


clavier et affiche un carré d'étoiles de taille n × n.
Les sous-programmes
Solution aaa) :

void exercice_aaa ()
{
int chiffre_lu ;
printf("Entrez un chiffre entre 1 et 9 :\n ");
scanf("%d", &chiffre_lu);
while ((chiffre_lu<1)||(chiffre_lu>9))
{
printf("Entrez un chiffre entre 1 et 9 :\n");
scanf("%d", &chiffre_lu);
}
printf("la valeur lue est %d : ", chiffre_lu);
}
Les sous-programmes
Solution bbb) :
void exercice_bbb ()
{
int compteur ; /* pour traiter les valeurs de 1 à 100*/
char message[] = "Les nombres suivants sont des multiples de 17 ou de 23 :" ; /* le
message à afficher contenant les nombres*/
/*' On ajoute au message tous les multiples de 17 ou de 23*/
printf("%s ", message);
for (compteur=1; compteur<100; compteur ++)
{
if ((compteur % 17==0) ||(compteur % 23==0))
{

printf("%d ", compteur);


}
}
/* on affiche les nombres trouvés*/
}
Les enregistrements
Exemple: un enregistrement correspond à
une structure en C sous la forme:

enregistrement TypeArticle
début
entier code;
caractere nom[100];
reel prix;
fin
Les enregistrements
enregistrement TypeArticle
début
entier code;
caractere nom[100];
reel prix;
fin

PROCEDURE Affiche(TypeArticle A)
début
ecrire(A.code);
ecrire(A.nom);
ecrire(A.prix);
fin

Algorithme
début
TypeArticle A;
ecrire("Entrez le code, le nom et le prix");
lire(A.code, A.nom, A.prix);
Affiche(A);
Fin
Les enregistrements
A quoi servent les enregistrements?

Réponse : Ils permettent de représenter


une structure hétérogène constituée
d'éléments qui n'ont pas le même type
contrairement aux vecteurs qui
représentent uniquement des éléments de
même type.
Les enregistrements
En C, le mot clé struct permet de déclarer un
enregistrement. La syntaxe est la suivante :

struct nomType{
type1 composante1 ;
type2 composante2 ;
...
typen composanten
}
Les paramètres formels et
paramètres effectifs
Un paramètre permet aux sous-programmes
d'échanger de l'information qui normalement
ne serait pas visible entre eux.

Lorsqu’on passe un paramètre à une fonction,


la fonction ne peut pas modifier la variable. La
variable est automatiquement recopiée, et la
fonction travaille sur une copie de la variable.
On appelle cette technique le passage de
paramètre par valeur.
Les paramètres formels et
paramètres effectifs
Exemple:
#include <stdio.h>
void NeModifiePas(int x)
{
x=2;/* le x local est modifiée, pas le x du main */
}
int main(void)
{
int x=1;
NeModifiePas(x);
printf("%d", x); /* affiche 1 (valeur inchangée) */
return 0;
}
Les paramètres formels et
paramètres effectifs
Exercices:
a) Sachant qu'un mile correspond à 1.60934 km, écrivez une fonction qui
reçoit une distance en miles et retourne celle-ci en kilomètres. Lorsque la
fonction est complétée, créez une petite procédure afin de vérifier que
votre fonction ne contient pas d'erreur.

b) Sachant que l'aire d'un triangle se calcule à l'aide de la formule (Base


× Hauteur) / 2, écrivez une fonction qui calcule l'aire d'un triangle. Prenez
le temps de bien commenter la définition de la fonction.

c) Écrivez une fonction qui trouve la valeur absolue d'un nombre. Prenez
le temps de tester la fonction à l'aide d'une petite procédure.
Les paramètres formels et
paramètres effectifs
Qu’est ce qu’un paramètre formel?

Réponse : Un paramètre formel est une


variable locale qui apparaît dans l'en-tête
de la définition d'un sous-programme et à
laquelle une valeur est assignée lors de
chaque appel de ce sous-programme.
Les paramètres formels et
paramètres effectifs
Qu’est ce qu’un paramètre effectif?

Réponse : Un paramètre effectif est une


expression dont le résultat de l'évaluation
est assigné à un paramètre formel lors de
l'appel d'un sous-programme.
Les paramètres formels et
paramètres effectifs
Paramètre effectif versus paramètre formel :

Paramètres formels

int puissance (int n, int k)

Paramètres effectifs

puissance (3,6)
Les paramètres formels et
paramètres effectifs
Exercices: série 1
a) Écrivez une fonction qui trouve la valeur
maximale parmi deux nombres.

b) Écrivez une fonction qui trouve la valeur


maximale parmi trois nombres.

c) Écrivez une fonction qui trouve la valeur


maximale parmi quatre nombres.
Les paramètres formels et
paramètres effectifs
Exercices: série 2
a) Écrivez une fonction qui permet de calculer n!. Rappelons que n! = 1 x
2 x ... x n.

b) Les combinaisons servent, entre autres, à dénombrer le nombre de


façons qu'il existe de choisir k objets parmi n. On calcule le nombre de
combinaisons à l'aide de la formule suivante :

Écrivez une fonction qui calcule le nombre de façons qu'il existe de


choisir k objets parmi n.

c) Pour calculer la probabilité de gagner le gros lot à la 6/49, il suffit de


diviser le nombre de billets achetés par le nombre de combinaisons
possibles de 6 nombres parmi 49. Écrivez une fonction qui reçoit un
nombre de billets et retourne la probabilité de gain.
Les structures séquentielles
(chapitre 3)
Points importants

Pointeurs;
Tableaux;
Tableaux à deux dimensions.
Les pointeurs
Qu’est ce qu’un pointeur?

Réponse : Les variables dont les valeurs


sont des adresses s’appellent des
pointeurs. On déclare un pointeur sur int
par le type int*, un pointeur sur float par le
type float*, etc.
Les pointeurs
Qu’est ce qu’un pointeur?

Un pointeur est un objet dont le contenu est


l’adresse d’un octet en mémoire.

Pour tout type T, un « pointeur vers un T »


peut être créé (cela inclut les fonctions).
Pointeurs : déclaration
Syntaxe :

<type pointé> * <nom>;

Exemples :

int * ptr1;
double * ptr2;
Pointeurs : assignation
• Pour indiquer qu’un pointeur ne pointe nulle
part, on lui assigne la valeur NULL.

• Pour faire pointer un pointeur vers un objet, on


affecte au pointeur l’adresse de l’objet.

Exemple :
int nb;
int * ptr = &nb;
Pointeurs : indirection
En ajoutant l’opérateur * devant une
adresse ou un pointeur, on obtient l’objet
pointé.

Exemple :
int nb;
int * ptr = &nb;

*ptr = 5;
Pointeurs : type
Soit les déclarations suivantes :
int nb;
int * ptr = &nb;

Alors :

• &ptr correspond à l’adresse de ptr;


• ptr correspond au pointeur ptr;
• *ptr correspond à l’objet pointé par ptr.
Les pointeurs
Exemple utilisant un pointeur p qui prend pour
valeur l’adresse de x:
#include <stdio.h>
int main(void)
{
int x=2; /*déclaration d’une variable x */
int *p; /* déclaration d’un pointeur p */
p = &x; /* p pointe sur x */
/* la valeur de p est l’adresse de x */
scanf("%d", p); /* lecture de la valeur de x au clavier */
printf("%d", x); /* affichage de la nouvelle valeur de x */
return 0;
}
On accède à la donnée pointée par un pointeur (valeur de x dans
l’exemple ci-dessus) par une étoile.
*p = 3; /* l’objet pointé par p prend pour valeur 3 */
Les pointeurs
Remarques:

Ne pas confondre l’usage de l’étoile lors de la


déclaration d’une variable de type pointeur avec
l’usage de l’étoile qui permet d’accéder à l’objet
pointé par le pointeur.

Ne pas confondre la valeur d’un pointeur p, qui est


une adresse, et la valeur de l’objet pointé par p, qui
n’est en général pas une adresse, par exemple un
int dans le cas d’un pointeur de type int*.
Les pointeurs
Remarques:
#include <stdio.h>
int main(void)
{
int x=2;
int *p = &x; /* x et *p deviennent synonymes */
*p = 3;
printf("La nouvelle valeur de x est %d\n", x);
/* doit afficher la valeur 3 */
return 0;
}
#include <stdio.h>
int main(void)
{
int x=2;
int *p = &x; /* x et *p deviennent synonymes */
printf("La valeur de x est %d\n", *p);/* affiche 2 */
x=5;
printf("La nouvelle valeur de x est %d\n", *p);
/* doit afficher la valeur 5 */
return 0;
}
Les pointeurs
Passage de paramètre par valeur:

Lorsqu’on passe un paramètre à une fonction,


la fonction ne peut pas modifier la variable. La
variable est automatiquement recopiée et la
fonction travaille sur une copie de la variable.

La modification de la copie n’entraîne pas une


modification de la variable originale. C’est le
passage de paramètre par valeur.
Les pointeurs
Exemple:

#include <stdio.h>
void NeModifiePas(int x)
{
x = x+1; /* le x local est modifié, pas le x du main */
}
int main(void)
{
int x=1;
NeModifiePas(x);
printf("%d", x);/* affiche 1 : valeur de x inchangée */
return 0;
}
Les pointeurs
Passage de paramètre par adresse:

L’idée du passage par adresse est que, pour


modifier une variable par un appel de fonction, il faut
passer en paramètre non pas la variable, mais un
pointeur qui pointe sur la variable. Ainsi, le
paramètre est l’adresse de x.

Lorsqu’on modifie la mémoire à cette adresse, la


donnée x est modifiée, car on travaille bien sur
l’emplacement mémoire de x.
Les pointeurs
Exemple:
#include <stdio.h>
/* la fonction suivante prend en paramètre un pointeur */
void Modifie(int *p)
{
*p = *p+1; /* p pointe sur x, la copie de p aussi */
/* le x du main est modifié */
}
int main(void)
{
int x=1; /* la varible x n’est pas un pointeur */
int *p;
p = &x; /* pointeur qui pointe sur x */
Modifie(p);
printf("%d", x); /* affiche 2 */
return 0;
}
Les pointeurs
Remarque:

Lors de l’appel de la fonction Modifie, le pointeur p


est recopié, et la fonction Modifie travaille sur une
copie du pointeur p. Cependant, les pointeurs p et
sa copie contiennent la même valeur, qui est
l’adresse de x. Lorsqu’on modifie l’objet qui se
trouve à cette adresse, on modifie x.
Les pointeurs
Remarque: L’utilisation explicite d’un pointeur dans le main
est superflue, on peut passer directement l’adresse de x à la
fonction, sans avoir besoin de définir une variable de type
pointeur dans le main.
#include <stdio.h>
void Modifie(int *p) /* paramètre de type pointeur */
{
*p = *p+1;/* ce pointeur p a pour valeur &x (x du main) */
}
int main(void)
{
int x=1;
Modifie(&x);/* on passe directement l’adresse de x */
printf("%d", x); /* affiche 2 */
return 0;
}
C’est sous cette dernière forme que l’on utilise en général le passage par adresse.
Les pointeurs
Exemple :
Écrire une fonction qui initialise deux entiers et un réel à
0. Écrire le programme principal qui appelle cette
fonction.

Réponse:
void remplir(int *a,int *b,float *x)
{
*a = 0;
*b = 0;
*x = 0.0;
}
int main()
{
int u, v;
float t;
remplir(&u, &v, &t);
return 0;
}
Les tableaux
Qu’est ce qu’un tableau?
Réponse:
Un tableau est une série d'éléments de même type
regroupés sous un seul identificateur. Chaque élément
possède un indice permettant d'accéder à son contenu
en lecture et en écriture..

En termes plus simple, un tableau est une suite de


variables de même type accessibles à partir d'un
identificateur (le nom du tableau) et d'un indice (le
numéro de l'élément).
Les tableaux
Illustration d’un tableau:
Le tableau ci-dessous contient 5 éléments de type
entier. L'indice de chacun des éléments apparaît au-
dessus de ce dernier.
Les tableaux
Qu’est-ce qui différencie un tableau d’un
enregistrement ?
Réponse :
• Les éléments d’un tableau doivent tous
être de même type.
• Les opérations permises sur un
enregistrement ne sont pas les mêmes
que sur un tableau.
Les tableaux
Déclaration d’un tableau:

typeElements nomTableau[NOMBRE_ELEMENTS];
où typeElements est le type des éléments du
tableau, nomTableau est le nom du
tableau, et NOMBRE_ELEMENTS est une
constante indiquant le nombre d’éléments du
tableau.
Les tableaux
Exemple de déclaration:
int tab[10];
Tableau nommé tab contenant 10 entiers.

const double tab[100];


Tableau nommé tab contenant 100 réels constants.

char * tab_ptr[30];
Tableau nommée tab_ptr de 30 pointeurs de caractère.

int tab[10] = {0};


Tableau nommé tab contenant 10 entiers initialisés à 0.

long tab[7] = {1, 1, 2, 3, 5, 8, 13};


Tableau nommé tab contenant 7 entiers longs initialisés avec les
valeurs 1, 1, 2, 3, 5, 8 et 13.
Les tableaux
Déclaration d’un tableau:
Un tableau dont la taille est spécifiée dans la
déclaration est un tableau statique (ou à taille
fixe). La taille d'un tel tableau ne peut pas être
modifiée durant le traitement.

Un tableau dont la taille n'est pas spécifiée


dans la déclaration est un tableau dynamique.
La taille d'un tel tableau peut être modifiée
durant le traitement.
Les tableaux

Exercice:
Écrivez une procédure qui saisit trois valeurs
entières au clavier et les affiche dans l'ordre
inverse de la lecture. Cependant, plutôt que
d'utiliser trois variables, utilisez plutôt un
tableau de trois entiers.
Les tableaux
Solution:
#include <stdio.h>
void lire_trois_valeurs_avec_tableau()
{
int tab[3] ;
printf("Veuillez entrer un nombre :") ;
scanf("%d", &tab[0]) ;
printf("Veuillez entrer un nombre :") ;
scanf("%d", &tab[1]) ;
printf("Veuillez entrer un nombre :") ;
scanf("%d", &tab[2]) ;
printf(tab[2]) ;
printf(tab[1]) ;
printf(tab[0]);
}
Les tableaux
Accès aux éléments d’un tableau à une dimension:

Pour accéder à un élément du tableau, on spécifie le nom du


tableau et l'indice (la position) de l'élément dans le tableau.

Les indices des éléments d’un tableau commencent à 0 et non


pas à 1. Par conséquent, les éléments d’un tableau à N
éléments ont leurs indices allant de 0 à N−1. L’accès à un
élément d’indice supérieur ou égal à N provoquera
systématiquement un résultat faux, et généralement une erreur
mémoire (erreur de segmentation). On parle de dépassement
de tableaux.
Les tableaux
Nombre d’éléments fixé:
#include <stdio.h>
#define NB_ELEM 15 /* Nombre d’éléments du tableau */
/* ******** Fonction Affichage ********** */
/* Affiche un tableau */
void Affichage(float tableau[NB_ELEM])
{
int i;
for (i=0 ; i<NB_ELEM ; i++)
{
printf("l’élément numéro %d vaut %f\n", i, tableau[i]);
}
}
/* ********* Fonction main ********** */
/* Lit un tableau et le fait afficher */
int main()
{
int i; /* indice */
float tableau[NB_ELEM]; /* déclaration du tableau */
for (i=0 ; i<NB_ELEM ; i++)
{
printf("Entrez l’élément %d : ", i);
scanf("%f", &tableau[i]); /* lecture d’un élément */
}
Affichage(tableau); /* Affichage du tableau */
return 0;
}
Les tableaux
Nombre d’éléments variable borné:
#include <stdio.h>
#define NB_ELEM_MAXI 100 /* Nombre maximum d’éléments */
/* du tableau */
/* ******** Fonction Affichage ********** */
/* Affiche un tableau de taille n */
void Affichage(float tableau[],int n)
{
int i;
for (i=0 ; i<n ; i++)
{
printf("l’élément numéro %d vaut %f \n", i, tableau[i]);
}
}
/* ********* Fonction main ********** */
/* Lit un tableau et le fait afficher */
int main()
{
int n, i; /* nombre d’éléments et indice */
float tableau[NB_ELEM_MAXI]; /* déclaration du tableau */
printf("Entrez le nombre d’éléments à taper : ");
/* lecture du nombre d’éléments au clavier (variable) */
scanf("%d", &n);
if (n > NB_ELEM_MAXI)
{ /* test d’erreur */
puts("Erreur, nombre trop grand !");
return 1;
}
for (i=0 ; i<n ; i++)
{ /* n éléments */
printf("Entrez l’élément %d : ", i);
scanf("%f", &tableau[i]); /* lecture d’un élément */
}
Affichage(tableau, n); /* Affichage du tableau */
return 0;
}
Les tableaux
Nombre d’éléments variable borné:

Le nombre maximum NB_ELEM_MAXI, qui


correspond au nombre d’emplacements
mémoire disponibles, est parfois appelé taille
physique du tableau.

Le nombre n d’éléments du tableau


effectivement utilisés est la taille logique du
tableau.
Les tableaux
Initialisation lors de la déclaration:

#include <stdio.h>
int main(void)
{
int tab[5] = {3, 56, 21, 34, 6};/* avec point-virgule */
for (i=0 ; i<5 ; i++) /* affichage des éléments */
printf("tab[%d] = %d\n", i, tab[i]);
return 0;
}
Les tableaux à deux dimensions
Qu’est ce qu’un tableau à deux dimensions?
Réponse :

Un tableau de dimension 2, aussi appelé tableau à


double entrée, ou matrice, est un tableau de
tableaux. On peut déclarer un tableau de dimension
2 statiquement :
#define NB_LIGNES 100
#define NB_COLONNES 50
...
int tableau[NB_LIGNES][NB_COLONNES];
Les tableaux à deux dimensions
Accès aux différents éléments du tableau:

On accède aux différents éléments par des crochets


: l’élément tableau[i] est un tableau, et son élément j
est donc noté tableau[i][j].

Conventionnellement, on conçoit un tel tableau


comme ayant des lignes et des colonnes, l’indice i
représentant le numéro d’une ligne, et l’indice j
représentant le numéro d’une colonne. L’élément
tableau[i][j] se trouve à l’intersection de la ligne i et
de la colonne j.
Les tableaux à deux dimensions
Le programme suivant crée une matrice dont chaque élément (i,j) vaut i+j.
#define NB_LIGNES_MAX 100
#define NB_COLONNES_MAX 50
void Creer(int tableau[NB_LIGNES_MAX][NB_COLONNES_MAX],
int nbl, int nbc)
{
int i, j;
for (i=0 ; i<nbl ; i++) /* pour chaque ligne du tableau */
for (j=0 ; j<nbc ; j++) /* pour chaque colonne */
tableau[i][j] = i+j;
}

void Afficher(int tableau[NB_LIGNES_MAX][NB_COLONNES_MAX],


int nbl, int nbc)
{
int i, j;
for (i=0 ; i<nbl ; i++) /* pour chaque ligne */
{
for (j=0 ; j<nbc ; j++) /* pour chaque colonne */
printf("%d ", tableau[i][j]);
printf("\n"); /* on va à la ligne */
}
}

int main(void)
{
int tableau[NB_LIGNES_MAX][NB_COLONNES_MAX];
int nbl, nbc;
puts("Entrez le nombre de lignes et de colonnes");
scanf("%d %d", &nbl, &nbc);
if (nbl > NB_LIGNES_MAX || nbc > NB_COLONNES_MAX)
{
puts("Erreur, nombre dépassant la taille du tableau");
exit(1);
}
Creer(tableau, nbl, nbc);
Afficher(tableau, nbl, nbc);
return 0; }
Les tableaux à deux dimensions
Le résultat de l’exécution de ce programme
pour 4 lignes et 6 colonnes est :
012345
123456
234567
345678
Les structure de données

Points importants

Listes chainées;
Piles;
Files.
Les listes chainées
Qu’est ce qu’une liste chainée?
Réponse :

Une liste chaînée est un ensemble de cellules liées


entre elles par des pointeurs. Chaque cellule est
une structure contenant les champs suivants :
une ou plusieurs données comme dans n’importe
quelle structure ;
un pointeur suivant sur la cellule suivante.
Qu’est-ce qu’une liste chainée ?
Une liste chaînée est une structure de données à
l’intérieure de laquelle les objets sont ordonnés
de façon linéaire. À la différence d’un tableau, où
l’ordre linéaire est déterminé par les indices du
tableau, l’ordre dans une liste chaînée est
déterminé par un pointeur dans chacun des
objets.

- Introduction to algorithms / Thomas H. Cormen, Charles E.


Leiserson, Ronald L. Rivest, p. 204
Représentation simpliste d’une liste
simplement chaînée

3
Maillon (ou
Tête de nœud)
liste Pointeur vers
un nœud

Données
Données
(toutes
(toutes de
de
même
même type)
type)
Déclaration d’une liste chaînée
Pour créer une liste chaînée, il faut déclarer une nouvelle structure de
données : la structure qui représentera une cellule.

/* exemple : les données dans les cellules sont des float */


Typedef float TypeDonnee;
/* définition du type cellule : */
typedef struct Cell
{
TypeDonnee donnee; /* définition des données */
/* on peut mettre ce qu’on veut comme donnée */
struct Cell *suivant;/* pointeur sur la structure suivante */
/* (de même type que celle qu’on est en train de définir) */
}TypeCellule;
On déclare ensuite le pointeur qui donne l’adresse de la première cellule
(NULL si la liste est vide) :
TypeCellule *L;/* déclaration d’une liste */
Les listes chainées
Nous avons déclaré une liste chaînée de
float.
Nous avons défini un type TypeDonnee par
un typedef. Ainsi, nous pourrons avoir
maintenant des données de type
TypeDonnee.

On parle d’un code générique pour parler d’un


code qui peut fonctionner pour différents
types de données
Les listes chainées
Exemple:

void AfficheDonnee(TypeDonnee donnee)


{
printf("%f ", donnee);/* ici donnée est de type float */
}
TypeDonnee SaisieDonnee(void)
{
TypeDonnee donnee;
scanf("%f", &donnee);/* ici donnée est de type float */
return donnee;
}
Les services à offrir dans une liste
chaînée
Une liste chaînée devrait minimalement offrir les
fonctionnalités suivantes :

 Création
 Consultation (au début, à la fin et ailleurs)
 Ajout (au début, à la fin et ailleurs)
 Retrait (au début, à la fin et ailleurs)
 Consultation de la longueur
Création de la liste
On fait pointer la tête vers NULL.
On initialise le nombre de nœuds à 0.

?
?
0
Consultation du ième élément
SI i ≥ 0 et i < nombre de nœuds de la liste ALORS
On fait pointer un pointeur sur le premier nœud.
TANT QUE i > 0 BOUCLE
Faire pointer le pointeur vers le prochain nœud.
ii-1
FIN TANT QUE
FINSI

i 26 34 12
10
2 3
Ajout au début de la liste
On tente de créer un nouveau nœud.
SI la création fut un succès ALORS
On fait pointer le nouveau nœud vers le premier
élément de la liste (NULL si celle-ci est vide).
On initialise le nœud.
On fait pointer la tête de liste sur le nouveau nœud.
On incrémente le nombre de nœuds.
FINSI

34 12
3
2
26
Ajout à la fin de la liste
SI la liste est vide ALORS
On ajoute au début de la liste
SINON
On tente de créer un nouveau nœud.
SI la création fut un succès ALORS
On positionne un pointeur sur le dernier élément de la liste (voir consulter
ième élément).
On initialise les champs du nouveau nœud.
On fait pointer le dernier nœud sur le nouveau nœud.
On incrémente le nombre de nœuds.
FINSI
FINSI

34 12 26
3
2
Ajout à la ième position
SI i = 0 OU la liste est vide ALORS
On ajoute au début de la liste
SINON SI i < nombre de nœuds de la liste ALORS
On tente de créer un nouveau nœud.
SI la création fut un succès ALORS
On positionne un pointeur sur le i-1ème nœud.
On initialise les données du nouveau nœud.
On fait pointer le nouveau nœud sur le ième nœud (NULL si on ajoute à la fin).
On fait pointer le i-1ème nœud sur le nouveau.
On incrémente le nombre de nœuds.
FINSI
FINSI

34 12 53
i
2 3
4
26
Retrait au début de la liste
SI la liste n’est pas vide ALORS
On fait pointer un pointeur sur le premier élément de la liste.
On fait pointer la tête de liste sur le deuxième nœud (NULL s’il
n’y avait qu’un seul nœud).
On détruit le nœud pointé par le pointeur.
On décrémente le nombre de nœuds.
FINSI

34 12 26
2
3
Retrait à la fin de la liste
SI la liste n’est pas vide ALORS
SI la liste ne contient qu’un seul élément ALORS
Retirer au début de la liste.
SINON
On fait pointer un pointeur sur l’élément à l’indice nombre de nœuds – 2.
On détruit le dernier nœud.
On fait pointer l’avant dernier vers NULL.
On décrémente le nombre de nœuds.
FINSI
FINSI

34 12 26
2
3
Retrait à la ième position
SI i ≥ 0 et i < nombre de nœuds de la liste ALORS
SI la liste ne contient qu’un seul élément ALORS
Retirer au début de la liste.
SINON
On fait pointer un pointeur sur l’élément à l’indice i – 1.
On fait pointer un pointeur sur l’élément à l’indice i.
On fait pointer le i-1ème nœud sur le i+1ème nœud (NULL si on détruit le dernier).
On détruit le ième nœud.
On décrémente le nombre de nœuds.
FINSI
FINSI

34 12 26

1 2
3
Les piles
Qu’est ce qu’une pile?
Réponse :
Une pile est une structure de données dans laquelle
on peut ajouter et supprimer des éléments suivant la
règle du dernier arrivé premier sorti ou encore LIFO
(Last In First Out).

Une pile peut être implémentée par un tableau ou


par une liste chaînée.
Les piles
Il existe des opérations de base appelées primitives de
gestion des piles qui permettent de les manipuler
facilement (utilisation d’un tableau):

Initialiser: cette fonction crée une pile vide;


EstVide: renvoie 1 si la pile est vide, 0 sinon;
EstPleine: renvoie 1 si la pile est pleine, 0 sinon;
AccederSommet: cette fonction permet l’accès à l’information contenue
dans le sommet de la pile;
Empiler: cette fonction permet d’ajouter un élément au sommet de la
pile. La fonction renvoie un code d’erreur si besoin en cas de manque
de mémoire;
Depiler: cette fonction supprime le sommet de la pile. L’élément
supprimé est retourné par la fonction Depiler pour pouvoir être utilisé.
Vider: cette fonction vide la pile;
Detruire: cette fonction permet de détruire la pile.
Les piles
Structure de données pour l’implémentation d’une pile sous
forme de tableau (les données sont de type float pour ce
cas de figure):

Typedef float TypeDonnee;


typedef struct
{
int nb_elem; /* nombre d’éléments dans la pile */
int nb_elem_max; /* capacité de la pile */
TypeDonnee *tab; /* tableau contenant les éléments */
}Pile
Les piles
Fonction permettant de créer une pile:

Pile Initialiser(int nb_max)


{
Pile pilevide;
pilevide.nb_elem = 0; /* la pile est vide */
pilevide.nb_elem_max = nb_max; /* capacité nb_max */
/* allocation des éléments : */
pilevide.tab=(TypeDonnee*)malloc(nb_max*sizeof(TypeDonnee));
return pilevide;
}
Les piles
Fonction permettant de savoir si la pile est vide:

int EstVide(Pile P)
{
/* retourne 1 si le nombre d’éléments vaut 0 */
return (P.nb_elem == 0) ? 1 : 0;
}

La fonction renvoie 1 si le nombre d’éléments est égal à 0 et


renvoie 0 dans le cas contraire.
Les piles
Fonction permettant de savoir si la pile est pleine:

int EstPleine(Pile P)
{
/* retourne 1 si le nombre d’éléments est supérieur */
/* au nombre d’éléments maximum et 0 sinon */
return (P.nb_elem >= P.nb_elem_max) ? 1 : 0;
}
Les piles
Fonction permettant d’acceder au sommet de la pile:

int AccederSommet(Pile P, TypeDonnee *pelem)


{
if (EstVide(P))
return 1; /* on retourne un code d’erreur */
*pelem = P.tab[P.nb_elem-1];/* on renvoie l’élément */
return 0;
}
Les piles
Fonction permettant de modifier le nombre d’élément de
la pile (ajouter):

int Empiler(Pile* pP, TypeDonnee elem)


{
if (EstPleine(*pP))
return 1; /* on ne peut pas rajouter d’élément */
pP->tab[pP->nb_elem] = elem; /* ajout d’un élément */
pP->nb_elem++; /* incrémentation du nombre d’éléments */
return 0;
}
Les piles
Fonction permettant de supprimer le sommet de la pile:

char Depiler(Pile *pP, TypeDonnee *pelem)


{
if (EstVide(*pP))
return 1; /* on ne peut pas supprimer d’élément */
*pelem = pP->tab[pP->nb_elem-1]; /* on renvoie le sommet
*/
pP->nb_elem--; /* décrémentation du nombre d’éléments */
return 0;
}
Les piles
Fonction permettant de vider la pile:

void Vider(Pile *pP)


{
pP->nb_elem = 0;/* réinitialisation du nombre d’éléments */
}
Les piles
Fonction permettant de détruire la pile:

void Detruire(Pile *pP)


{
if (pP->nb_elem_max != 0)
free(pP->tab) ; /* libération de mémoire */
pP->nb_elem = 0 ;
pP->nb_elem_max = 0 ;/* pile de taille 0 */
}
Les files
Qu’est ce qu’une file?
Réponse :
Une file est une structures de données dans
laquelle on peut ajouter et supprimer des éléments
suivant la règle du premier arrivé, premier sorti, ou
encore FIFO (First In First Out).

Une file peut être implémentée par une liste


chaînée, ou par un tableau avec une gestion
circulaire.
Les files
Il existe des opérations de base appelées primitives de
gestion des files qui permettent de les manipuler
facilement :
Initialiser: cette fonction crée une file vide;
EstVide: renvoie 1 si la file est vide, 0 sinon;
EstPleine: renvoie 1 si la file est pleine, 0 sinon;
AccederTete: cette fonction permet l’accès à l’information contenue dans la tête
de file;
Enfiler: cette fonction permet d’ajouter un élément en queue de file. La fonction
renvoie un code d’erreur si besoin en cas de manque de mémoire;
Defiler: cette fonction supprime la tête de file. L’élément supprimé est retourné
par la fonction Defiler pour pouvoir être utilisé;
Vider: cette fonction vide la file;
Detruire: cette fonction permet de détruire la file.
Les files

Comme dans le cas des piles, lorsqu’on


utilise une file, on ne se préoccupe pas de
la manière dont elle a été implémentée,
mais on utilise uniquement les primitives
qui sont toujours les mêmes. Une file peut
être implémentée par un tableau ou par
une liste chaînée.
Les algorithmes de tri

Points importants

Notion de Complexité;
Tri par sélection;
Tri par insertion;
Tri par bulle.
La notion de complexité

La complexité temporelle est le décompte du nombre


d'opérations élémentaires effectuées par un algorithme
donné.

Une opération élémentaire est une opération


fondamentale d'un algorithme si le temps d'exécution est
directement lié (par une formule mathématique ou
empirique) au nombre de ces opérations élémentaires. Il
peut y avoir plusieurs opérations élémentaires dans un
même algorithme
La notion de complexité

Soient i1 , i2 , ... , ik des instructions algorithmiques


(affectation, itération, condition,...)
Soit une opération élémentaire dénotée OpElem,
supposons qu'elle apparaisse n1 fois dans l'instruction i1, n2
fois dans l'instruction i2, ... nk fois dans l'instruction ik. Nous
noterons Nb(i1) le nombre n1, Nb(i2) le nombre n2 etc.
Soit S la séquence d'exécution des instructions i1 ; i2 ; ... ; ik,
soit nk =Nb (ik) le nombre d'opérations élémentaires de
l'instruction ik.
Le nombre d'opérations élémentaires OpElem de S, Nb(S)
est égal par définition à la somme des nombres: n1 + n2 + ...
+ nk :
La notion de complexité
Complexité temporelle d’une séquence d’instruction:
La notion de complexité
Complexité temporelle d’une instruction conditionnelle:
La notion de complexité
Complexité temporelle d’une instruction itérative
bornée:

La complexité est égale au produit du nombre d'itérations


(nbr_d’itérations) par la somme de la complexité de la
séquence d'instructions (S) du corps et de celle de
l'évaluation de la condition d'arrêt Expr(i).
La notion de complexité
Complexité temporelle d’une instruction itérative bornée:

Pour le cas de la boucle for ci-dessus, nous avons:


Nb( Iter ) = ( ∑Nb(ip) + 1 ).|b-a+1|
Le tri par sélection
Fonctionnement du tri par sélection:

Première passe
On cherche l'élément contenant la plus petite valeur du
tableau à partir du premier élément.
On échange la valeur de cet élément avec celle du premier
élément du tableau.
Deuxième passe
On cherche l'élément contenant la plus petite valeur du
tableau à partir du deuxième élément.
On échange la valeur de cet élément avec celle du
deuxième élément du tableau.
... et ainsi de suite pour chaque élément du tableau jusqu'à
l'avant-dernier.
Le tri par sélection
Fonctionnement du tri par sélection:

Pour i = 1 À n - 1
indice_du_minimum = indice du plus petit élément se
trouvant entre T(i) et T(n) inclusivement
permuter T(i) et T(indice_du_minimum)
Fin Boucle
Le tri par sélection
Fonctionnement du tri par sélection:
Nous pouvons également commencer par chercher l’élément contenant
la plus grande valeur (le maximum) par exemple:
Le tri par sélection
Algorithme du tri par sélection:
PROCEDURE TriSelection(entier *T,entier n) /* on fait un tri ci sur les entiers*/
début
entier k, i, imax, temp;
pour k ←n-1 à 1 pas -1 faire
/* recherche de l’indice du maximum : */
imax←0;
pour i←1 à k pas 1 faire
si T[imax] < T[i] faire
imax←i;
fin faire
/* échange : */
temp←T[k];
T[k]←T[imax];
T[imax]←temp;
fin faire
fin
Le tri par sélection
Exercice:

Estimer le nombre d’opération à effectuer (la complexité)


lorsqu’on applique un algorithme de tri par sélection sur un
tableau d’entiers de taille n.
Le tri par insertion
Fonctionnement du tri par insertion:

Première passe
On recule la valeur du deuxième élément dans le tableau
jusqu'à ce que les valeurs des deux premiers éléments
soient ordonnées.
Deuxième passe
On recule la valeur du troisième élément dans le tableau
jusqu'à ce que les valeurs des trois premiers éléments
soient ordonnées.
... et ainsi de suite pour tous les autres éléments du tableau.
Le tri par insertion
Fonctionnement du tri par insertion:

Pour i = 2 À n
insérer l'élément T(i) au bon endroit parmi les i-1 éléments
déjà triés
Fin Pour
Le tri par insertion
Algorithme du tri par insertion:
PROCEDURE TriInsertion(entier *T, entier n)
début
entier k, i, v;
pour k ←1 à n-1 pas 1 faire
v←T[k];
i←k-1;
/* On décale les éléments pour l’insertion */
tant que i≥0 et v < T[i] faire
T[i+1]←T[i];
i←i-1;
fin faire
/* On fait l’insertion proprement dite */
T[i+1]←v;
fin faire
fin
Le tri par insertion
exercice:

Estimer le nombre d’opération à effectuer (la


complexité) lorsqu’on applique un algorithme de tri
par insertion sur un tableau d’entiers de taille n.
Le tri par bulle
Fonctionnement du tri par bulle:

Dans le tri par bulle, on échange deux éléments


successifs T[i-1] et T[i] s’ils ne sont pas dans
l’ordre.
Il faut faire cela un grand nombre de fois pour
obtenir un tableau trié. Plus précisément, on fait
remonter le maximum à sa place définitive par
échanges successifs avec ses voisins.
Le tri par bulle
Fonctionnement du tri par bulle:
Le tri par bulle
Algorithme du tri par bulle:
PROCEDURE TriBulle(entier *T, entier n)
début
entier i, k, temp;
/* pour chaque passe */
pour k ←n-1 à 1 pas -1 faire
/* on fait remonter le plus grand */
pour i←1 à k pas 1 faire
si T[i] < T[i-1] faire
/* échange de T[i-1] et T[i] */
temp←T[i];
T[i]←T[i-1];
T[i-1]←temp;
fin faire
fin faire
fin faire
fin
Le tri par bulle

Exercice:
Estimer le nombre d’opération à effectuer (la
complexité) lorsqu’on applique un algorithme de tri
par bulle sur un tableau d’entiers de taille n.
C’est tout pour le cours d’Info II

Maintenant, place à la partie


pratique!

Vous aimerez peut-être aussi