Vous êtes sur la page 1sur 82

Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ

Par K. Constant KOUAKOU deuxième tirage

PARTIE I :
LE LANGAGE C

INTRODUCTION

Le langage C est un langage de programmation structuré qui a été créé par


KERNIGHAN & RITCHIE dans l'objectif de développer un Système
d'Exploitation : UNIX.
90% du code d’UNIX natif a été conçu en C , et 10% en Assembleur et
langage machine. Ce qui explique la très grande portabilité d'un programme écrit
en C sur les Systèmes UNIX.
Un Système d'Exploitation est un Logiciel de base (i.e. un logiciel servant
à faire fonctionner les Logiciels d’un système informatique) c'est à dire un
ensemble d'utilitaires de type Logiciel qui permettent de gérer des ressources de
type Matériel ou Logiciel d'un ordinateur ou d'un assemblage informatique.
En vu de répondre à des contraintes d’outil de conception de Système
d’Exploitation, le Langage C a été conçu de manière à pouvoir effectuer des accès
de bas niveau vis à vis du matériel et des logiciels, il est donc très performant tout
en étant un Langage structuré. Les programmeurs en C ont conçus des
programmes d’intérêt général qui ont été intégrés par la suite dans certains
logiciels de développement en C ; ainsi par exemple le Langage C (pur) ne
possède pas de fonction d'affichage mais la fonction printf( ) qui est très utile
pour l'affichage a été intégrée dans la plupart des Logiciels de programmation en
C à travers une bibliothèque : stdio.h.
Les bibliothèques C existent presque en quantités indénombrables.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 1
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

LangC I STRUCTURE GENERALE D'UN PROGRAMME EN C

Pour écrire un programme en C, un débutant peut retenir un plan standard qui


n’est pas obligatoire. Son programme pourra suivre la progression suivante :
i • Une partie d’entête de déclaration des bibliothèques
ii • Une partie de définition ou déclaration de constantes ou de macros
iii • Une partie déclarative des types de données spécifiques au programme
iv • Une partie déclarative des variables globales
v • Une partie de déclaration/définition des fonctions (sous programme)
vi • Une partie codant le corps du programme principal
vii • Les fonctions déclarées en « partie v » peuvent être définies ici
Remarque :
1 Il faut faire une distinction entre une déclaration de fonction et une
définition de fonction.
- La définition d'une fonction donne l'algorithme conceptuel de la fonction
ainsi que le mode d’appel de cette fonction.
- La déclaration ne donne que le mode d'appel de la fonction .
2 Le plan de progression ci–dessus n’est conseillé que dans une première
phase d’apprentissage du Langage C ; d’un aspect avancé , la modularité le
mettra certainement en cause .

LangC – 2 L'ENTETE DES BIBLIOTHEQUES

Dans cette partie nous commentons la directive include


Exemple : include <stdio.h>.
Il y a 2 formes pour cette directive
* include < c:\ tcp\ include\ stdio.h >

Nom de la bibliothèque avec le chemin complet


* include "stdio.h"

Nom de la bibliothèque sans le chemin

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 2
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Dans la 2ème forme, le Compilateur (par l’intermédiaire du Pré–processeur) va
chercher la bibliothèque mentionnée dans le/les répertoire/s de l’interface du
Logiciel de programmation .
Dans le cas du Turbo C, la séquence

OPTION Directories Include files

permettra de connaître ou préciser ces répertoires .

Remarque Sous Turbo C la compilation se fait en 2 passes.


– Une 1ère passe au cours de laquelle un "compagnon" du compilateur
appelé le PREPROCESSEUR fait d'abord son travail. Les tâches qui lui sont
destinées sont généralement précédées du caractère  .
– Une 2ème passe au cours de laquelle le compilateur fait son travail en
effectuant (pas nécessairement) une édition de lien et produit souvent un fichier
exécutable associé au programme.

LangC – 3 DEFINITION ET DECLARATION DE CONSTANTE


Pour définir ou déclarer une constante, on se sert de la directive define
Exemple
define imax 1000
define pi 3.1415926535897
define bonjour "bonjour"
define exist

Remarque
1)La directive define ne sert pas strictement à définir ou déclarer des paramètres.
Elle sert également à déclarer des MACROS.
2) La définition d’une constante à l’aide d’une valeur donne implicitement le type
de la constante :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 3
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
#define pi 3.14 sous entend que pi est de type réel
#define strg "bonjour" sous entend que strg est une chaîne de caractères
3)En C, on peut définir des constantes ou des paramètres sans leur attribuer de
valeur comme par exemple
#define MOIJEXISTE
Ici MOIJEXISTE est un paramètre qui se contente d’avoir une existence dans le
programme
4) La directive #define sert également à définir des MACROS
Exemple
define max (a, b) ((a > b) ? a : b)
define permut (a, b, t) ( t = a ; a = b ; b = t )

Il y a une différence entre une MACROS et une fonction ou procédure : une


MACRO substitue (ou remplace) son code à l'emplacement où elle est mentionnée
dans le programme ; cette substitution n’a pas lieu avec une fonction qui, en plus,
effectue des opérations manipulant une pile d'appel de fonction.
Exemple include <stdio. h>
 define permut (a, b, t) (t = a , a = b , b = t)
int x , y;
void main (void){
int t ;
x = 10 ;
y=0;
permut (x,y,t) ;
}
l’expression permut (x, y, t) sera substituée par (t = x , x = y , y = t)
– l’appel d’une macro fonctionne généralement plus vite que celle d'une fonction
. Bien que les macros soit avantageuses sur les fonctions pour leur rapidité
d’appel, il ne faut pas en abuser, car une macro produit plus facilement qu’une
fonction des mauvais effets de bord .

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 4
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Exemple :
Pour la macro définie par define Doubler1(a) (2 * a)
l’appel Doubler1 (x + y) sera substitué par 2*x + y
pour une bonne implémentation il faut la définir par
define Doubler (a) ( 2* (a))
l’appel Doubler(x+y) sera alors substitué par 2*(x+y)

LangC – 4 DECLARATION DES TYPES


Le Langage C possède des types scalaires prédéfinis tels que :
char : caractère
int , long : pour les nombres entiers
float , double : pour les nombres réels
char  : chaîne de caractère
Ce sont évidemment les types les plus connus et les plus utilisés.
En C il n'y a pas de types booléens (la valeur entière nulle est considérée comme
FAUSSE et toute valeur entière non nulle est VRAIE)
Bien entendu tout programmeur aura besoin de traiter des types de données qui
ne sont pas prédéfinis dans le langage C ; le Langage C lui permettra de le faire
en utilisant le mot réservé typedef à l’aide d’une syntaxe générale de la forme
typedef <type de donnée à désigner> <nom du type de donnée> ;

Exemple typedef struct


char  nom ;
int nom :
} ETUDIANT ;
Ici le nouveau type de donnée est ETUDIANT. La mise en œuvre des types de
données demande une maîtrise des structures de données que nous verrons dans
la 2ème partie.
I–5 LES VARIABLES

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 5
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Une variable ou un identificateur désigne une adresse sous forme d'une
appellation. Cette désignation est établie à l'aide d'une lettre minuscule ou
majuscule suivie ou pas de chiffres ou de lettres minuscules ou majuscules : x 1,
X1 , xmin , XminDeb , XminFin , X1minDeb , …
Le langage C fait une distinction entre les minuscules et les majuscules.
Par ailleurs un nouvel identificateur ne doit pas être un mot réservé du langage C
comme int , char , ….; le blanc souligné "_" est également pris en compte.
La syntaxe déclarative d’un identificateur de variable sera généralement de la
forme <type_de_la_variable > nom_de_la_variable ;
Exemples 1) int x ;
2) int i , j , k , xmin ;
Ici i , j , k , et xmin sont tous de type int (type entier)
3) float x;
int i ;
char * str ;
Remarque:
A l'aide de typedef , le programmeur conçoit ses propres types de données;
ensuite il peut déclarer une ou plusieurs variables qui sont associées
à ces types de données
Exemple : 1) typedef struct {
int num ;
char * nom ;
} ETUDIANT ;
ETUDIANT etd1 , etd2 ;
2) typedef float tnot[100] ;
tnot t ;
Le type booléen n'existe pas en C : il faut le construire si besoin est.
Le mot réservé enum peut permettre de construire un type booléen :
typedef enum {FAUX, VRAI} BOOLEAN ;
BOOLEAN varlogic ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 6
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Il est à noter qu’une énumération initialise implicitement ses éléments avec les
valeurs suivantes 0,1,2,…. dans l’ordre croissant ; dans l’exemple précédant
FAUX a donc la valeur 0 et VRAI la valeur 1. varlogic est une variable de type
BOOLEAN ; les valeurs gérées avec varlogic doivent impérativement être
mentionnées dans l’énumération associée à varlogic. D’autre part pour un usage
optimal de typedef, il faut une maîtrise des structures de données .

LangC – 6 LES FONCTIONS


Une fonction permet de prendre en compte le code d’un sous–programme, et est
généralement destinée à être utilisée dans un programme principal. Les sous
programmes dans les langages structurés mettent en oeuvre des procédures, mais
en Langage C il n’y a pas de procédures, une procédure est un cas particulier de
fonction. On peut déclarer une fonction en respectant la syntaxe suivante :
<type_de_retour> nom_de_fonction (argument/s avec leur type) ;
les arguments sont optionnels
Exemple int Ajoute (int a , int b) ;
void permut (float x , float y) ; /* déclaration */
void RienFaire (void) ;
int ajoute2 (int a , int b) ;
Une fois qu'une fonction est déclarée , elle devra être définie.
Exemple de définition pour les quatre (4) fonctions déclarées ci–dessus :

int ajoute(int a , int b) int ajoute2(int a , int b)


{ {
int x=a+b ; return(a+b) ;
return(x) ; }
} void RienFaire(void)
void permut(float x , float y) {
{ ;
float t ; }
t=x , x=y , y=t ;
}

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 7
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Remarques
I- On verra que la fonction permut( ) qui devrait échanger les valeurs de x et
y ne modifie pas x et y, car les arguments sont passés par valeur et non
par adresse.
II- Le langage C permet de définir des fonctions récursives
Exemple int factoriel (int n)

if (n == 0) return (1) ;
else
return (n * factoriel (n – 1)) ;

Cependant pour bien écrire une fonction récursive, il faut avoir décelé une
condition d'appel non récursif.

Les modes de passage par adresse et de passage par valeur


La définition de la fonction permut( ) telle qu'elle est écrite restitue les
valeurs de a et b après la fin de permut( ).
a et b sont passés par valeur. Ces arguments ne sont pas des pointeurs (des
adresses) sur des réels. Pour que les arguments d’une fonction puissent subir une
modification, il faut les passer par adresse, en utilisant des pointeurs comme dans
l’exemple suivant :

void permut2 (float *x , float * y)


float t ;
t =*x;
*x=*y;
*y=t;

La fonction permut2() corrige le problème de modification des valeurs de x et y.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 8
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Remarque La fonction main( ) est associée au corps du programme principal.
Son entête peut suivre différentes formes parmi lesquelles :
void main (void) ;
void main (int argc , char * argv[] ) ;
Donnons quelques exemples d’utilisation de main :
void main (void) { void main (void){
int n = 10 ; float x , y ;
int m ; x=0;
m = factoriel (n) ; y=1;
(void) factoriel (n/2) ; permut (x, y) ;
} permut2 (&x, &y) ;

void main (int argc , char * argv[ ] )



int i
for(i =0 ; i< argc ; i++) printf("%s\n" , argv[i] ) ;

Dans le dernier exemple , lorsque le programme est exécuté sur la ligne de
commande (de MSDOS en l’occurrence) , le nombre de paramètres de la ligne
de commande sera stocké dans argc , les paramètres sont traités en tant que
chaînes de caractères , le premier paramètres sera stocké dans argv[0] , le
deuxième paramètre dans argv[1] , le troisième dans argv[2] …
La fonction main ci–dessus se contente donc d’afficher la liste des paramètres
lancés sur la ligne de commande.
La structure de contrôle for( ) utilisée sera étudiée très ultérieurement.

EXEMPLE DE PROGRAMME
 include "stdio. h"
 define imax 9
 define absol(a) ( ((a) > –(a)) ? (a) : – (a))

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 9
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

typedef enum {FALSE , TRUE} boolean ;


int n , m;
boolean b;
float factoriel (int n) ;
float factoriel2 (int n) ;
void main (void)
{
n=8;
m = factoriel (n) ;
printf ("%d\n", m) ;
scanf ("%d", &n) ;
n = absol (n) ;
n= factoriel2(n) ;
b = ( (n > m) ? TRUE : FALSE ) ;
printf ("%d\n", b) ;
if (b == FALSE) printf ("Echec") ;
else printf ("Très bien")
}
float factoriel (int n)
{/* n doit être positif ou nul : n>=0 */
if (n == 0) return (1) ;
else return (n * factoriel (n – 1)) ;
}
float factoriel2 (int n)
{/* n doit être positif ou nul : n>=0 */
return ((n == 0) ? 1 : n * factoriel2 (n – 1)) ;
}

Structure de contrôles, opérateurs, récursivité sont mis en œuvre dans ce


programme étudions les.

LangC – 7 LES STRUCTURES DE CONTROLE

Comme le Langage Pascal, le Langage C possède des Structures de Contrôle


telles que les test conditionnelles , les boucles, … Les structures de contrôle
permettent généralement à un programme d’avoir un comportement dynamique,
non figé effectuant des branchements. Le Langage C est donc un langage

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 10
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Structuré contrairement aux langages tels que l'ASSEMBLEUR, et le Langage
MACHINE.
Nous passons en revu dans ce cours introductif, les structures de contrôle les plus
fréquemment rencontrées .

LangC 7a) Le Test Conditionnel Si... alors

La syntaxe générale de la 1ère version de la structure conditionnelle est


if ( < expression> ) <instruction(s)>
Exemple 1) if (i > 0) j = i ;
2) if ((i > 0) && (j > 0)) k = i + j ;
3) if (i) j = i ;
4) if (i > 0) {
j=i;
k=i–1;
}
5) if ((i > 0)  (j > 0))
{
if (i > 10) j – – ;
k ++ ;
} /*Pas de ";" après l'accolade fermante*/
– Pour le premier exemple :
1) lorsque i > 0 , on affecte i à j
2) && représente l’opérateur ET logique
– Une condition ayant une valeur numérique différente de 0 est considérée
comme vraie. Il n'y a donc pas que les expressions booléennes qui soient
testées par les structures de contrôle conditionnelles

LangC 7b Si... alors......sinon

Sa syntaxe générale sera de la forme :


if (<expression >) <instruction1(s)>

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 11
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

else <instruction(s)>
e1) if (i > 0) j = i ; e2) if (i > 0) {
else j = –i ; j=i;
k=2*i;
}
else k = –i ;
e3) if (i > 0) {j=i; e4) if (i > 0) k = i ;
k=2*i; else { k = –i ;
} j = –2 * i ;
else { j=2*i ; k=i ; } }
Remarque :
Lorsque la partie "if" n'est pas un bloc d'instructions mais une instruction
élémentaire, il ne faut pas oublier le ";" qui termine l’instruction et précède le
"else" .
LangC 7c L’interrogative (expression1) ?expresssion2 : expression3

Lorsque expresssion1 est vérifiée, c'est expression2 qui donne le résultat


sinon c'est expression3 qui donne le résultat.
Exemples
e1) (n > 0) ? (x = factoriel (n)) : (x = factoriel (–n));
e2) x = (n > 0) ? factoriel (n) : factoriel (–n) ;
e3) x = ( (n > 0) ? factoriel (n) : x ) ;
e4) (n > 0) ? x=factoriel (n) : ;
e5) prim= (nbhrs >= 500) ? 50.000 :
( (nbhrs > 400) ? 40.000 :
((nbhrs > 300) ? 30.000 : 20.000)
);
La structure interrogative possède souvent elle même une valeur contrairement à
une structure if…else...

LangC 7d La structure tant que


Sa syntaxe générale sera de la forme :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 12
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
while (< expression >) < instruction (s)>
Exemple 1 while(i>0) i – – ;
Exemple 2 while (i>0) { j++ ; i– – ; }
Exemple 3 while ((i>0) && (i<10 )) ;
Exemple 4 while (i– –) ; /* while (i !=0) i = i– 1 ; */
Exemple 5 while (– – i) ; /* i est decrémenté avant d'être testé */

LangC 7 e La structure répétitive


Sa syntaxe générale sera de la forme :
do < instruction (s) > while ( < expression > )

Exemple 1 char c ;
int i=10 ;
do i = i–1 ; while (i>0) ;
do c = getch () ; while ( kbhit ( ) ) ;
Exemple 2 int i =0 , j=10 ;
do{
i++ ; j– – ;
} while(j>0) ;

LangC 7f La structure de contrôle "pour…"


La boucle for( ) est une généralisation de la boucle tant que. Sa syntaxe
générale est :
for (expression1 ; expression2 ; expression3) <instruction(s)>
Elle est équivalente à :
expression1 ;
while(expression2) {
<instruction(s)> ;
expression3 ;
}

Exemple int i ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 13
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
for(i=0 ; i<10 ; i++) t[i]=i ;
ces instructions sont équivalentes aux suivantes :
i=0;
while(i<10){
t[i]=i ;
i++ ;
}
Remarque : Les trois expressions sont facultatives ; au cas où les trois
expressions seraient absentes, la boucle for( ) écrite sous la forme "for( ; ; )" est
une boucle infinie.

LangC 7g L’instruction d’aiguillage (switch)


Cette structure de contrôle permettra de discuter plusieurs cas de figures de façon
explicite . Sa syntaxe générale est :
Switch (<expression>) {
case <valeur1> : <instruction(s)1>
case<valeur2> : <instruction(s)2>
case <valeur3> : <instruction(s)3>
[default] : <instruction(s) par défaut>
}
Le cas par défaut est bien entendu optionnel. Lorsqu’un cas est pris en compte,
les instructions associées ainsi que les instructions qui suivent le cas concerné sont
exécutées jusqu’à la rencontre d’une instruction "break" ou de la fin du switch( ).
Le programmeur à donc pour charge d’insérer des instructions break si nécessaire.

Exemple 1
switch( i) {
case 0 : j=0 ;
case 1 : { j=1 ; i++ ; }
case 2 : k++ ;
default : k=20 ;
}

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 14
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Exemple 2
char c ;
switch(c = getch ( )) {
case 0 : switch (c = getch( )) {
case 72 : { i++ ; break ; }
case 73 : { i– – ; break ;}
default : break ;
} break ;
case ‘A’ : { printf ( c’est la lettre A\n) ; break ;}
default : break ;
}
Le langage C possède également une structure de contrôle de branchement "goto"
à une étiquette que l’auteur du présent fascicule déconseille en l’occurrence, car
le caractère structuré d’un algorithme est inversement proportionnel au nombre
de goto dont il fait usage.
Les structures de contrôle vues ci–dessus ont été volontairement mises en œuvre
à l’aide d’instructions très simples voire primitives , car l’objectif est de montrer
au débutant comment il devrait se servir de ces structures de contrôles ; c’est leur
syntaxe qui est importante à retenir et non l’intelligibilité des instructions figurant
dans le corps de ces structures de contrôle. Nous passons maintenant à
l’élaboration d’une instruction; les problèmes de sémantique seront considérés
dans les parties projets et algorithmes .

LangC 8 EXPRESSIONS , OPERATEURS ET INSTRUCTIONS

LangC 8a ) Les expressions

Une expression en C s’écrit à l’aide d’identificateurs, de constantes,


d’opérateurs...
Un identificateur permet d’identifier une variable, un paramètre, une
constance ; en fait il s’agit d’un libellé d’adresse.
Un identificateur en C sera de manière générale une lettre minuscule ou
majuscule suivie ou pas de lettres ou de chiffres minuscules ou majuscules ; le

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 15
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
langage C contrairement au Pascal fait une distinction entre minuscules et
majuscules ; nous rappelons que le caractère "_" peut figurer parmi les lettres
d’un identificateur.
Exemple : x1 , xmin, xmax , Xmin , xmin_ , xmax2 , _xmax , _x1_ ,
min_max , …
Les identificateurs de fonction seront appelés avec parenthèses ouvrantes et
fermantes ( , et ). Il est d’usage courant de nommer des identificateurs de
paramètres, c’est–à–dire des constantes, avec des lettres majuscules. Un
identificateur peut être d’un type scalaire (constante, chaîne de caractère, …) ou
construit avec le mot clé typedef.

LangC 8b) Les opérateurs


Le langage C dispose des opérateurs qu’on trouve dans la plupart des autres
langages ; un opérateur peut être unaire (avec un seul opérande) ou binaire ( avec
deux opérandes). Dans l’optique de ce cours introductif nous passons en revue
quelques opérateurs très usuels en C.
Opérateurs unaire
Op1) – (opposé) exemple –x
Op2) ++ , – – (incrémentation et décrémentation d’une unité)
Remarques :
I- L’instruction x = y++ met la valeur de y dans x et incrémente ensuite la
valeur de y.
x = ++y incrémente d’abord la valeur de y et met ensuite cette
valeur dans x.
Ces deux instructions et leurs analogues conçues à l’aide de l’opérateur – –
modifient donc aussi la valeur de y .
II- L’instruction y++ augmente y d’une unité mais est plus performante que
l’instruction y = y+1 .

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 16
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

Op3) L’opérateur ! (négation logique)


Exemple if ( ! (x>0)) x++ ;
If ( ! x) x++ ;
If ( ! kbhit ( ) ) x++ ;
Op4) L’opérateur  (donne le complément à 1) ; exemple : ~x
Op5) L’opérateur * (en gestion des pointeurs ou des adresses)
et l’opérateur & (en gestion des pointeurs ou des adresses)
exemple 1 &x ; /* donne l’adresse de x */
exemple 2 int i ;
int *x ;
x = &i ; /*x est l’adresse d’un entier et est adressé sur i*/

Bien entendu dans l’exemple de programme suivant ,


# include <stdio.h >
void main (void)
{
int i ;
int * x ;
x = &i ;
*x=15 ;
printf("%d\n",i) ;
}
la valeur de i est finalement 15 , car *x désigne la valeur de l’élément adressé
par x , qui est ici i .
Op6) L’opérateur ( ) de cast ou de conversion de type ou de coercision

Exemple
int i=10 ;
float x;
x = (float)i ;
/*convertit i en nombre réel avant d’installer le résultat 10.0 dans x */

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 17
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Opérateurs binaires : +, – , * , / , % , & , | , ^ , &&, ||, =, == , != ,
<< , >> , ...
Parmi les quatre opérateurs arithmétiques classiques, l’addition , la multiplication
et la soustraction fonctionneront comme nous le savons déjà , mais la division
mérite quelques commentaires.
Op7) La division /

La division est à la fois une division entière (euclidienne) et réelle.


• si les 2 opérandes sont des entiers , le résultat est un entier.
• Si l'un des deux opérandes est un réel , le résultat est un réel.
Exemple: x=2/5 ; /* La valeur affectée à x est 0*/
x=2/5.0 ; /* La valeur affectée à x est 0.40 */

Si i et j sont 2 opérandes de type entiers et si nous voulons mettre le quotient


de i par j dans une variable x qui est de type réel, à priori l’instruction est: x= i/j.
Mais alors si j>i ce sera 0 qui sera affecté à x. Pour cela il faut utiliser l’opérateur
de cast.
Exemple
int i , j ;
float x ;
x= ((float)i) / j ; /* ou x = i/((float)j) , j doit être non nul */

Op8) L'opérateur modulo %

Il donne le reste de la division entière (ou euclidienne) du premier opérande par


le deuxième opérande quels que soient les types des opérandes (convertit
implicitement les deux opérandes en entier). Cependant il convient d'utiliser des
opérandes de type entier; le deuxième opérande ne doit évidemment pas être nul.
Exemple int i , j , k;
k=i % j ; /* j est supposé non nul */

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 18
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

Op9) L' opérateur & (en arithmétique binaire)


exemple
1100101
& 1110010
1100000
int i , j , k ;
k = i&j ;

Op10) L'opérateur | (OU inclusif arithmétique)


10110110
| 11010111
11110111
exemple d'application : k=i | j ;
Op11) Les autres opérateur
^ (OU exclusif arithmétique) Exemple: k= i ^ j ;
&& (ET logique – en algèbre propositionnelle) Exemple: (i>0)&&(j>0)
|| (OU logique – en algèbre propositionnelle) Exemple: (i>0)||(j>0)
= affectation Exemple: i=1
= = comparaison (égalité) Exemple: a==b
!= différence Exemple: a!=b
<< décalage de bits vers la gauche Exemple: k=i<<5
>> décalage de bits vers la droite Exemple: k=i>>5
Le décalage de n bits vers la gauche est une multiplication par 2n ; le décalage
de n bits vers la droite est une division par 2n .
La plupart des opérateurs binaires possèdent une version d'affectation étendue; ce
qui donne les opérateurs +=, –=, *=, /=, %=, &=, |=, …
Exemple : float x ;

x+ = 15.0 ; /* x=x+15.0 */
une expression du type <idf>operbin=<secdmbr> où idf est un identificateur,
operbin un opérateur binaire et secdmbr une expression valable de second
membre sera équivalente à <idf>=<idf>operbin<secdmbr> .
l'exemple ci–dessus x+=1.50 est donc équivalent à x=x+1.50

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 19
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Tous les opérateurs ainsi que les identificateurs et les constantes interviennent
dans les expressions .
En langage C, toute expression (correctement écrite) possède une valeur. C'est
bien là un avantage du langage C sur les autres langages, qui permet d'élaborer
des expressions prenant en compte simultanément plusieurs tâches.
On peut écrire des expressions qui sont des expressions composées. Lorsqu’une
expression est composée de plusieurs expressions, ses composantes sont séparées
par une virgule, la virgule est donc un opérateur binaire de composition
d'expressions. La valeur d’une expression qui est composée de plusieurs
expressions est la valeur de la dernière composante.
Exemple 1 : z=b=x=y+1 associative de la droite vers la gauche
Exemple 2 : if ((x = 1, y = x++, y = z) == 0) k++ ;
Remarquez bien la puissance d'une telle instruction !
LangC 8c) Les instructions
Une instruction est une expression terminée par un ";" (point virgule).
Le ";" termine donc les instructions et ne les sépare pas comme en Pascal.
En guise d'application nous donnons ci-dessous un exemple de programme
permettant de calculer xn à l'aide des opérateurs de décalage et de la décomposition
binaire de n :
#include "stdio.h"
#include "conio.h"
float x , resultat=1.0 , xp , rp ;
int n , p=0 , mask=1 , pp ;
void main(void)
{
clrscr();
printf("\nEntrer la valeur de x: " );
scanf("%f",&x);
printf("\nEntrer la valeur de n:");
scanf("%d",&n);
do {
xp=x , pp=p;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 20
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
if(n&mask) {
if(!pp) rp=x;
else do rp=xp*xp , xp=rp; while(--pp);
resultat *=rp;
}
p++ , mask<<=1;
} while(mask);
printf("\nLe calcul de %f puissance %d donne : %f",x,n,resultat);
getch( );
}

LangC 9 – LES POINTEURS


Un pointeur est une adresse donc un entier. A cette adresse est généralement
installé un type de donnée.
Le langage C intègre les pointeurs d’une manière assez souple. Si p est un pointeur
sur une donnée de type t, alors p+1 représente la donnée de type t qui suit la
donnée pointée par p ou installée à l’adresse de p. De manière générale p+i
représente la donnée numéro i+1 installée à partir de l’adresse de p. (On suppose
que les adresses sont consécutives). Un pointeur peut pointer sur une variable
comme dans l'exemple suivant :
int x , y;
int *p ;

p = &x ;

p est un pointeur qui indique l’adresse de x , *p est donc la valeur de x , p+1 est
l’adresse de l’entier qui suit x , c'est à dire y (parce que x est entier et l’entier
déclaré après x est y ), *(p+1) est donc la valeur de y , *(p+i) est donc la valeur
de l’entier à l’emplacement i+1 à partir de l’emplacement de x.
Généralement lorsque nous déclarons un pointeur, nous devons veiller à ce qu’il
"pointe" à un emplacement "qui nous appartient" : c’est le grand problème des
pointeurs.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 21
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Si le pointeur n’est pas positionné sur une variable ou une donnée que nous avons
déclarée, à partir du moment où une variable est une adresse en mémoire
(généralement mémoire RAM) il faut quand même que le pointeur pointe en
mémoire. Ce qui revient à dire que nous devons effectuer une allocation de
mémoire et installer le pointeur p à l’adresse allouée.
Le langage C ne possède pas d’instruction pour cela mais plusieurs bibliothèques
permettent d’effectuer l’allocation de mémoire.
Exemple : alloc.h , process.h
En Turbo C on peut utiliser la fonction de bibliothèque qui s’appelle malloc( )
dont le prototype est déclaré par void *malloc(unsigned) ; le type void*
représente un pointeur générique. Si on veut allouer un pointeur d’entier, on
remplace void* par int* à l’aide d’un CASTING (opérateur de cast), pour
l'exemple suivant :
int *p ;
p = (int* ) malloc(4) ;
quatre octets seront alloués en mémoire et p pointera sur le premier des octets
alloués. Le nombre d'octets à allouer pourra être calculé en se servant de la
fonction sizeof( ). En général lorsqu'une zone mémoire allouée par malloc( ) n'est
plus nécessaire, il faut la libérer pour qu'elle redevienne disponible pour les
prochaines allocations. Pour cela on se sert de la fonction free( ). L'instruction
free(p) libérera l’espace alloué à p .
Remarque sur les tableaux
En C un tableau est un pointeur. Dans une déclaration comme int tab[100] ; le
nom tab est un pointeur sur un entier (le 1er entier du tableau) , tab est l’adresse
de tab[0] et tab +i est l’adresse de tab[i] ; *(tab+i) est la valeur de tab[i]
L'opérateur d’incrémentation ++ incrémente l’adresse du pointeur p.
Réciproquement, si p est un pointeur sur une donnée de type t, alors p peut être
ème
considérée comme un tableau, et p[i] est la donnée de type t située à la i

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 22
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
adresse après la donnée pointée par p ; cependant le programmeur prendra soin de
ne pas affecter des valeurs à des adresses qu'il n'a pas créée lui même ou dont il a
une ignorance totale . Un morceau de code tel que
char *p ;
p=(char *)malloc(10);
p[15]=1;
peut conduire à des erreurs gênantes.
Dans l'exemple suivant
int x , y ;
int *p ;

p = &x ;
p++ ;
p pointe finalement sur y. La variable y appartient au programmeur, il peut donc
se servir d'une instruction telle que
*p=1; ou p[0]=1;
c'est alors y qui reçoit 1 .

Le programme suivant est un programme de recopie de chaîne de caractères à


l'aide de pointeurs. On notera qu'un pointeur est supposé vrai si sa valeur est
différente de zéro ou si sa valeur n'est pas NULL.
# include <stdio.h>
# include <alloc.h>
void main (void)
{
char buf1[100] , buf2[100] ;
int i = 0 ;
char *p=buf1 , *q=buf2 ;
do {
*buf1 = getch () ;
i++ ;
} while ((i<99)&&(*(buf1++) !=0)) ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 23
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
* (p+99) = 0 ; /* 0 ou '\0' doit terminer les chaînes de caractères ! */
while ( *q++ = *p++ ) ;
printf("%s\n", buf2);
}
Nous donnons une deuxième version de ce programme :

#include <stdio.h >


#include <alloc.h>
void main (void){
char * buf1, *buf2, *p, *q ;
int i = 0 ;
buf1 = (char*) malloc(100 × sizeof(char)) ;
buf2=(char*)malloc(100 × sizeof(char)) ;
p = buf1, q = buf2 ;
do { *buf1=getch() ; i++ ; } while ((i<99)&&(*(buf1++) ! =0)) ;
*(p+99) = 0 ;
while ( *q++=*p++ ) ;
printf ("%s\n", buf2) ;
}
Lors d'un appel à malloc( ) il est possible qu'il n 'y ait pas d'espace disponible en
mémoire. Dans ce cas alors, le pointeur retourné par malloc( ) est NULL .
Le programme précédent doit donc être écrit plus proprement de la manière
suivante :
# include <stdio.h>
# include <alloc.h>
void main (void){
char *buf1, buf2, *p, *q ;
int i = 0 ;
if( (buf1 = (char*) malloc(100 × sizeof(char))) ! = NULL)
if( (buf2 = (char*)malloc(100 × sizeof (char))) ! = NULL)
{ p = buf1, q = buf2 ;
do{
*buf1 = getch () , i++ ;
}while ((i < 99)&&(*(buf1++) ! =0)) ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 24
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
*(p+99)=0 ;
while( *q++ = *p++ ) ;
printf("%s\n", buf2) ;
} /* fin de l’if buf2 */
else printf ("impossible d’allouer buf2 ! \n") ;
else printf("impossible d’allouer buf1 ! \n") ;
}

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 25
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

PARTIE II :
STRUCTURES de DONNEES et

ALGORITHMES en C

INTRODUCTION

Les structures de données et algorithmes mentionnés dans cette partie sont conçus
en C mais pourront assez facilement être transposés dans d'autres Langages de
programmation structurés. L'auteur garde ici assez d'originalité due à une
expérience et n'oublie cependant pas qu'il s'adresse à des débutants ou des initiés.
Le lecteur avancé pourra d'une part consulter l'auteur pour des conseils
particuliers, d'autre part s'intéresser plus efficacement à la troisième partie de ce
fascicule qui développe des minis–projets.

AlgoC I– STRUCTURES DE DONNEES


AlgoC I.I Enregistrements et Unions

Un enregistrement est une structure de données permettant de regrouper des


informations de différentes natures et représentant dans leur ensemble un type
complexe d'information. Ainsi par exemple quelques informations fondamentales
dans la gestion d'un employé sont le nom(qui est une chaîne de caractères),
l'adresse(encore une chaîne de caractères), le numéro matricule(un entier) , le
numéro de téléphone(un entier), le salaire(un réel); nous nous limitons à ces cinq
informations. Dans leur ensemble ils constituent une seule information que nous
pouvons désigner par le libellé Employe; en C la déclaration d'un employé pourra

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 26
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
se faire avec le mot clé struct réservé aux enregistrements, et la syntaxe
déclarative sera généralement de la forme
struct{
<type du champ 1> <nom du champ 1>;
<type du champ 2> <nom du champ 2>;
<type du champ 3> <nom du champ 3>;
.
.
<type du champ n> <nom du champ n>;
};
Ainsi par déclaration de type, notre entité employé pourra être construite de la
manière suivante

typedef struct{ typedef struct Employe{


char * nom; char * nom;
char * adresse; char * adresse;
int numatric; int numatric;
int teleph; int teleph;
float salaire; float salaire;
} Employe; };
Employe e; Employe e;

Première version Deuxième version


e représente ici une variable qui est de type Employe. L'accès à un des champs
du type Employe se fera à l'aide du symbole "." ; pour initialiser le champ
désignant le numéro matricule avec la valeur 1 on tapera donc
e.numatric=1;
Ici notre enregistrement est conçu avec des types scalaires. Dans la suite de ce
fascicule on rencontrera des enregistrements conçus avec des type de données
évoluées qui sont parfois des enregistrements, aucune limitation n'est imposée
mais les types intervenant dans la construction d'un enregistrement doivent avoir

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 27
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
été conçus eux–mêmes avant d'en faire usage dans la construction de
l'enregistrement désiré. D'autre part l'accès aux champs d'un enregistrement doit
respecter les types de données. Dans les déclarations suivantes
typedef struct{
int num;
char * nom;
float tnotes[10];
}Eleve;
typedef struct{
int salle;
Eleve list[50];
}Classe;
typedef Classe Ecole[20] ;
Ecole ecl;
ecl est une variable de type "Ecole", qui est un tableau de 20 "Classe" regroupant
(chacune) une salle et une liste de 50 "Eleve" ….
Pour initialiser la 3–ième note du 2–ième élève de la 4–ième classe de l'école ecl
avec la valeur 12.50, on utilisera donc l'instruction
ecl[3].list[1].tnotes[2]=12.5;
Les types de données et leur mode d'accès sont ici respectés . on n'oubliera
pas qu'en C les indices des tableaux commencent par 0 .
Une autre version de type de données similaire aux enregistrements est l'union
qui se déclare comme dans la première version des enregistrements vue ci–dessus,
avec le mot réservé union . Les champs d'une union sont par défaut des entiers
initialisés de manière croissante à partir de zéro ; l'exemple
typedef union{FAUX , VRAI}Boolean;
déclare un type de donnée appelé Boolean à l'aide d'une union ; la première
valeur de l'union déclarée est 0 et est libellée FAUX, la deuxième valeur de
l'union est 1 et est libellée VRAI; par contre dans la déclaration
typedef union{

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 28
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
TRESFAUX=–2 , FAUX , RIEN , VRAI , TRESVRAI
} HyperBoolean;
les valeurs de l'union HyperBoolean sont –2 , –1 , 0 , 1 , 2 dans le sens croissant,
à partir de la valeur –2 imposée ici .
Le Logiciel Turbo C met en œuvre les unions dans la bibliothèque dos.h afin
de permettre par exemple la déclaration des registres intervenant dans les
interruptions et la programmation système.

Remarque
Si p est un pointeur sur une structure (un enregistrement) ayant un champ libellé
c, l'accès à ce champ se fera par l'appel (*p).c ; le langage C simplifie cette
expression en permettant l'appel p–>c . A l'aide de notre exemple sur les
employés , la déclaration Employe *eptr nous donne un pointeur eptr sur une
structure Employe, on affectera donc le champ numatric par
(*eptr).numatric=1 ou eptr–>numatric=1
La deuxième méthode d'accès sera la plus utilisée dans la suite de ce fascicule.

AlgoC I.II Piles et Files statiques


AlgoC I.II a) Piles statiques
Une pile est une structure de donnée permettant de stocker des informations,
généralement en vue d’une consultation ultérieure. Mais dans le cas d’une pile le
stockage s’effectue par une "porte" et la récupération s’effectue par la même
porte. Par conséquent, lors d’une récupération d’une donnée dans une pile, c’est
le dernier élément stocké qui est récupéré. C’est une structure de données de type
LIFO (Last In First Out).
La pile statique est en fait un enregistrement qui contient deux champs. Le premier
champ indique la position de stockage ou de déstockage. Le second champ est un
tableau qui contient la liste de tous les éléments présents dans la pile. Les
déclarations en C seront (de façon standard) :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 29
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

#define nbMax 50
typedef union{FAUX , VRAI}Bool;
typedef int typinfo;
typedef struct {
int sommet ;
typinfo corps[nbMax] ;
}PILE ;
Ici nbMax représente le nombre maximum d'éléments que nous désirons gérer
dans la pile, les informations stockées dans la pile sont de type typinfo, le type
typinfo est int à présent mais devra être déclaré selon le contexte d'étude; nos
algorithmes devant être standards et adaptables nous avons donc choisi le type
simple int; sommet est un champ qui indique la prochaine position de stockage
d'une information dans la pile, et corps est un tableau contenant les éléments
rangés dans la pile. On adopte une fois pour toutes, les deux schémas suivants
pour empiler et dépiler. A chaque fois qu’on veut empiler, on empile dans le corps
de la pile à l’emplacement indiqué par la valeur de sommet et on incrémente la
valeur de sommet afin d'apprêter la prochaine position d’empilage. Pour la
récupération d’un élément, on décremente sommet et ensuite on récupère la valeur
indiquée à la position de sommet. Bien entendu, il faut qu’au départ sommet soit
égal à 0 et dans ce cas la pile est vide. La fonction d’initialisation de la pile va
affecter 0 à sommet.
Dans notre gestion, comme les indices commencent par 0 et qu’il y a nbMax
éléments au total, le dernier élément est stocké à la position nbMax–1 et alors
sommet vaut nbMax c’est–à–dire que la pile est pleine quand sommet vaut nbMax.
Si jamais notre programme tente de dépiler dans une pile vide, nous allons afficher
le message "dépilage refusé" et ensuite arrêter le programme.
Si notre programme tente d'empiler dans une pile pleine, nous allons afficher le
message "empilage refusé" et arrêter le programme.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 30
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
On arrêtera le programme avec la fonction exit( ) de la bibliothèque stdlib.h .
Les prototypes des primitives de base de gestion d'une pile statique seront donc
void Creer (PILE *p) ;
Bool PileVide (PILE p) ;
Bool PilePleine(PILE p) ;
void Empiler (PILE *p , typinfo elt) ;
typinfo Depiler (PILE *p) ;
Les définitions de ces primitives de base peuvent être

void Creer (PILE *p)


{
p → sommet = 0 ; /* (*p).sommet =0*/
}

Bool PileVide(PILE p)
{
Bool b;
return (b=((p.sommet = = 0) ?VRAI :FAUX)) ;
}

Bool PilePleine(PILE p)
{
Bool b=((p.sommet == nbMax) ?VRAI:FAUX);
return (b) ;
}

void Empiler (PILE *p , typinfo elt)


{
if( !PilePleine(*p))
p →corps[(p→sommet)++] = elt ;
else {
printf ("Empilage refusé dans une pile pleine! \n") ;
exit(1);
}

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 31
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
}
typinfo Depiler (PILE *p)
{
if(PileVide(*p)) {
printf ("dépilage refusé dans une pile vide ! \n") ;
exit (1) ;
}
else return (p →corps [– – (p→sommet)] );
}
Bien entendu les codes peuvent être modifiés ou optimisés. Nous laissons ce soins
au lecteur.
Exercice d’application
On considère un tableau t d’entiers non ordonnés; on dispose de deux piles p
et q vides pour trier le tableau t de la manière suivante:
Au départ on range le premier élément e1 de t dans la pile p et on se positionne
sur le deuxième élément e2 de t. On retire alors tous les éléments de p qui sont
inférieurs à e2 et on les range dans q, on range ensuite e2 dans p et on récupère
les éléments de q pour les remettre dans p; on se positionne maintenant sur le
troisième élément de t et on recommence le même processus jusqu'à ce qu'on ait
traité tous les éléments de t. A ce moment alors les éléments de t sont rangés en
ordre décroissant du bas au sommet de la pile p ! Ecrire le programme en C !

/*_______________________________________________________________
PROGRAMME DONNE PAR L'auditeur Ingénieur
DOFFONSOU Adrien au cours du Module17 Année 1997/1998
REVU et CORRIGE par:
Constant K. KOUAKOU
_______________________________________________________________
*/

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define Nmax 100

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 32
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
#define TailleMax Nmax
typedef struct { int sommet ;
int corps[TailleMax] ;
} PILE ;
PILE p , q ;
void Creer (PILE *p){
p→sommet = 0 ;
}

int PileVide (PILE p)


{
return ((p.sommet == 0) ?1 :0) ;
}

int PilePleine(PILE p)
{
return ((p.sommet ==TailleMax) ?1 : 0) ;
}

int Depiler (PILE *p)


{
if(PileVide(*p)){
printf ("dépilage refusé !\n") ;
exit(1) ;
}
else return(p→corps[––(p→sommet)]) ;
}

void Empiler (PILE *p , int elt)


{
if( !pilepleine(*p)){
p→corps[p→sommet] = elt ;
p → sommet++ ;
}
else{
printf ("empilage refusé ! \n") ;
exit (1) ;
}
}

void SaisieTab (int *t)


{

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 33
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
int i ;
for (i = 0 ;i < Nmax ; i++) {
printf ("donner la valeur de t[%d] :",i) ;
scanf("%d", (t+i)) ;
}
}

void Traiter (PILE *p1 , PILE *p2 , int *t)


{
int secour ; int i = 0;
Creer (p1) ; /* initialisation des tableaux/
Creer (p2) ;
Empiler (p1 , *t) ;
t++ ; /* inclémente l’adresse pour atteindre l’élément suivant */

do {
do{
secour=Depiler(p1) ;
if (secour < *t) Empiler (p2,secour) ;
}while ( !PileVide (*p1)&&(secour< *t)) ;
if (secour>= *t) Empiler (p1, secour) ;
Empiler (p1, *t);
while ( !PileVide(*p2)) Empiler (p1, Depiler(p2)) ;
i++ , t++ ;
}while (i< Nmax);
}
void Affichage (PILE *p) {
while( !PileVide(*p)) printf ("%d\n", Depiler(p)) ;
getch();
}

void main (void){


int t[Nmax] ;
SaisieTab(t) ;
Traiter (&p , &q , t) ;
Affichage (&p) ;
}

Exercice de recherche

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 34
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Les éléments manipulés dans le tableau et les piles sont des entiers. On considère
maintenant que ce sont des enregistrements modélisant des étudiants définis de
la manière suivante :
typedef struct { int num ; char *nom ;
float notes[10] ;
}ETUDIANT ;
Adapter les primitives des piles et le programme précédent afin de pouvoir trier
un tableau d’étudiants par le numéro matricule num.

AlgoC I.II b) Files Statiques


Les Files sont des structures de données rencontrées très fréquemment, il nous
suffit de penser aux cas des files d'attente des guichets . On sert le premier venu
et on dessert le dernier venu ; bien entendu un nouvel élément se range en dernière
position . Ici nous avons une file simple à priorité élémentaire , non circulaire …;
certaines files peuvent être complexes munies d'une fonction de priorité qui sert
et dessert les éléments . Le type abstrait de donnée File Statique pourra être mis
en œuvre de la manière (volontairement simpliste !) suivante :
#define TailFile 100
typedef int typinfo;
typedef struct{
int t , q;
typinfo corps[TailFile];
} File;
Remarque :
Ici q donne la position de l'élément en queue de la file et t donne la position de
l'élément en tête de la file; une file sera donc vide lorsque q<t , un élément est
en tête de la file lorsqu'il doit être servi en priorité, selon une fonction de priorité
prior( ) , avant les autres éléments. Dans le cas le plus simple, la fonction de
priorité appliquée à une file retourne 0 (t est constamment égal à 0), car c'est le
premier élément du corps de la file qui doit être servi, ce qui revient à dire que

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 35
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
dans un cas simpliste de priorité, nous n'avons pas besoin du champs t. Cependant
dans le cas général la fonction prior( ) devra calculer la valeur de t. Le cas général
pourra être étudié en projet. L'ordre de priorité des éléments de la file sera donc
ici l'ordre des indices du tableau corps; et alors notre file est vide lorsque q<0 ,
elle est pleine lorsque q=TailFile–1 .
Les prototypes des primitives de base pour la gestion d'une file statique seront
void CreerFile (File *flptr);
int FileVide (File fl);
int FilePleine (File fl);
void Enfiler (File *flptr , typinfo e);
typinfo Defiler (File *flptr);
leurs définitions seront basées sur les codes suivant :
void CreerFile(File *flptr)
{ flptr –>q=–1 , flptr–>t=0 ; }
int FileVide(File fl)
{ return( (fl.q<fl.t )?1:0) ; }
int FilePleine(File fl)
{ return( (fl.q==TailFile–1)?1:0) ; }
void Enfiler ( File *flptr , typinfo e){
if (FilePleine( *flptr)){
printf ( "Refus d'enfiler un élément dans une file pleine");
exit(1);
}
else flptr–>corps[++(flptr–>q)]=e;
}
typinfo Defiler (File *flptr){
typinfo tp;
int i;
if ( FileVide(*flptr)){ printf("Refus de défiler une file vide !") ; exit(1); }
else{
tp = flptr–>corps[flptr–>t];
for (i=0 ; i<=flptr–>q–1;i++) flptr–>corps[i]=flptr–>corps[i+1];
(flptr–>q) – – ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 36
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
return (tp);
}
}
Exercice de recherche
Dans le codage ci–dessus le champs t d'une file ne varie pas et vaut 0 . Nous
considérons donc une fonction prior( ) de calcule de priorité qui donne la position
de l'élément prioritaire dans une file En admettant qu'il y ait à chaque fois un seul
élément prioritaire et que le prototype de prior( ) est
int prior (File fl) ;
l'élément prioritaire dans une file fl est donc fl.corps[prior (fl)] . Adapter les
primitives et les déclarations de File afin de prendre en compte la fonction prior(
), l'élément prioritaire n'étant pas nécessairement à l'indice 0 du tableau corps de
la file.
AlgoC I.III Structures de données dynamiques simples
AlgoC I.IIIa Listes chaînées
Une Liste Chaînée est une structure de donnée permettant de stocker des
informations en mémoire de façon disparate, contrairement aux tableaux qui
rangent les informations de façon contiguë en permettant des accès à l'aide d'un
indice. Dans une liste chaînée chaque élément "connaît" l'emplacement de son/ses
voisin/s immédiat/s, ce qui est à la base de l'expression "chaînée". On utilise donc
les listes chaînées généralement pour éviter les risques de manque de mémoire.
Les éléments d'une liste chaînée doivent être alloués, l'adresse de l'élément de
départ permet généralement de gérer toute la liste . Une cellule de la liste sera un
enregistrement contenant une information capitale et l'adresse ou les adresses des
cellules immédiatement voisines. Dans le cas d'une liste chaînée simple qui gère
les adresses des successeurs , nous obtenons un schéma du type

X Y Z T NULL ;

lst
Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule
… 37
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

lst est un pointeur donnant l'adresse de départ de la liste qui a ici quatre éléments;
les listes chaînées à simple chaînage que nous allons voir sont généralement
définie de la manière suivante:

typedef int typinfo ; typedef int typinfo;


typedef struct list_node *list_ptr ; typedef struct list_node{
typedef struct list_node{ typinfo data ;
typinfo data ; struct list_node *link ;
list_ptr link ; } * list_ptr ;
};

Première version Deuxième


version

Type list_ptr = ^ list_node ;


list_mode = record
data : integer ; en Pascal
link : list_ptr ;
end ;

L'instruction list_ptr lst = (list_ptr) NULL ; initialise le pointeur nulle part.


On se servira d'une macro IS_EMPTY pour savoir si la liste est vide.
#define IS_EMPTY(lst) ( ((lst) = = (lst_ptr)NULL) ? 1 : 0 )
Les prototypes des primitives de base que nous rencontrerons dans la gestion
d'une liste chaînée à simple chaînage sont
void Creer ( list_ptr *lst );
int AjoutTete ( list_ptr *lst , typinfo e );
int AjoutQueue ( list_ptr *lst , typinfo e );
int AjoutQueueRec (list_ptr *lst , typinfo e)

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 38
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
int InserApres (list_ptr *lst , int e1 , int e);
int Supprimer (list_ptr *lst , typinfo e);
list_ptr SupprimerRec (list_ptr *lst , typinfo e);
void Detruire (list_ptr *lst);
void DetruireRec (list_ptr *lst);

Creer initialise une liste à NULL:


void Creer ( list_ptr *lst ) { *lst = (lst_ptr)NULL ; }
AjoutTete( ) et AjoutQueue( ) retournent 1 lorsque l'élément a effectivement été
introduit dans la liste chaînée et 0 sinon , AjoutQueue( ) a une version récursive
AjoutQueueRec( ).
Soit lst une liste chaînée d’entiers

X Y Z • NULL

lst

Nous désirons ajouter en queue de lst un élément dont l'information capitale est
e afin d'obtenir la liste suivante:

• NULL
X Y Z

lst e • NULL

Pour cela il y a plusieurs étapes fondamentales:


1°) Allouer une cellule temporaire tp pour un nœud à un élément
• Copier e dans le champ data de la cellule allouée
• Chaîner le champs "suivant" de la cellule allouée sur un pointeur NULL
2°) Si lst est vide alors on remplace lst par tp, sinon on cherche la queue de lst,
soit q ; on adresse q sur tp : q=tp . Ce qui donne la fonction suivante :

int AjoutQueue(list_ptr *lst , typinfo e)


{ /* Version itérative */

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 39
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
list_ptr q , tp = (list_ptr)NULL ;
if( !(tp=(list_ptr)malloc (sizeof(list_node)))) {
printf ( Plus assez de mémoire ! \n) ;
return (0) ;
}
else {
tp →data =e , tp →link = (list_ptr)NULL ;
if(IS_EMPTY(*lst)) *lst =tp ;
else{ q = *lst ;
while (q→link) q=q→link ;
q→link = tp ;
}
return (1) ;
}
}
int AjoutQueueRec(list_ptr *lst , typinfo e) {/* Version récursive */
if(IS_EMPTY(*lst)){
list_ptr tp;
if( !(tp=(list_ptr)malloc (sizeof(list_node)))) {
printf ( Plus assez de mémoire ! \n) ;
return (0) ;
}
else {
tp →data =e , tp →link = (list_ptr)NULL ;
*lst=tp;
return(1);
}
}
else AjoutQueueRec( &((*lst)–>link) , e);
}
La fonction AjoutTete( ) ne fait pas de recherche de dernier élément de la liste et
semble donc plus simple à écrire :
int AjoutTete (list_ptr *lst , int e)
{ list_ptr tp = (list_ptr)NULL ;
if ( !(tp=(list_ptr)malloc (sizeof(list_node)))) {
printf (Plus assez de mémoire ! \n) ;
return (0) ;
}

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 40
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
else{
tp →data =e , tp → link = *lst ;
*lst=tp ;
return (1) ;
}
}
Pour l'insertion d'un élément e après un élément e1 de la liste chaînée , nous
devons :
1°) Allouer tp pour l 'élément
2°) Chercher e1 avec une liste temporaire q
3°) Chaîner le suivant de tp au suivant de q obtenu
4°) Chaîner le suivant de q à l'adresse de tp
• NULL
e1

q
lst
4°) e 3°)

tp

Le code associé à tout ce procédé sera donc :

int InserApres(list_ptr *lst , int e1 , int e)


{
list_ptr tp , q ;
if ( IS_EMPTY(*lst) ) return(0);
if( !(tp=(list_ptr)malloc(sizeof(list_node)))) {
printf (Plus assez de mémoire ! \n) ;
return (0) ;
}
else{ tp →data = e ;
q= *lst;
while ((q →data != e1) && (q–>link)) q=q→link ;
if (q–>data != e1 ) return(0); /* si e1 n'est pas dans la liste */
tp→link = q –> link ;
q –> link = tp ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 41
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
return (1) ;
}
}
Remarque : Ici au cas où l'élément e1 serait présent dans la liste chaînée ,
l'insertion de e a lieu après la première occurrence de e1 dans la liste; on peut
modifier le code pour que l'insertion ait lieu après la dernière occurrence de e1,
cette précaution est à la charge du lecteur .

La suppression d'un élément de la liste chaînées peut être récursive :

list_ptr SupprimerRec(list_ptr * lst , typinfo e)


{
if (IS_EMPTY(*lst)) return ((list_ptr)NULL) ;

if ((*lst)–>data==e) {
q=*lst , *lst = (*lst)–>link ;
free(q);
}
else (*lst)–>link = SupprimerRec( &((*lst)–>link) , e );
return (*lst);
}

Nous donnons également une version itérative de Detruire( ) qui doit libérer
toutes les cellules allouées dans le chaînage de la liste passée en argument :

void Detruire ( list_ptr * lst)


{
while (! IS_EMPTY(*lst)){
q = *lst ;
*lst = (*lst)–>link ;
free ( q );
}
}

Exercice de Recherche : donner la version non récursive de Supprimer( ) et la


version récursive de Detruire( ).

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 42
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

AlgoC I.IIIb Piles dynamiques

Les piles dynamiques sont des cas particuliers de listes chaînées ; le type abstrait
de données Pile dynamique peut être déclaré simplement de la manière suivante
typedef list_ptr PileDyn ;
Les prototypes des primitives de base pour la gestion d’une pile dynamique
sont :
void CreerPileDyn( PileDyn *p );
int PileVideDyn( PileDyn p );
int EmpilerDyn( PileDyn *p , typinfo e );
int DepilerDyn( PileDyn *p , typinfo *e );
void DetruirePileDyn ( PileDyn *p );
La plupart des primitives seront celles des listes chaînées ; il n ' y a pas de test
d'une pile pleine .
void CreerPileDyn ( PileDyn *p) { Creer ( p ) ; /*appel de Creer liste chaînée*/ }

int PileVideDyn (PileDyn p)


{return ( IS_EMPTY( p )) ; /*IS_EMPTY de liste chaînée */ }

int EmpilerDyn(PileDyn *p , typinfo e)


{ return ( AjoutTete ( p , e ) ) ; }
int DepilerDyn( PileDyn *p , typinfo *e )
{ PileDyn ptemp=*p ;
if ( !PileVideDyn (*p) ) {
*e = (*p)–>data ;
(void *) SupprimerRec ( p , *e) ;
return ( 1 ) ;
} else return ( 0 ) ;
}

void DetruirePileDyn ( PileDyn *p )


{ Detruire( p ) ; /* appel de Detruire liste chaînée */ }

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 43
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

Remarques :
– L'élément dépilé en cas de dépilage est stocké dans l'argument e passé à
DepilerDyn( ) .
– Même si nous n'avons pas donné de test de pile pleine , nous pouvons quand
même admettre qu'une pile est pleine lorsqu'il n ' y a plus assez d'espace en
mémoire pour une allocation .Notons également que la fonction d'allocation
malloc( ) n'accède qu'à la mémoire conventionnelle et pour accroître les
possibilités d'allocation il faut d'autres primitives d'allocation .

AlgoC I.IIIc Files dynamiques


Les files peuvent être modélisées sous forme de files dynamiques à partir des
primitives sur les listes chaînées. Dans une file classique sans fonction de gestion
des priorités, on supprime en tête et on ajoute en queue. Il serait donc intéressant
de connaître à chaque fois la TETE et la QUEUE de la file. Ces deux éléments
seront des pointeurs.

X Y Z T NULL

TETE QUEUE

Au lieu d’une liste chaînée qui a une seule entrée, on veut maintenant 2 entrées
appelées tête et queue. Nous adaptons les algorithmes afin qu’ils prennent
maintenant en compte ces deux nouveaux pointeurs . Avant tout , le type abstrait
de données file dynamique peut être déclarée par
typedef struct { list_ptr tete , queue ; } FileDyn ;
Nous donnons donc une définition adaptée de AjoutQueue( ) appelée EnfilerDyn(
) :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 44
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
void EnfilerDyn (FileDyn * f , typinfo e)
{
list_ptr tp ;
if( !(tp=(list_ptr)malloc(sizeof (list_node)))) {
printf(" LA FILE EST PLEINE ! \n") ;
exit(1) ;
}
else {
tp →data = e , tp →link = (list_ptr) NULL ;
if ( FileDynVide( f )) f →tete = f → queue = tp ;
else {
f→queue →link=tp ;
f→queue =tp ;
}
}
}
Bien entendu la file doit avoir été créée de la manière suivante :
void CreerFileDyn ( FileDyn *f ) { f–>tete = f–>queue = (list_ptr)NULL ; } on
peut également prévoir une fonction FileDynVide( ):
int FileDynVide (FileDyn f) { return ( f–>tete == (list_ptr)NULL) ; }
Exercice de Recherche : La fonction qui retire un élément de la file sera appelée
DefilerDyn( ) ; écrire le code d'une telle fonction en tenant compte de notre
structure de donnée FileDyn .

AlgoC I.IIId Les arbres


A Introduction et définitions

Un arbre est un ensemble A fini ayant un ou plusieurs éléments appelés nœuds;


ces éléments sont organisés selon un chaînage qui donne à un arbre non vide les
deux propriétés fondamentales suivantes :
1. A possède un nœud appelé la racine de A

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 45
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
2. Les nœuds restants sont partitionnés en n ensembles disjoints A1 , A2 , … ,
An où chacun de ces ensembles est un arbre. A1, A2 , … , An sont appelés les
sous arbres de la racine .

Remarques :
1 . Les sous arbres étant des ensembles disjoints, il n ' y a pas de connexion entre
eux .
2 . Un arbre est donc une structure de données récursive dans laquelle chaque
nœud de l'arbre est racine d'un sous–arbre vide ou pas .

Les arbres sont généralement étudiés avec certaines définitions que nous donnons
ci–dessous .
Degré d ' un nœud Le degré d'un nœud est le nombre de sous arbres du nœud.
C'est aussi le nombre de nœuds qui sont directement reliés au nœud considéré.
Feuille Un nœud ayant pour degré 0 est une feuille .
Parent ou père Un nœud ayant des sous arbres est le père ou le parent des racines
de ces sous arbres
Enfant ou fils Les racines des sous arbres d'un nœud sont appelées les fils
(enfants) de ce nœud
Ancêtres Les ancêtres d'un nœud sont tous les nœuds sur le chemin de la racine
à ce nœud.
Descendants Les descendants d'un nœud sont tous les nœuds de ses sous arbres
Niveau d'un nœud Le niveau d'un nœud est défini comme suit:
• La racine de l'arbre a pour niveau 1
• Tout autre nœud a pour niveau le niveau du père plus 1
Profondeur ou hauteur d'un arbre La hauteur/profondeur d'un arbre est le
maximum des niveaux des nœuds de l'arbre .

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 46
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Il y' a plusieurs types de représentation pour un arbre . On utilise généralement
les listes chaînées ; nous modéliserons ici les arbres de degré deux qui sont les
ARBRES BINAIRES (dans lesquels chaque nœud a au plus deux sous arbres) ,
les sous arbres d'un arbre binaire sont usuellement appelés fils gauche et fils droit.
Le type abstrait de donnée arbre binaire peut être déclaré comme suit :
typedef int typinfo;
typedef struct bintree_node {
typinfo data ;
struct bintree_node *left ;
struct bintree_node *rigth ;
} * bintree_ptr ;
Les prototypes des primitives fondamentales sur les arbres binaires sont déclarées
comme suit :
int CreerBinTree ( bintree_ptr * btptr) ;
void DetruireBinTree ( bintree_ptr * btptr) ;
void Inf_order ( bintree_ptr ptr ) ;
void Pre_order ( bintree_ptr ptr ) ;
void Pst_order ( bintree_ptr ptr ) ;
/* pour les arbres binaires de recherche :
void InsereBinTreeGch ( bintree_ptr * btptr , typinfo r , typinfo e ) ;
void InsereBinTreeDrt ( bintree_ptr * btptr , typinfo r , typinfo e ) ;
*/
Nous donnons ci–dessous un exemple graphique de représentation chaînée d'arbre
binaire :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 47
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

l r
Y
Z
l r

NULL NULL NULL NULL NULL NULL

NULL NULL
NULL NULL

Un arbre binaire peut servir à trier les entiers 5 , 1 , 10 , 3 , 11 , 7 , 0 , 4 , 9 par


ordre croissant comme le suggère la disposition graphique suivante :

5
10
1
11
0 3 7

4 9

B Quelques algorithmes de parcours des arbres binaires


Quand nous parcourons un arbre, nous voulons traiter chaque nœud et ses sous
arbres de la même manière. Si LVR signifie se déplacer à gauche (Left), Visiter
le nœud et se déplacer à droite (Right) ; il y a 6 manières de parcourir l’arbre LVR
, LRV , VRL , VLR, RLV, RVL. Une visite consiste par exemple à afficher la
valeur du nœud.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 48
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Exemple d’arbre binaire avec expression arithmétique

 (((A/B)C)D)
* + E =E
A/BCD + E =
ACD
* + E D
B
/ C

A B

Si on adopte la convention que nous parcourons le sous arbre gauche avant le sous
arbre droit, alors il reste trois ordres de parcours LVR , LRV et VLR appelés
respectivement ordre infixe , suffixe et préfixe; les primitives qui leur sont
associées sont : Inf_order ( ) , Pre_order ( ) et Pst_order ( ) .

Parcours d’un arbre binaire en ordre infixe (LVR)


void Inf_order (bintree_ptr ptr)
{
if (ptr) {
Inf_order (ptr →left) ;
printf ("%d\n", ptr →data) ;
Inf_order (ptr →right) ;
}
}
Parcours en ordre préfixe (VLR)
void Pre_order (bintree_ptr ptr)
{

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 49
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
if(ptr) {
printf("%d\n" , ptr →data ) ;
Pre_order ( ptr→left ) ;
Pre_order ( ptr→right ) ;
}
}
Parcours en ordre suffixe (LRV)
void Pst_order (bintree_ptr ptr)
{
if (ptr) {
Pst_order (ptr →left) ;
Pst_order (ptr →right) ;
printf (" %d\n" , ptr→data) ;
}
}
Parcours en ordre infixe itératif Nous donnons à titre de comparaison , un
algorithme itératif de parcours en ordre infixe. On considère une pile statique pl
gérée par les déclarations suivantes :
#define nbMax 100
typedef union{FAUX , VRAI}Bool;
typedef bintree_ptr typinfo;
typedef struct { int sommet ;
typinfo corps[nbMax] ;
}PILE ;
PILE pl ;
Les primitives de gestion de piles mentionnées dans la fonction Iter_Inf_order( )
ci–dessous étant les mêmes que celles étudiées au paragraphe AlgoC I.IIa), seules
les données stockées dans la pile pl changent de type . Le parcours itératif en ordre
infixe peut alors être défini comme suit :

void Iter_Inf_order (bintree_ptr node)


{

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 50
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Creer(&pl );
for ( ; ; ){
for ( ; node ; node=node → left ) Empiler(&pl , node) ;
node = Depiler (&pl) ;
if ( ! node ) break ;
printf("%d\n", node →data) ;
node=node→right ;
}
}

• Parcours d’un arbre binaire par niveau


Les arbres binaires peuvent également être parcourus par niveau. L'algorithme
suivant donne une solution , il n'est pas récursif et utilise une file statique. Notre
file fl est gérée par les déclarations suivantes :

#define TailFile 100


typedef bintree_ptr typinfo;
typedef struct{
int t , q;
typinfo corps[TailFile];

} File;
File fl;
Seuls les types de données stockées dans la file changent. Le parcours par niveau
est alors défini par :

void Level_order (bintree_ptr ptr)


{ CreerFile( &fl );
if( !ptr) return ;
Enfiler ( &fl , ptr );
for( ; ; ){
ptr =Defiler ( &fl );
if (ptr) {

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 51
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

printf("%d", ptr →data) ;


if (ptr →left ) Enfiler ( &fl , ptr→left ) ;
if (ptr→right) Enfiler ( &fl , ptr→right ) ;
}
else break ;
}
}
AlgoC I.IIIe Les graphes
A Définition
• Un graphe G est composé de deux (2) ensembles :
– un ensemble non vide de sommets et
– un ensemble éventuellement vide d'arc.
V(G) désignera l'ensemble des sommets et E(G) celui des arcs.
• On peut écrire G = ( V , E )
• Un graphe non orienté est un graphe dans lequel les paires de sommets
représentant tout arc sont non ordonnés.
Ainsi (V0 , V1) et (V1 , V0) représentent le même arc
• Dans un graphe orienté, les paires de sommets sont orientées donc
(V0 , V1)  (V1 , V0)
(V0 , V1) représente un arc dont V0 est la queue et V1 la tête
Exemple de graphe

0
0 0

1 2 1 2 1

3 3 4 5 6 2

G1 est un graphe G2 est aussi un graphe G3 est un graphe


orienté

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 52
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

E(G3) = { <0,1>, <1,0>, <1, 2> }


V(G1) = { 0, 1, 2, 3}
E(G2) = { (0,1), (0,2), (1,3), (1,4), (2,5), (2,6) }

Remarque Un graphe n'aura pas d'arc cyclique d'un sommet vers lui–même.

• Un graphe complet est un graphe ayant un nombre maximum d'arcs.


→ Pour un graphe non orienté ayant n sommets, le nombre maximum d'arcs est
le nombre de paires distinctes non ordonnées, ce nombre est n(n – 1)
2
→ Pour un graphe orienté à n sommets, le nombre maximum d'arcs est n(n – 1).
• En examinant les figures précédentes, G1 est un graphe complet.
• Si (V0 , V1) est un arc dans un graphe non orienté, alors V0 et V1 sont dits
adjacents , et l'arc (V0 , V1) est dit incident aux sommets V0 et V1.
• Un sous graphe de G est un graphe G' tel que V(G')  V(G) et E(G')  E(G).
• Un chemin du sommet Vp au sommet Vq est une succession de sommets : Vp,
Vi1, Vi2, Vi3, ....Vin – 1, Vin, Vq contenus dans G tels que deux (2) sommets
consécutifs soient adjacents (c'est à dire forment un arc).
• La longueur d'un chemin est le nombre d'arc qu'il contient.
• Un chemin peut être écrit sous forme simple à l'aide de sommets distincts à
l'exception du premier et du dernier sommet du chemin.
(0,1), (1,3), (3,2) dans G1
{ (0, 1, 3, 2) (forme simple) ou chemin simple

{{ (0, 1, 3, 2, 0) chemin simple


(0,1), (1,3), (3,2), (2,0)
• Un cycle est un chemin simple dont les extrémités sont identiques.
{
• Deux (2) sommets a et b sont connectés dans G , s'il existe un chemin dans G
de a vers b . Dans G3 , 0 et 2 sont connectés mais 2 et 0 ne sont pas connectés.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 53
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

• Un graphe non orienté est connexe si toute paire de sommets distincts est
associée à un chemin (2 sommets quelconques distincts sont connectés) .

Exemple

0
Sous– G (G n'est pas connexe)
graphe
maximal 1 2
connexe
(composant
connexe)
4 3 Composant connexe

• Un composant connexe ou simplement composant d'un graphe non orienté est


un sous graphe maximal connexe (maximal en quantité d'arc et sommets)
• Un graphe orienté est fortement connexe si deux sommets quelconques
définissent un chemin orienté dans le graphe.
Exemple : G3 n'est pas fortement connexe.
• Un composant fortement connexe est un sous graphe maximal qui est fortement
connexe .

0 0

est un composant fortement connexe de G3


1 1

G3
2

• Le degré d'un sommet est le nombre d'arcs incidents à ce sommet


dans G1 : le degré de 0 est 3 dans G2 : le degré de 4 est 1

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 54
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

• Pour un graphe orienté, le ½ degré intérieur d'un sommet est le nombre d'arcs
qui arrivent vers ce sommet , ou qui ont pour tête ce sommet.
• Le ½ degré extérieur d'un sommet est le nombre d'arcs qui partent de ce
sommet.
• Si di est le degré d'un sommet i d'un graphe G ayant n sommets et e arcs, alors
n–1
 di
i=0
e=
2
B Types abstraits de données graphe

B–1 Matrice d'adjacence

Pour un graphe à n sommets, la matrice d' adjacence est un tableau à deux


dimensions n * n noté par exemple Adj–mat.
Si l'arc ( Vi , Vj ) est dans le graphe, alors Adj_mat [i][j] = 1 , dans le
cas contraire Adj_mat [i][j] = 0 .
Adj_mat = (Adj_matij ; 1 <= i , j <= n )
• La matrice d'adjacence d'un graphe non orienté est symétrique.
Si Adj_mat [i][j] = 1 alors Adj_mat [j][i] = 1
l'exemple suivant donne les matrices d'adjacence, des graphes G1, G2, et G3
les sommets sont numérotés en gras de 0 à n .

G1 0 1 2 3 G2 0 1 2 3 4 5 6 G3 0 1 2
0 0 1 1 1 0 0 1 1 0 0 0 0 0 0 1 0
1 1 0 1 1 1 1 0 0 1 1 0 0 1 1 0 1
2 1 1 0 1 2 1 0 0 0 0 1 1 2 0 0 0
3 1 1 1 0 3 0 1 0 0 0 0 0
4 0 1 0 0 0 0 0
5 0 0 1 0 0 0 0

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 55
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
6 0 0 1 0 0 0 0

• Pour un graphe non orienté, le degré du sommet i est la somme des éléments
de la ième ligne de la matrice d'adjacence
n–1 n–1
di =  Adj_mat [i] [j] =  Adj_mat [j] [i] , i fixé
j=0 j=0

• Pour un graphe orienté, la somme des éléments de la ième ligne est le demi degré
extérieur.
La somme des éléments de la ième colonne est le demi degré intérieur

B–2 Liste d'adjacence

Maintenant on remplace les lignes de la matrice d'adjacence par une liste


chaînée. On a donc une liste chaînée pour chaque sommet.
La structure nœud pour ces listes doit contenir au moins un champ pour le
sommet et pour le lien .
Pour toute liste donnée i, les nœuds de la liste contiennent les sommets qui
sont adjacents au sommet i.
Exemple : Construction de listes d'adjacence pour G2

0
0 1 2 3 4 5 6
0 0 1 1 0 0 0 0 1 2
1 1 0 0 1 1 0 0
2 1 0 0 0 0 1 1 3 4 5 6
3 0 1 0 0 0 0 0
4 0 1 0 0 0 0 0
5 0 0 1 0 0 0 0
6 0 0 1 0 0 0 0

graph [0] : 1 2 •
0 3 4
Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule
… 0 5 6 56
1

1
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
graph [1] : : •
graph [2] : : •
graph [3] : •
graph [4] : •
graph [5] : •
graph [6] : •
Les déclarations C pour les structures listes d'adjacence seront :

#define MAX_VERTICES 50 /* nb de sommet */


typedef struct node {
int vertex ;
srtuct node * link;
} * node_pointer ;
node_pointer graph[MAX_VERTICES] ;
int n = 0 ;
C Algorithmes de Parcours

* Le parcours en profondeur d'abord : (deapth first search : dfs( ))

Pour ce parcours, on commence par un sommet de départ v, ensuite on


choisit un sommet non visité w de la liste d'adjacence de v et on procède à une
recherche en profondeur d'abord de w; la visite est ici un simple affichage.
On conserve la position courante en la plaçant dans une pile dont nous
n'avons pas besoin dans la version récursive. Finalement on aboutit à un sommet
u qui ne possède pas de sommet non visité dans sa liste d'adjacence. Alors on ôte
le sommet de la pile et on continue à traiter sa liste d'adjacence. La recherche se
termine quand la pile est vide . Nous donnons la version récursive :

void dfs(int v){


/*Recherche en profondeur d'abord d'un graphe commençant au sommet v */

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 57
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
node_pointer w ;
visited [v] = TRUE ;
printf ("%5d", v) ;
for (w = graph[v] ; w ; w = w → link)
if ( ! visited[w → vertex] ) dfs (w → vertex) ;
}

* Le parcours en largeur d'abord ( breadth first search bfs( ) )

Le parcours en largeur d'abord commence par un sommet v et le marque


comme visité. Il visite alors tous les sommets de la liste d'adjacence de v.
Ensuite on visite tous les sommets non visités qui sont adjacents au premier
sommet de la liste d'adjacence de v. Lorsque nous visitons un sommet, nous
plaçons le sommet dans une file. Quand nous avons terminé avec une liste
d'adjacence, nous supprimons un sommet de la file et continuons en examinant
chacun des sommets de la liste d'adjacence.
Les sommets vierges sont visités (affichés) et placés dans la file. Les sommets
visités sont ignorés. On termine quand la file est vide. Les files sont supposées
dynamiques pour ne pas imposer une taille et peuvent être déclarées comme vu
au paragraphe AlgoC I.IIIc . Les informations stockées dans la file sont des entiers.
Nous déclarons une variable fld de type file dynamique :
typedef struct { list_ptr tete , queue ; } FileDyn ;
FileDyn fld;
Le type list_ptr est déjà connu . Notre fonction de parcours sera donc définie par:

void bfs(int v)
{ /* Parcours en largeur d'abord d'un graphe commençant au
sommet v. Le tableau global visited doit être initialisé à 0.*/
node_pointer w ;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 58
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
CreerFileDyn( &fld ); /* initialisé la file */
printf ("%d\n", v) ;
visited [v] = TRUE ;
EnfilerDyn (&fld , v) ;
while (!FileDynVide(fld)) {
v = DefilerDyn(&fld) ;
for (w = graph[v] ; w ; w = w → link)
if (! visited [w → vertex]) {
printf ("%d\n", w → vertex) ;
EnfilerDyn (&fld , w → vertex) ;
visited [w → vertex] = TRUE;
}
}
}

Exercices de recherche : Adapter les fonctions dfs( ) et bfs( ) pour qu'elles soient
opérationnelles avec les matrices d'adjacence (et non des listes d'adjacence).
Comme application nous pouvons afficher les composantes connexes à l'aide de
dfs( ) par la fonction suivante :

void connected(void){
/* Determine les composantes connexes d'un graphe */
int i ;
for (i = 0 ; i < n ; i ++)
if (!visited [i]) {
dfs (i) ;
printf ("\n\n ") ;
}
}

AlgoC II FONCTIONS STANDARDS DE GESTION DES FICHIERS


La gestion des fichiers à l'aide de fonctions standards en C peut être effectuée à
deux niveaux .

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 59
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
AlgoC II.I Fonctions de niveau 1
Les fonctions de niveau 1 associent à un fichier un numéro (file number ,
file handle) . Ce numéro est attribué par la fonction open. Les fonctions d'accès
aux fichiers read( ) , write( ) , lseek( ) ,… traitent ce numéro en référence au
fichier. En général une fonction de niveau 1 fait appel au système d'exploitation
pour effectuer l'essentiel des tâches requises , le chargement du fichier à partir de
la mémoire de masse sur un PC sera par exemple effectué par l'intermédiaire du
système d'exploitation. Dans cette partie nous donnons une description succincte
des fonctions de niveau 1 . Le fichier d'entête à inclure est généralement io.h

Ouverture
Le prototype est :
int open (char* nomfich , int mode);
nomfich représente le nom du fichier à ouvrir.
mode indique les opérations que le programmeur désire effectuer sur le fichier.
Il y a des constantes à manipuler pour la valeur de mode.
O_APPEND si toutes les écritures doivent être effectuées à la fin du fichier.
O_CREATE s'il faut créer un fichier inexistant à l'ouverture.
S_IWRITE pour autoriser des écritures dans le fichier
S_IREAD pour autoriser la lecture du fichier.
S_I WRITE |S_IREAD pour un accès à la fois en lecture et écriture.
Les constantes qui commencent par S sont déclarées dans le fichier sys\ stat.h
O_TRUNC : nécessaire s'il faut vider le fichier à l'ouverture.
O_TEXT : pour l'ouverture d'un fichier en mode texte.
O_BINARY : pour l'ouverture d'un fichier en mode binaire
En cas d'erreur la variable errno contient le code de l'erreur.
IL suffit de déclarer "errno" par "extern int errno" . Les codes à tester sont
déclarés dans le fichier errno.h; parmis ces codes on trouve

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 60
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
ENOENT (fichier n'existe pas)
EMFIL (trop de fichiers ouverts)
EACCES (accès au fichier refusé)

Création :
Le prototype de la fonction de création de fichier est :
int creat (char *nomfich , int mode);
Si le fichier existe déjà et s'il autorise des écritures, il est vidé de son contenu.
Le mode d'accès (O_BINARY ou O_TEXT) est celui de la variable prédéfinie
"_fmode", qu'il faut modifier pour créer le fichier en mode binaire. Les modes
d'autorisation sont précisés par les combinaisons de S_I WRITE , S_I READ
(sys\stat.h).
creat( ) retourne le numéro du fichier créé ou "–1" en cas d'erreur, et errno
donne le code de l'erreur.

Lecture :
Le prototype de la fonction de lecture est
int read (int nf , void *buf , unsigned nbytes);
read( ) lit à partir de la position actuelle dans le fichier nbytes octets (caractère)
dans le fichier ou le périphérique dont le numéro est nf ( valeur de retour attribué
au fichier par open). Les caractères ou octets lus sont rangés dans "buf". La valeur
maximale de nbytes est 65534 (car 65535 est considéré comme négatif). Le
nombre d'octets ou de caractères effectivement lus est donné par la valeur de
retour de read( ). S'il y a une erreur cette valeur est –1; on teste alors errno.

Ecriture :
Le prototype de la fonction d'écriture est :
int write(int nf , void *buf , unsigned nbytes);

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 61
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
write( ) écrit nbytes caractères ou octets de buf vers le fichier référencé par nf. Le
pointeur de position dans le fichier avance de nbytes. L'écriture est effectuée à
partir de la position courante dans le fichier . La valeur de retour de write( ) est le
nombre de caractères effectivement écrits par write( ) de buf vers le fichier

Positionnement :
Le prototype est :
long lseek (int nf , long depl , int mode);
lseek( ) modifie la position du pointeur de fichier et prépare ainsi une lecture ou
écriture. depl contient la valeur du déplacement désiré ; la nouvelle position,
exprimée en nombre de caractères et sous forme d'un entier long par rapport au
début du fichier est la valeur de retour de lseek( ). La valeur de retour est
"–1L" en cas d'erreur. Dans ce cas l'erreur est codé dans "errno". Les codes
possibles sont EBADF (numéro du fichier erroné), EINVAL (argument erroné).
Notons que lseek( ) n'a de sens que si le fichier a été ouvert dans le mode binaire.
Le mode de déplacement est indiqué par mode via les constantes :
SEEK_SET (effectué à partir du début du fichier),
SEEK_CUR (déplacement à partir de la position courante),
SEEK_END (déplacement à partir de la fin du fichier)
Ces trois constantes sont déclarées dans le fichier "io.h".

Fermeture :
Le prototype de la fonction de fermeture d'un fichier est :
int close (int nf);
Une fois qu'on n'a plus besoin d'un fichier ouvert par open( ), il faut le fermer à
l'aide de la fonction close( ), car le système d'exploitation gère un nombre
maximum de fichiers simultanément ouverts.
Nous donnons trois exemples de programme de gestion de fichier au niveau 1
Exemple 1 :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 62
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
include <stdio.h>
include <io.h>
include <fcntl.h>
void main (void)
{ int nf , nb;
char buf[75];
nf=open("c:\\donnees\\fich01.dat", O_BINARY|O_RDONLY);
if(nf = = – 1){
printf("erreur …\n");
return;
}
else {
nb=read(nf , buf , 50);
nb=read(nf , buf +50, 25);
close(nf);
}
}
Le caractère \ dans une chaîne de caractère en C doit être écrit deux fois, comme
dans la chaîne de caractères "c:\\donnees\\fich01.dat". Dans le programme ci–
dessus, si le fichier fich01.dat contient au moins 75 caractères alors les deux
appels à read( ) vont retourner 50 et 25.
Exemple 2 :
/* programme de copie entre deux fichiers */
#include <fcntl.h> /* O_BINARY*/
#include <sys\stat.h> /*S_I READ */
#include <io.h> /*open, read, …*/
#include <stdio.h> /*printf,…*/
#include <stdlib.h> /*exit, ….*/
extern int errno;
void main (void){
int nf1 , nf2 , nb;
char buf [100];
if( ( nf1= open("fich1.dat" , O_BINARY | O_RDONLY ))==–1){
printf("ouverture de fich1.dat erroné : erreur (%d)\n", errno);

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 63
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
exit (1);
}
nf2= open("fich2.dat" , O_BINARY|O_WRONLY|O_TRUNC|O_CREAT ,
S_IREAD|S_IWRITE);
if(nf2==–1){
printf("erreur d'ouverture de fich2.dat : erreur (%d) \n" , errno);
exit(1);
}
while(nb=read(nf1 , buf , 100)) write(nf2 , buf , nb);
close(nf2) ; close( nf1 ) ;
}
Exemple 3 :
/*programme de mini gestion d'enregistrements d'un fichier*/
#include <io.h >
#include <fcntl.h>
#include <sys\stat.h>
struct FICHE{
char nom[11];
int age;
}; /* typedef implicite */
void main(void){
struct FICHE f[ ]=
{{"gaston",27},{"jeanne",26},{"prunelle",35} };
struct FICHE fiche;
int nf;
nf=open("fich.dat" , O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,
S_IREAD|S_IWRITE);
if(nf != –1){
for(int i=0 ; i<sizeof(f)/sizeof(struct FICHE) ; i++)
write(nf , f+i , sizeof(struct FICHE)):
close(nf);
}
nf=open("fich.dat" , O_BINARY|O_RDWR);
if(nf != –1){
lseek (nf , sizeof (struct FICHE) , SEEK_SET ) ;
read( nf , &fiche , sizeof(struct FICHE) );
fiche.age +=2;
lseek(nf , sizeof (stuct FICHE) , SEEK_SET);
write(nf , &fiche , sizeof(struct FICHE));

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 64
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
close(nf);
}
}\*main*\
AlgoCII.II Les fonctions de niveau 2
Les fonctions de niveau 2 font appel à un processus de bufferisation ou de
mémoire tampon. Elles permettent très souvent d 'éviter d'appeler le système
d'exploitation. La plupart de ses fonctions sont préfixées par "f". Avec les
fonctions de niveau 2, les fichiers sont identifiés par un pointeur sur une structure
FILE (déclarée dans stdio.h).
Ouverture
Le prototype est : FILE *fopen(char *nomfich , char *mode);
fopen( ) retourne un pointeur sur le type de donnée FILE
En cas d'erreur fopen( ) retourne "NULL". Le mode d'accès est spécifié par une
chaîne de caractère dont les lettres sont significatives :.
"r" (lecteur seule)
"w" (écriture seule)
"a" (créer un nouveau fichier ou ajouter à la fin)
"r+" (mise à jour)
"w+" (créer un nouveau et effectue lecture et écriture)
"a+" (ajouter à la fin)
"b" (fichier binaire)
"t" (fichier texte)
} suffixe

Quand un fichier est ouvert avec intention de mise à jour, une écriture ne
peut être directement suivie d'une lecture. Un "fseek( )" est nécessaire entre les
deux opérations. Après une écriture, un fseek( ) doit également être exécuté. Il
suffit d'exécuter fseek (P , 0 , SEEK_CUR).
Réouverture
Le prototype est :
FILE *freopen(char *nomfich , char *mode , FILE *fp);

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 65
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Cette fonction ferme le fichier associé à fp et ouvre à nouveau un autre fichier.
Les remarques vues ci–dessus à propos des modes d'ouverture restent encore
valables.
Fermeture
Le prototype est :
int fclose(FILE *fp);
fclose( ) retourne 0 si l'opération s'est bien déroulée, –1 en cas d'erreur.
Lecture
Le prototype de la fonction de lecture est :
int fread (void *p , int s , int n , FILE *fp);
fread( ) lit à partir de la position actuelle dans le fichier n blocs de s caractères.
Ces blocs sont amenés dans une zone de la mémoire pointé par p. Le pointeur de
fichier est incrémenté de ns caractères . fread( ) retourne le nombre de blocs
effectivement lus. En cas d'erreur il faut consulter la variable ferror.
Ecriture
Le prototype est:
int fwrite (void *p , int s , int n , FILE *fp);
fwrite( ) écrit n blocs de s caractères dans le fichier référencé par fp. Les données
à écrire étant présentes dans une zone mémoire pointée par p ; fwrite( ) retourne
le nombre de blocs effectivement écrits .
Positionnement
Le prototype est :
int fseek (FILE *fp , long pos , int mode);
fseek( ) est analogue à lseek( ).
long ftell (FILE *fp) est également le prototype d'une fonction qui retourne la
position courante exprimée en nombre d'octets à partir du début du fichier.
fseek( ) retourne 0 si l'opération s'est bien déroulée, –1 sinon; mais lseek( )
retourne la position recherchée.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 66
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Gestion d'erreur
int ferror (FILE *fp) est le prototype de la fonction qui retourne une valeur
différente de 0 si l'erreur a été détectée à la suite d'une opération sur le fichier
désigné par fp.
Détection de fin de fichier
int feof (FILE *fp) ; est le prototype de la fonction qui retourne 0 si la fin de
fichier n'a pas été détectée.
Remise à 0 de l'indicateur d'erreur.
clearerr (FILE *fp);
Obtention du numéro du fichier
int file(FILE *fp); est le prototype de la fonction qui retourne le numéro du fichier
utilisé par les fonctions de niveau 2 lorsqu'elles atteignent les fonctions de niveau
1.
Repositionnement en debut de fichier
void rewind (FILE *fp) est le prototype de la fonction de repositionnement en
début de fichier.
Mise à jour des données sur disque
void fflush (FILE *fp) est le prototype de la fonction qui force l'écriture du
tampon sur le disque.

Gestion du Tampon
Le tampon peut être géré par deux fonctions de prototype
void setbuf (FILE *fp , char *buf) et
int setvbuf(FILE *fp , char *buf , int type , unsigned taille);
Les deux fonctions provoquent l'utilisation d'un même tampon que celui
utilisé par défaut. Elle doivent être appelées immédiatement après l'ouverture.
setvbuf( ) est plus intéressante, car elle permet de modifier la taille du buffer en

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 67
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
réduisant le nombre d'accès au disque. Si le deuxième argument de setvbuf( ) est
NULL , setvbuf( ) provoque l'utilisation d'une zone allouée dynamiquement et
automatiquement par setvbuf( ).
Les valeurs possibles pour type sont :
_IOFBF : bufferisation complète (option usuelle)
_IOLBF : amène dans la mémoire tampon une ligne à la fois d'un fichier text.
_IONBF : pas de bufferisation, pas de mémoire tampon.
Remarque : Quelques noms de pointeur sur des structures FILE sont prédéfinis
et associés à des périphériques. On n'ouvre pas les fichiers correspondants; Ce
sont :
stdin : entrée standard (clavier)
stdout : sortie standard
stderr : sortie standart (erreur).
stdaux : COM1
stdprt : l'imprimante
Exemples d'application :
Exemple 1
Le programme suivant crée un fichier dont chaque enregistrement comprend le
nom d'une personne (de longueur maximale 9 caractères) et l'âge de cette
personne. La création du fichier est terminée lorsque l'utilisateur tape return ou
retour chariot en réponse à "nom ?". Il y a ensuite une réouverture du fichier et
une lecture séquentielle des données du fichier.
#include <stdio.h> /*printf( ) …*/
#include <string.h> /* gets( ) …*/
#include <stdlib.h> /* exit( ) …*/
void main (void){
FILE *fp;
struct {
char nom[10];

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 68
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
int age;
}pers;
int nb;
char buf[65];
fp=fopen("c:\\fichpers.dat" , "wb"):
if(fp==NULL){
printf("ne peut ouvrir fichpers.dat\n");
exit(1);
}
printf("nom :"); gets(buf);
while(buf[0])
{
strcpy(pers.nom , buf),
printf("AGE ?");
gets(buf);
sscanf (buf , "%d", &pers.age);
fwrite(&pers , sizeof(pers) , 1 , fp);
printf("\n NOM ?");
gets(buf);
}
fclose(fp);
if( (fp=fopen ("c:\\fichpers.dat" , "rb")) == NULL)
printf("echec d'ouverture du fichier fichpers.dat");
else{
while( nb=fread(&pers , sizeof (pers) , 1 , fp) )
printf( "%s (%d ans)\n" , pers.nom , pers.age);
fclose(fp);
}
}
Exemple 2
La lecture du fichier dans le programme ci–dessus est optimisée à l'aide du tampon
buf :
#include <stdio.h>
#include <stdlib.h>

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 69
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
#include <conio.h>
void main (void)
{ char buf[5000];
FILE *fp;
If( (fp = fopen ("c:\\fch01.dat","rb") )==NULL) {
printf("échec d'ouverture");
exit(1);
}
setvbuf (fp , buf , _IOFBF , 5000);
do {
fread(buf , 200 , 1 , fp);
getch( );
} while (!feof (fp));
fclose(fp);
}

REMARQUES
Pour une bonne méthodologie de programmation , les fonctions de niveau 1 ne
doivent pas être appelées concurremment avec celles de niveau 2 ainsi par
exemple un fichier ouvert par open( ) ne devra pas être fermé par fclose( ).

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 70
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

PARTIE III :

MINIS PROJETS EN C

Cette troisième partie de notre fascicule doit développer des minis projets
et s'enrichira au fil des années . Seuls les auditeurs ayant écrit des codes lisibles,
intéressants et mettant en œuvre les structures de données mentionnées dans le
fascicule pourront voir leurs projets figurer dans cette partie . Nous ne donnons à
la date actuelle que deux programmes de tri et un programme système, pour le
démarrage concurrentiel .

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 71
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
Les propositions des professionnels , étudiants, élèves et autres lecteurs seront
bienvenues.

/* PROGRAMME 1 :
PROGRAMME DE TRI PAR RECHERCHE ET POSITIONNEMENT
SIMULTANE DU MINIMUM ET DU MAXIMUM DANS UN TABLEAU
*/

/* PARTIE ENTETE DE BIBLIOTHEQUE : */


#include "stdio.h"
#include "process.h" /*exit( )*/
#include "conio.h" /*getch()*/

/* PARTIE DECLARATION DE CONSTANTES : */


#define tailtab 10

/* PARTIE DECLARATION DE VARIABLES GLOBALES : */


int t[tailtab] , d , f , vp , ip , vg , ig ;

/* PARTIE DECLARATION DE FONCTIONS : */


void saisir(int *t);
void afficher(int *t);
void chercherlepluspetit(int d, int f, int *vp, int *ip);
void chercherleplusgrand(int d, int f, int *vg, int *ig);
void placerlesdeux(int d, int f, int ip, int ig);
void permut (int i1, int i2);

/* CORPS DU PROGRAMME PRINCIPAL: */


void main (void)
{ clrscr( );
saisir (t);

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 72
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
printf ("Voici le tableau à trier:\n");
afficher( t );
d = 0 ; f = tailtab-1;
do{
chercherlepluspetit(d , f , &vp , &ip);
chercherleplusgrand(d , f , &vg , &ig);
placerlesdeux(d , f , ip , ig);
d++; f--;
}while (d < f);
printf ("Voici le taleau trié :\n");
afficher ( t );
}

/*PARTIE DEFINITION DES FONCTIONS DECLAREES : */

void saisir (int *tab)


{
for (int i= 0; i < tailtab; i++) {
printf("entrer la valeur de t[%d] :", i);
scanf("%d",(tab+i));
}
}

void afficher (int *tab)


{
for (int i= 0; i <= tailtab-1; i++)
printf ("\t%d\n", *(tab+i));
getch();
}

void chercherlepluspetit(int d, int f, int *vp, int * ip)


{
*vp = t[d], *ip = d;
for (int i = d; i <=f; i++)
if (t[i] < * vp) {
* vp = t[i];
*ip = i;
}
}

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 73
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

void chercherleplusgrand(int d, int f, int *vg, int * ig)


{
*vg = t[d], *ig = d;
for (int i = d; i <=f; i++)
if (t[i] > * vg) {
* vg = t[i];
*ig = i;
}
}

void placerlesdeux(int d, int f, int ip, int ig)


{
if ((ip ==d) && (ig ==f));
else
if ((ig ==d) && (ip ==f)) permut (ip, ig);
else
if ((ip == d) && (ig != f)) permut (ig, f);
else
if ((ig == d) && (ip != f))
{
permut (ig,f);
permut (ip,d);
}
else
if ((ig == f) && (ip != d)) permut (ip,d);
else
if ((ip ==f) && (ig != d))
{
permut (ip,d);
permut (ig,f);
}
else {
permut (ip,d);
permut (ig,f);
}
}

void permut (int i1 , int i2)

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 74
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
{
int tp;
tp = t[i1] , t[i1] = t[i2] , t[i2] = tp ;
}
/*FIN*/

/* PROGRAMME 2 :
UN PROGRAMME DE TRI PAR RECUPERATION DU MINIMUM DANS
UN TABLEAU DE DEPART TDEP , ET AFFECTATION DANS UN
TABLEAU FINAL TFIN, TRIE FINALEMENT EN ORDRE CROISSANT
*/

/*PARTIE ENTETE DES BIBLIOTHEQUES : */


#include "stdio.h"
#include "conio.h"

/*PARTIE DECLARATION DE CONSTANTES : */


#define n 10

/*PARTIE DECLARATION DE VARIABLES GLOBALES : */


int tdep[n] , tfin[n] , val , indic , cpt = 0;

/*PARTIE DECLARATION DE FONCTIONS : */


void saisir(int *tab);
void afficher(int *tab);
void parcourir(int *tab, int *x);

/*CORPS DU PROGRAMME PRINCIPAL : */


void main (void)
{
clrscr ( );
saisir (tdep);
while (cpt < n) {
for (int i= 0; i <= n-1; i++)

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 75
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
if (tdep [i] >= 0) {
val = tdep[i];
indic = i;
break;
}
parcourir(tdep , &val);
tfin[cpt++] = val;
}
afficher(tfin);
}

/*PARTIE DEFINITION DES FONCTIONS DECLAREES : */


void saisir(int *t)
{
for (int i = 0;i < n; i++) {
printf ("entrez la valeur de tdep[%d]:", i);
scanf ("%d", (t+i));
}
}

void afficher(int *t)


{ for (int i = 0; i <= n-1; i++)
printf ("%d\n", *(t+i));
}

void parcourir(int *t , int *x)


{
int *t2=t;
for (int i = 0; i <=n-1; i++)
{

if ((*t < *x) && (*t != -1)){


*x = *(t++);
indic = i;
}
t++;
}
t = t2;
*(t2+indic) = -1;

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 76
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
}
/*FIN*/

/* PROGRAMME 3 :
UN PROGRAMME SYSTEME DE CONTROLE DE L'ESPACE
GASPILLE EN MEMOIRE DE MASSE, SON PERFECTIONNEMENT
PEUT FAIRE L'OBJET D'UN STAGE EN INFORMATIQUE
INDUSTRIELLE OU MAINTENANCE INFORMATIQUE AU SINUS-
APLIQ
*/

/*PARTIE ENTETE DES BIBLIOTHEQUES : */


#include <c:\tcp\include\stdio.h>
#include <c:\tcp\include\conio.h>
#include <c:\tcp\include\stdlib.h>
#include <c:\tcp\include\dos.h>
#include <c:\tcp\include\string.h>
#include <c:\tcp\include\dir.h>

/*PARTIE DECLARATION DE CONSTANTES : */


#define STOMAX 10000 /*Taille espace mémoire utile pour le stockage */

/*PARTIE DECLARATION DE VARIABLES GLOBALES : */


long T_Cluster; /* Taille des clusters de votre DD */
long T_Perdus=0; /* Nombre total d'octets perdus */

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 77
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
char *S_Unite; /* Nom d'unité de mémoire de masse */
short N_Unite; /* Numéro associé à l'unité */
long MOPerdus,T_Free; /* taille totale perdue(Mo) et libre sur disque */
union REGS inregs,outregs; /* voir dos.h pour les interruptions systèmes */
struct diskfree_t Free; /*voir dos.h : pour récupération de paramètres */

/*PARTIE DECLARATION DE FONCTIONS : */


void Scan_Fich(char *chemin);

/*CORPS DU PROGRAMME PRINCIPAL : */


void main (int argc , char *argv[ ])
{
clrscr();
gotoxy(2,2);
printf("calcul de l'espace perdu sur votre disque...\n");
if((argc !=2)&&(strlen(argv[1])>1))
{
printf("Erreur: nom de commande incorrect\n");
exit(1);
}
S_Unite=(char*)malloc(100);
strcpy(S_Unite , strcat(strupr(argv[1]),":"));
if(strcmp(S_Unite,"A:")==0) N_Unite=1;
else if(strcmp( S_Unite,"B:")==0) N_Unite=2;
else if(strcmp(S_Unite,"C:")==0) N_Unite=3;
else if(strcmp(S_Unite,"D:")==0) N_Unite=4;
else
{
printf("Erreur: l'unité doit être l'une des 4 lettres A,B,C,D\n");
exit(1);
}

if(!_dos_getdiskfree(N_Unite, &Free))

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 78
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
{
T_Free = (long) Free.avail_clusters
* (long) Free.bytes_per_sector
* (long) Free.sectors_per_cluster;
printf(" Taille libre en octet sur votre disque : %u octets \n",
T_Free);
}
else exit(1);
inregs.h.ah=0x1C;
inregs.h.dl=N_Unite;
intdos(&inregs,&outregs);
T_Cluster=outregs.h.al*outregs.x.cx;
printf("Unite %s , cluster de %d octets\n",S_Unite,T_Cluster);
delay(5000);
printf("scan du disque en cours : ........\n");
Scan_Fich(S_Unite);
printf("\n");
printf("Au total vous perdez %ld octets\n" , T_Perdus);
MOPerdus=(T_Perdus/1048576);
if(MOPerdus>1){ printf("ou %d Mega Octets(Mo) \n",MOPerdus);
printf("soit %f%% de votre espace libre de %f Mo\n",
(T_Perdus/T_Free)*100 , (T_Free/1048576) );
} else printf("MERCI\n");
}

/*PARTIE DEFINITION DES FONCTIONS DECLAREES : */


void Scan_Fich(char *chemin)
{
struct ffblk fl;
int done,x;
x=strlen(chemin);
if(chemin[x-1]!='\\')
strcat(chemin,"\\");
done=findfirst(strcat(chemin,"*.*"),&fl,0x37);

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 79
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage
while(!done)
{
if(((fl.ff_attrib & 0x10)==0x10)&&(fl.ff_name[0]!='.'))
{
Scan_Fich(strcat(chemin,fl.ff_name));
}
gotoxy(1,8);
clreol();
gotoxy(1,8);
printf(" Pertes dues au fichier: %s ",strcat(chemin,fl.ff_name));
gotoxy(4,8);
clreol();
delay(20);

T_Perdus+=(T_Cluster - (fl.ff_fsize %T_Cluster));


done=findnext(&fl);
clrscr();
}
return;
}
/*FIN*/

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 80
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

Conclusion

Au cours de ce fascicule qui est un support des cours que je dispense depuis
quelques années aux auditeurs des sections informatiques, nous avons eu
l'occasion de découvrir le Langage C , sa puissance et ses finesses ; ce fascicule
étant encore en phase de perfectionnement, l'auteur ne pourrait faire autrement
que conseiller le lecteur d'être critique envers son contenu, car il a été rédigé en
tenant compte des besoins pressants des auditeurs. Il doit être accompagné de
certains documents sur le Langage C et les Algorithmes. Vous remarquerez par
exemple que les fonctions d'entrée et/ou sortie des bibliothèques C ne sont pas
décrites dans ce fascicule. En effet cette tâche est toujours accomplie oralement
pendant mes cours . Les Algorithmes également sont sélectionnés pour les
auditeurs , vous pourrez par exemple consulter d'autres ouvrages pour un
complément sur les Algorithmes d'équilibre d'arbres et d'autres structures de
données . Ce support est néanmoins très satisfaisant pour les auditeurs ayant suivi
les cours oraux, et il est destiné à évoluer pour ses prochaines éditions.

Le lecteur en possession d'un original de l' EDITION PI–SINUS a un pied au


SINUS-APLIQ en ce sens qu'il pourra profiter de certaines prestations :
❖ Obtention d'un stage en Informatique au SINUS-APLIQ
❖ Suivi de son stage au SINUS-APLIQ
❖ Travaux Pratiques sur C/C++ , Access , …
Sans compter d'autres prestations pratiques et intellectuelles sur mesures.

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 81
Algorithmes avancés en C Edition Stage et Concours / SINUS-APLIQ
Par K. Constant KOUAKOU deuxième tirage

Tous Droits de Reproduction Réservés au SINUS–APLIQ . Les élèves, étudiants, et autres


lecteurs en possession d'une copie de ce fascicule peuvent le faire certifier auprès de l'auteur ou du
SINUS–APLIQ afin de pouvoir profiter des prestations ci-dessus mentionnées.
Abidjan, Le 21 Juillet 1999
Original livré à :
Par : Le :

Décrochez un stage , un suivi de stage , et autres prestation; grâce à l'original de ce fascicule


… 82

Vous aimerez peut-être aussi