You are on page 1of 126

I.U.T.

de Marne-La-Valle

Introduction l'informatique et programmation en langage C


(DUT Gnie Thermique et Energie) Jean Fruitet
Jean.Fruitet@univ-mlv.fr

1999

Introduction la programmation

I.U.T. de Marne-La-Valle

Introduction l'informatique et programmation en langage C


(DUT Gnie Thermique et Energie)
Jean Fruitet
Jean.Fruitet@univ-mlv.fr

Avertissement Caractrisation dun problme informatique Introduction linformatique Le codage binaire Notion dalgorithme et de machine accs direct Langage C Processus itratifs Fonctions et sous-programmes Notion de complexit Des donnes aux structures de donnes : tableaux, calcul matriciel Calcul numrique : fonctions numriques, rsolution d'quation, intgration Structures de donnes : ensembles, listes, piles, files, hachage, arbres, graphes Algorithmes de tri Bibliographie Table des matires

3 3 5 7 14 19 43 44 48 50 61 76 112 123 122

Jean Fruitet - IUT de Marne La Valle - 2

Introduction la programmation

Avertissement Ce cours sadresse aux tudiants de premire anne de DUT de Gnie Thermique et Energie (GTE). Il leur est prsent en quelques dizaines dheures une trentaine les rudiments de la programmation numrique et des notions dalgorithmique. Ces tudiants n'tant pas destins une carrire dinformaticien professionnel, je naborde pas lalgorithmique dans tous ses raffinements. En particulier les notions pourtant fondamentales de preuve de programme et danalyse de complexit ne sont pas voques. Ce cours est divis en quatre parties : - notion d'informatique et de codage ; - structure d'un ordinateur : la machine accs direct (MAD / RAM) ; - langage de programmation : le langage C ; - algorithmique numrique et structures de donnes. Aprs quelques notions de thorie de l'information et de codage (codage binaire, reprsentation des entiers et des flottants) j'introduis la programmation de fonctions numriques sur ordinateur PC sous MS-DOS puis l'utilisation de quelques structures de donnes fondamentales (tableaux, piles, files, arbres, graphes) et les principaux algorithmes de tri. Ce cours ne fait donc aucune place la technologie des ordinateurs, leur architecture, systme d'exploitation et de fichiers. Il n'est pas non plus question d'apprentissage de logiciels bureautiques (traitement de texte ou de tableur). Ce n'est pas que ces connaissances ne soient pas ncessaires aux techniciens, mais je laisse d'autres enseignants le soin d'y contribuer. Sagissant de la syntaxe dun langage de programmation, jintroduis le langage RAM, pour passer rapidement au langage C. J'insiste beaucoup dans ce cours sur la ncessit d'une programmation structure descendante. Cette dmarche est recommande depuis des lustres par tous les spcialistes. Malheureusement l'exprience montre que livr lui-mme le programmeur moyen se permet des liberts qui rendent rapidement ses programmes illisibles et inutilisables. Mais ce ne sera pas faute d'avoir t prvenu... Caractrisation dun problme informatique L'art de programmer, c'est l'art de faire rsoudre des problmes par des machines. Il sagit bien dun art, au sens de lartisan, qui passe par une longue priode dapprentissage et dimitation. Dans cet exercice certains individus ont des dispositions naturelles ; pour les autres un apprentissage rigoureux fournit les rudiments dune mthode. Le reste est affaire de travail et dinvestissement personnels. Un ordinateur est dnu dintelligence ; il ne peut donc rsoudre que les problmes pour lesquels existe une mthode de rsolution algorithmique, cest--dire une recette dterministe. De plus, mme si la recette existe en thorie pour rsoudre tel problme, encore faut-il que lnonc du problme lespace des paramtres et lensemble des solutions soient de dimension finie, en raison de la limitation en taille de la mmoire des machines. Enfin, condition ultime, la mise en oeuvre dun algorithme doit avoir une dure finie. Un problme dont la solution ncessite de disposer dun temps infini nest pas considr comme rsoluble par ordinateur. Ces trivialits vont donc limiter nos ambitions de programmeur une classe de problmes assez restreinte, dautant que ne nous disposons pas de puissantes machines de calcul.
Jean Fruitet - IUT de Marne La Valle - 3

Introduction la programmation

2.1. Le traitement de linformation Linformatique est la science du traitement de linformation. Une information est un lment de connaissance susceptible dtre cod, transmis et trait de manire automatique. Le codage numrique en nombres binaires tant adapt la conception de machines lectroniques, une partie essentielle du cours dinformatique porte sur la reprsentation des nombres et la logique (algbre de Boole) binaires. Je considrerai comme acquises les notions dopration lmentaire (addition, soustraction, multiplication et division relle et euclidienne) sur les ensembles de nombres naturels, relatifs, rationnels, rels et complexes, qui ne seront pas redfinies, non plus que les oprations ensemblistes union, intersection, complmentation, ni les notions de relation binaire, relation dquivalence et relation dordre partiel ou total. Concernant les notions de constante numrique, de variable, dinstruction daffectation, de test, de boucle, qui sont au centre des techniques de programmation, elles seront redfinies ou prcises selon les besoins. 2.2. Quelques exemples de problmes Lordinateur fonctionne en binaire, mais il peut rsoudre des problmes autres que numriques. Et bien que le calculateur lectronique soit linstrument privilgi de lingnieur, ce nest pas en programmant des problmes numriques quon apprend le plus efficacement programmer. Pourtant il est de tradition dans les sections techniques et scientifiques de commencer par des exercices numriques : - Rsoudre une quation du second degr coefficients rels dans le corps de nombres complexes. - Programmer la division euclidienne de deux entiers en nemployant que des soustractions. - Trouver le plus grand diviseur commun de deux nombres naturels (PGDC). - Enumrer les n premiers nombres premiers. - Tester la conjecture polonaise. - Calculer le nime lment de la suite de Fibonacci. - Calculer le minimum, le maximum, la moyenne et lcart-type dune distribution numrique. - Calculer les zros dun polynome, tracer graphiquement le graphe d'une fonction numrique - inverser une matrice. Dautres problmes qui ne sont pas strictement numriques sont pourtant tout aussi instructifs pour lart de la programmation. Ils seront soit traits soit voqus : - Trouver un mot dans un dictionnaire. - Construire un arbre hirarchique - Ordonner une liste de mots. - Fusionner deux listes de mots dj ordonns. - Enumrer les parcours dun graphe et trouver le plus court chemin entre deux sommets. - Filtrer une image, etc. Dmarche Partant dun problme lmentaire nous montrerons comment le reformuler en des termes susceptibles dtre traits par un ordinateur idal. Puis nous coderons ces algorithmes en langage C. Nous encourageons le lecteur implanter ses propres solutions, les modifier, ventuellement les amliorer ou les rutiliser pour dautres applications.
Jean Fruitet - IUT de Marne La Valle - 4

Introduction la programmation

Tous les exemples fournis en C ont t tests sur compilateur Turbo C sur PC et Think C sur Macintosh. Je remercie par avance celles et ceux qui voudront bien me transmettre remarques et suggestions. Introduction linformatique L'Informatique est la science du traitement automatique de l'information. La notion d'information est assez gnrale. Pour l'informatique elle prend un sens particulier : Une information est un lment ou un systme de connaissance pouvant tre transmis au moyen d'un support et d'un codage appropri et pouvant tre compris. Par exemple des hiroglyphes (codage) sur un papyrus gyptien (support) constituent une information sur la socit gyptienne antique ds qu'on a t en mesure de les lire et d'en comprendre le sens (Champollion au XIXme sicle). Une information est une fonction du temps, puisque le contenu d'un message est sujet changer au cours du temps. L'information "La mer est 'calme' dans le Golfe de Gascogne" est particulirement prissable... Quand le vent se lve et que la houle se forme, la mer devient 'agite'. L'tat de la mer est une information qui peut prendre des valeurs diffrentes, au cours du temps. Langage La plupart des informations que les Humains changent sont supportes par un langage, c'est-dire des groupes de sons (les mots), qu'il faut assembler "d'une certaine manire" (grammaire) pour que les phrases aient un sens... Avec l'invention de l'criture, ces mots ont eu une transcription (recodage) sous forme de symboles graphiques (des formes) dessins ou imprims. Le concept de mot est fondamental en informatique, de mme que celui de langage. Un langage est un ensemble de mots construits avec les lettres choisies dans un alphabet. Les mots sont assembls en phrases selon des rgles de grammaire prcises qui dfinissent la syntaxe du langage. Le sens attach ces phrases, c'est--dire leur signification, constitue la smantique. L'essentiel de ce cours va consister expliquer comment sont commandes les machines que nous nommons ordinateurs, capables d'excuter des tches complexes de traitement de l'information. Traitement de l'information Le traitement de l'information consiste en une suite d'oprations transformant une reprsentation de cette information en une autre reprsentation plus facile manipuler ou interprter. Exemples : "3*2" remplac par "6" "Mille neuf cent quatre vingt treize" est remplac par "1993" "La somme des carrs des cts de l'angle droit d'un triangle rectangle est gale au carr de l'hypotnuse" est remplac par "Thorme de Pythagore" "Championne olympique 1992 et 1996 du 400 mtres fminin" est remplac par "Marie-Jos Prec". Dans une entreprise, traiter l'information peut consister tablir la paye, faire la facturation, grer le stock, dresser un bilan. Dans un atelier, diriger un robot. En mtorologie, reconnatre un cyclone sur une photo satellite...
Jean Fruitet - IUT de Marne La Valle - 5

Introduction la programmation

Ordinateur Un ordinateur est une machine qui permet d'effectuer des traitements sur des donnes l'aide de programmes. Les donnes (les paramtres du problme, par exemple les notes des tudiants du cours d'informatique) ainsi que le programme (par exemple le calcul de la moyenne des notes) sont fournis la machine par l'utilisateur au moyen de dispositifs de saisie (le clavier). Le rsultat du traitement est recueilli la sortie de l'ordinateur (l'cran, limprimante) sous forme de texte. Un peu d'histoire C'est en 1945 que le principe des ordinateurs a t invent. Mais on peut faire remonter ses origines au boulier et aux premires machines calculer mcaniques. Blaise Pascal (1623-1662) inventa l'ge de 18 ans une machine base de roues dentes et d'engrenages qui ralise d'elle-mme les additions et les soustractions. Il suffit d'indiquer les chiffres et l'opration faire. Au XIXme sicle l'anglais Babbage conoit deux grandes machines dont le principe tait correct, mais qui ne purent tre ralises en raison de difficults techniques et financires. Il tait sans doute trop tt. Ce n'est qu'au XXme sicle que sous la pression du dveloppement conomique et des besoins militaires (Deuxime guerre mondiale) des scientifiques et des ingnieurs s'attelrent la construction de gigantesques machines calculer. La plus fameuse de ces machines fut la "Harvard Mark 1" qui mesurait 16 mtres de long, pesait 5 tonnes et comprenait 800 000 lments, et pourtant n'avait pas plus de puissance qu'une simple calculette de poche actuelle ! La vritable rvolution pour les machines calculer viendra des progrs de l'lectronique et de la logique mathmatique. Le premier calculateur lectronique, l'ENIAC, destin calculer la trajectoire de projectiles pour l'arme amricaine, fut construit partir de 1943. Il pesait 30 tonnes, comportait 17 468 tubes vide et additionnait 5000 nombres en une seconde. Mais on ne peut considrer cette machine comme un ordinateur, car il n'tait pas vritablement automatique et n'utilisait pas de programme interne.1 Sur le plan technique les progrs dcisifs seront raliss dans les annes 1950 avec l'invention en 1947 du transistor (qui donne son nom aux postes de radio portables). Les transistors sont des composants lectroniques qui remplace partout les lampes vides ; rassembls par dizaines puis centaines de milliers sur des circuits intgrs ils permettent de raliser des puces lectroniques qui envahissent les automates (lave linge, magntoscopes, circuits d'allumage de voiture, calculettes...) et les ordinateurs. Sur le plan conceptuel, c'est aux anglais George Boole (1815-1864), inventeur de l'algbre binaire, l'algbre de la logique, et Alan Turing (1912-1954) et aux amricains d'origine europenne John Von Neumann (1903-1957) et Norbert Wiener (1894-164) que nous devons l'avance dcisive qui mne des calculateurs aux ordinateurs. Leurs travaux aboutissent la construction du premier ordinateur en 1948 Manchester, en Grande-Bretagne, le "Manchester Mark 1". Ce qui caractrise un ordinateur La machine conue par John Von Neumann comporte trois innovations majeures : - elle a une mmoire importante, dans laquelle sont archives les donnes et le programme. - elle a un programme enregistr dans la mmoire, qui dcrit l'ensemble des instructions raliser.

1 Philippe BRETON "Une histoire de l'Informatique" - Collection Points Sciences - Editions La Dcouverte, Le Seuil

1990. Jean Fruitet - IUT de Marne La Valle - 6

Introduction la programmation

- elle a une unit centrale de commande interne qui organise le travail en appliquant les instructions du programme et dirige les changes de donnes avec l'extrieur de la machine. Matriel et logiciel Un ordinateur est constitu de composants matriels (hardware ) et de composants logiciels (software ). Les composants matriels sont essentiellement des cartes lectroniques, des circuits intgrs, des cbles lectriques, des supports de mmoires de masse (disques durs) et des dispositifs d'entre/sortie (priphriques : clavier, cran, imprimante). Les logiciels, qui pilotent le fonctionnement des composant matriels, sont des programmes stocks sous forme code dans la mmoire de l'ordinateur. Pour tre interprts par l'unit centrale ces programmes doivent tre traduits dans le langage des machines, le langage binaire. Le codage binaire Toute l'information qui transite dans un ordinateur est code avec des mots forms seulement de deux symboles (ou de deux 'tats') nots 0 et 1. Cela tient la nature des composants lectriques et magntiques utiliss pour coder l'information. Dans les mmoires d'ordinateur, chaque unit lmentaire d'information peut tre reprsente par un minuscule aimant. Chaque aimant est orient soit dans un sens (tat 0), soit dans le sens oppos (tat 1)... C'est le mme principe qui est appliqu aux changes de donnes. Pour transmettre un 1, il faut appliquer sur un conducteur lectrique une diffrence de potentiel suprieure quelques volts pendant une priode "assez" longue, de l'ordre de la micro seconde (1/1 000 000 me de seconde). Pour transmettre un 0, il faut maintenir une diffrence de potentiel infrieure 1 volt pendant la mme dure. Par exemple pour coder le nombre 13 en binaire, il faut les quatre chiffres binaires 1101. En effet 13 peut tre dcompos comme une somme de puissances de 2 13 = 8 + 4 + 1 = 1 * 8 + 1 * 4 + 0 * 2 + 1 * 1 en dcimal = 1 * 23 + 1 * 22 + 0 * 21 + 1 * 20 on ne conserve que les coefficients = 1 1 0 1 en binaire Reprsentation des informations en binaire Pour coder de l'information , que ce soient des nombres, (PI=3,141592...), du texte (ce cours), des schmas, des images, des sons, des relations ("Pierre est le pre de Jacques et le frre de Marie"), les circuits lectroniques d'un ordinateur ne peuvent utiliser que des mots en binaire. Montrons d'abord comment il est possible de coder n'importe quel nombre entier naturel IN={0, 1, 2, 3, ... ,1 000, ..., 1 000 000, ...} en binaire. Puis nous en ferons autant pour les lettres et les mots de la langue franaise. Enfin il faudra montrer que les images, les sons et les relations aussi peuvent se coder en binaire. Passer du dcimal au binaire Il suffit de dcomposer un nombre dcimal en une somme de puissances de 2. On peut par exemple commencer par crire la table des premires puissances de 2 : 20 = 1 21 = 2 22 = 2x2 = 4 23 = 2x2x2 = 8 24 = 25 = 2x...x2 = 26 = 27 = 28 = 29 = 210 = 211 = Exercice 1 : Montrer que le nombre 256 est une puissance de 2. Exercice 2 : Montrer que le nombre 131 est une somme de puissances de 2
Jean Fruitet - IUT de Marne La Valle - 7

Introduction la programmation

Exercice 3 : Donner la reprsentation binaire des 10 premiers nombres entiers : 0 = 0x20 -> 0; 1=1x20 -> 1 ; 2=1x21 -> 10 3 = 1x2 + 1x1 = 1x21 + 1x20 -> 11 4 = 1x4+ 0x2 + 0x1 = 1x22 + 0x21 + 0x20-> 100 5 = 1x4 + 0x2 + 1x1 = 6= 7= 8= 9= 10 = Passer du binaire au dcimal Le codage binaire a un inconvnient majeur pour l'tre humain, son manque de lisibilit... Quelle est la reprsentation dcimale du nombre dont la reprsentation binaire est : 1001 1110 ? Rponse : 1x27+ 0x26 + 0x25 +1x24 + 1x23 + 1x22 + 1x21 + 0x20 = 1x128 + 0x64 + 0x32 +1x16 + 1x8 + 1x4 + 1x2 + 0x1 = 158 Exercice 4 : Mme question pour 1111 1111 Exercice 5 : Combien de chiffres binaires faut-il pour reprsenter le nombre dcimal 10000 ? Oprations usuelles en binaire Les deux oprations binaires de base sont - l'addition - la multiplication Table d'addition binaire 0+0=0 0+1=1 1+0=1 1 + 1 = 0 avec une retenue de 1 Table de multiplication binaire 0x0=0 0x1=0 1x0=0 1x1=1 Exercice 6 : En utilisant la table d'addition binaire calculez en binaire les nombres suivants : 1001 + 10100 1111 + 1 1010 + 111 1111 1111 + 1111 1111 Exercice 7 : En utilisant la table de multiplication et d'addition binaires calculez en binaire les nombres suivants : 1001 x 1 1111 x 10 100 x 101 1111 x 1111 Oprations logiques En logique binaire une variable logique (boolenne) est VRAI (TRUE = 1) ou FAUSSE (FALSE = 0). Une expression logique est constitue de plusieurs variables logiques combines par des connecteurs (oprateurs) logiques :
Jean Fruitet - IUT de Marne La Valle - 8

Introduction la programmation

Les oprateurs logiques lmentaires sont : - NON [NOT] - ET [AND] - OU [OR] - OU EXCLUSIF [XOR] Table de vrit du ET 0 ET 0 = 0 0 ET 1 = 0 1 ET 0 = 0 1 ET 1 = 1 Table de vrit du OU Table de vrit du OU EXCLUSIF [XOR] 0 OU 0 = 0 0 OU 1 = 1 0 XOR 0 = 0 1 OU 0 = 1 0 XOR 1 = 1 1 OU 1 = 1 1 XOR 0 = 1 1 XOR 1 = 0 Exercice 8 : Donner la valeur de vrit {VRAI ou FAUX} des assertions suivantes : A : 102 est un nombre pair B : 11 est un multiple de 3 C : 102 est un nombre pair ET 102 est divisible par 3 D : 11 est multiple de 3 ET 102 est divisible par 3 E : 108 est multiple de 9 OU 11 est divisible par 3 Table de vrit du NON NON 0 = 1 NON 1 = 0 Les nombres entiers et les nombres rels dcimaux L'ensemble des entiers naturels : IN = {0,1,2..,100,101,...1000,...} - IN est ordonn ; il a un plus petit lment 0 ; - Il n'y a pas de plus grand lment : tout lment a un successeur L'ensemble des entiers relatifs : Z = Z+ U ZZ = {...,-1000,...,-100,..., -3,-2,-1, 0, 1,2..,100,101,...1000,...} - Z est ordonn - il n'y a ni plus grand ni plus petit lment : tout lment de Z a un prdcesseur et un successeur. Oprations sur les entiers Oprateurs unaires : - (moins) : oppos succ : successeur renvoie le nombre suivant dans l'ordre des entiers pred : prdcesseur renvoie le nombre prcdent maxint : renvoie le plus grand entier reprsent sur la machine Oprateurs binaires : + - * DIV MOD / Oprateurs de comparaison : = < <=> >= Axiomes : associativit de + et *; distributivit de * sur +; relation d'ordre
Jean Fruitet - IUT de Marne La Valle - 9

Introduction la programmation

Implmentation des entiers non signs En raison des limitations d'espace mmoire, on ne peut reprsenter que des intervalles de nombres. Deux difficults rsoudre : choix des intervalles et reprsentation des nombres ngatifs Implantation courante sur 2 octets: l'intervalle slectionn est [0..65535] Il s'agit de gnrer une reprsentation de ce nombre en base 2 occupant au plus deux octets, soit 16 bits. Exemple pour n = 54710 On dcompose 547 en puissances successives de 2 : 54710 = 512 + 32 + 2 + 1 = 1*29 +1*25 +1*21 +1*20 et on ne code que les coefficients de la dcomposition, la reprsentation binaire de n est Bin(n) = 0000 0010 0010 0011 Le plus grand nombre entier non sign reprsentable est donc : 1111 1111 1111 1111 = 1*215 +1*214 +1*213 +1*211 +1*210 +1*29 +1*28 + 1*27 +1*26 +1*25 +1*24 +1*23 +1*22 +1*21 +1*20 = 1*216 - 1 La reprsentation dcimale de ce nombre est donc Dec(n) = 65 536 - 1 = 65 53510 Implmentation des entiers signs L'intervalle slectionn est [-32768.. +32767] Soit un nombre n de Z. Il s'agit de gnrer une reprsentation de ce nombre en base 2 occupant au plus deux octets, soit 16 bits. Si le nombre est positif et infrieur 215 (32 768) on le reprsente comme un entier non sign. Si le nombre est ngatif et suprieur -32768, le problme est de reprsenter le signe et de pouvoir passer d'un nombre son oppos de faon simple. Une mthode trs rpandue est la mthode du complment 2. On travaille MODULO 216 On reprsente Bin(216 + n) = 65 536 - 547 = 64 989 = 1111 1101 1101 1101 Une vrification de l'expression calcule consiste effectuer une somme bit bit de 547 et de -547 Si la reprsentation est correcte on doit trouver 0 : 0000 0010 0010 0011 + 1111 1101 1101 1101 _____________________________ Report 0000 0000 0000 0000 Le report (ou retenue) n'est bien sr pas reprsent. Donc un nombre entier sign reprsent sur 16 bits dont le bit de poids fort est 1 doit tre considr comme un nombre NEGATIF : sa valeur est -(216 - Dec(n2)) Algorithme de conversion d'un nombre en binaire complment 2 sur un octet : Trouver l'oppos d'un nombre en complment 2 : Soit n = 0000 0101 = 510 Son oppos est -5 obtenu en inversant tous les 1 en 0 et tous les 0 en 1 et en ajoutant 1: 0000 0101 --> 1111 1010 + 1 = 1111 1011 = -5

Jean Fruitet - IUT de Marne La Valle - 10

Introduction la programmation

Vrification : 5 + (-5) = 0 0000 0101 +1111 1011 ---------0000 0000 report ignor Exercice : Trouver les reprsentations binaires en complment deux sur deux octets des nombres suivants : -1; -2; 31000; -31000 -33000 est-il reprsentable ? Les nombres rels. L'ensemble IR ne peut pas tre reprsent de faon complte en machine. On retrouve les mmes difficults pour reprsenter les rels que pour reprsenter les entiers : l'ordinateur n'a pas une mmoire infinie. On reprsente donc un sous-ensemble fini de IR. Tout traitement (opration, reprsentation) peut tre entache derreur. Un calcul mathmatique permet destimer limportance de cette erreur. Oprations sur les rels : Opration unaire : - (oppos) Oprations binaires :+ - * / Comparaisons = < > <= >= Fonctions relles : cos sin log puiss sqrt Axiomes Corps ordonn x * (y + z) = x * y + x * z: distributivit On retrouve certains axiomes des entiers plus ceux des rationnels (inverse) plus quelques caractristiques intressantes (densit) La notation scientifique normalise On appelle notation normalise d'un rel celle o le premier chiffre significatif est plac immdiatement aprs la virgule (ou le point dcimal). Exemple : 1989 = 0.1989 E4 Pour stocker ce nombre en mmoire, il suffit de stocker l'exposant 4 et la partie dcimale appele mantisse 1989 Exemple : crire PI en notation normalise = 3.1415926535... = 0.31415926535 E1 Reprsentation des nombres rels en binaire Tout nombre rel peut tre reprsent dans une base quelconque : a=M*Be avec B : base ; e : exposant ; M : mantisse (qui peut tre une suite infinie de chiffres...) En notation normalise on a les conditions : (1/B) <= | M | < 1 ou bien M=0 Les rels sont reprsents en machine selon un standard dfini par l' IEEE Un rel est dcompos en signe +s exposant caractristique E partie dcimale mantisse F s . 2E-127 . 1, F x = (-1) En gnral on reprsente un rel sur 4 octets (32 bits) le bit 0 de poids fort (le plus gauche) est le signe s, soit 0 (positif) ou 1 (ngatif)
Jean Fruitet - IUT de Marne La Valle - 11

Introduction la programmation

les bits 1 8 sont la caractristique E qui est reprsente par un entier binaire sur 8 bits dcal de la valeur 127 les bits 9 31 sont pour exprimer la mantisse F en binaire, Exemple : 0.8 sera cod : s=0 E=126 F . ........ ....................... 0 01111110 10011001100110011001100 codage binaire . ........ ....................... 0 1 8 9 31 n de bit Dcomposition d'un nombre rel dcimal en binaire Soit le nombre 0.8 convertir en binaire. On constate dabord que son signe est positif, donc S=0. On cherche ensuite le dcomposer en une somme de puissances de 2. 0.8 = 20 x 0.8 0.8 x 2 = 1.6 donc 0.8 = 1.6 / 2 = 2-1 x 1.6 = 2-1 x 1 + 2-1 x 0.6 0.6 x 2 = 1.2 donc 0.8 = 2-1 x 1 + 2-2 x 1.2 0.2 x 2 = 0.4 donc 0.8 = 2-1 x 1 + 2-2 x 1 + 2-3 x 0.4 0.4 x 2 = 0.8 donc 0.8 = 2-1 x 1 + 2-2 x 1 + 2-3 x 0 + 2-4 x 0.8 0.8 x 2 = 1.6 donc ... on retrouve une expression dj rencontre qui va se rpter infiniment 0.8 = (-1)0 x 1. 10011001100110011.... x 2-1 Finalement on ne code que les chiffres binaires de la dcomposition : signe = 0 car 0.8 est positif E = 126 car 126-127 = -1 F = 10011001100110011.... Exemple 2 : 0.75 en base 2 donnera 0.75 x 2 = 1.5 donc 0.75 = 2-1 x 1.5 0.5 x 2 = 1.0 donc 0.75 = 2-1 x 1 + 2-2 x 1.0 0.75 = (-1) x 2 126-127 x 1.10000000000000000000000 Exercice : Montrer que le nombre dcimal 0.1 na pas de reprsentation finie en binaire. Rels en double prcision En augmentant le nombre d'octets attribus la reprsentation des rels, on amliore la prcision en consacrant plus de bits la mantisse, mais on n'augmente pas l'intervalle des rels reprsents car on conserve le mme nombre de bits pour la caractristique. Les nombres rationnels La reprsentation des rels a de gros dfauts ds qu'il s'agit par exemple de comparer des nombres manifestement gaux mais dont on ignore si l'ordinateur les identifiera. x = 0.000 020 et y = 0.000 019 999...; u = 20 ; v = 19 999... Comment est reprsent z = (x/y) et r = (u/v) ? Sont-ils perus comme gaux ? Il peut tre avantageux de dfinir directement un type de donnes NOMBRE RATIONNEL qui reprsentera de faon exacte tous les nombres quivalents une fraction entire...

Jean Fruitet - IUT de Marne La Valle - 12

Introduction la programmation

Codage des informations non numriques Textes Les textes peuvent tre reprsents en binaire condition d'associer chaque lettre de l'alphabet une reprsentation numrique, par exemple son rang dans l'ordre alphabtique : A serait cod1 ; B, de rang 2 serait cod 10 en binaire; C cod 11, etc. Mais ce codage est insuffisant car il faut aussi pouvoir coder les signes de ponctuation . , ; ? ! , distinguer les minuscules des MAJUSCULES, les caractres accentus, etc. La table ASCII (American Standard Code for Interexchange Information) propose un codage de 128 caractres diffrents sur 7 bits. Dans la table ASCII la lettre A est cod 65 B est cod 66 C est cod 67 ... Z est cod 90 a est cod 97 b est cod 98 ... 0 est cod 48 1 est cod 49 ... 9 est cod 57 ... Les caractres accentus des langues europennes ont ncessit l'ajout d'un huitime bit de codage, d'o la table ASCII tendue avec 256 caractres. Mais ce n'tait pas suffisant pour certaines langues comme le japonais ; un codage sur 16 bits est en cours de normalisation sous le nom d'UNICODE. Il supplantera dans l'avenir le code ASCII. Les images Le codage des images en noir et blanc ne prsente pas 0001 1100 0011 1110 de difficult. Il suffit d'observer la loupe une 0110 1011 0011 1110 photographie de journal pour en comprendre le principe. Si 0011 1110 0001 1100 une image est superpose une grille trs fine, chaque 0000 1000 carr de la grille color en NOIR par l'image est cod 1, 0001 1100 0111 1110 chaque carr BLANC est cod 0. Il suffit donc de coder 1111 1111 1111 1101 toute l'image sous forme dun tableau deux dimensions de 1111 1111 0 et de 1. Le codage des sons est plus compliqu. Il faut d'abord transformer chaque son en un signal lectrique continu (c'est le rle du microphone), puis chantillonner ce signal lectrique (discrtiser) et le numriser. On dispose alors d'un srie de nombres qui reprsentent le signal sonore... Les relations Le cours de bases de donnes (seconde anne GTE) introduit le modle entit/association qui permet de reprsenter les informations "Marie est la mre de Pierre et de Franoise" ; "Pierre et Franoise ont achet ensemble le vhicule Renault Clio 1234 ZA 75", "Marie a une Citron ZX" ; "la Twingo 3987 TT 51 n'est personne", etc., sous forme de tables relationnelles.
Image 12 lignes de 8 colonnes Recodage binaire

PERSONNE

n:m

VEHICULE

"possde"
1:n

"est la mre de"


PERSONNE Mre Nom Marie Pierre Franoise ? Marie Marie POSSEDE Propritaire Pierre Franoise Marie Vhicule 1234 ZA 75 1234 ZA 75 1001 AR 34 VEHICULE Immatriculation 1234 ZA 75 1001 AR 34 3987 TT 51 Marque Renault Citron Renault Modle Clio ZX Twingo

Jean Fruitet - IUT de Marne La Valle - 13

Introduction la programmation

Notion dalgorithme Un algorithme est un procd automatique qui transforme une information symbolique en une autre information symbolique. Seuls les problmes qui sont susceptibles d'tre rsolus par un algorithme sont accessibles aux ordinateurs. DONNEES Entre ---- transformation ------> ----- algorithme ---------> RESULTAT Sortie

Ce qui caractrise l'excution d'un algorithme, c'est la ralisation d'un nombre fini d'oprations lmentaires (instructions) ; chacune d'elles est ralisable en un temps fini. La quantit de donnes manipules au cours du traitement est donc finie. La notion d'opration lmentaire dpend du degr de raffinement adopt pour la description du procd. Ainsi, chaque algorithme peut tre considr comme une opration lmentaire dans un procd plus important. Exemple dalgorithme : Factorisation de ax2+bx+c quand a0. Algorithme A : soient x1 et x2 les zros de ax2+bx+c ; alors ax2+bx+c = a (x-x1) (x-x2). Algorithme B soit = b2-4ac; si = 0 alors soient x1 et x2 gaux -b/2a sinon si > 0 alors soient x1=(-b+)/2a et x2= (-b-)/2a sinon soient x1=(-b+i(-))/2a et x2= (-b-i(-))/2a; alors ax2+bx+c = a (x-x1) (x-x2). Traduction de lalgorithme dans un langage de programmation Avant de faire traiter la factorisation de ax2+bx+c quand a 0 par un ordinateur, il faut traduire cet algorithme dans le langage binaire susceptible dtre excut par la machine. Cette transformation est le travail du programmeur. Il dispose pour cela dun langage de programmation dit de haut niveau, cest--dire quun tre humain peut apprendre et manipuler sans trop de difficults, et de programmes spcialiss, appels compilateurs, qui font la conversion dun fichier crit dans le langage de haut niveau en code binaire excutable par la machine cible. Une fois compil, le programme (sil est correct) peut tre excut de multiples fois. Les rsultats de son excution (les sorties) dpendent des paramtres fournis en entre.

Programme source

COMPILATION

Programme binaire

..

EXECUTIONS

Une factorisation de 3x 2+11x-4 est 3(x-1/3)(x+4)

Jean Fruitet - IUT de Marne La Valle - 14

Introduction la programmation

Avant de passer la phase de programmation il est donc ncessaire de dfinir trs prcisment le cahier des charges du programme, cest--dire dans quelles conditions initiales il devra fonctionner, comment il devra procder (algorithme) et sous quelle forme seront prsents les rsultats. Types de donnes et structures de contrle Dans lexemple de la factorisation ci-dessus, les entits manipules sont des nombres (complexes et rels), des coefficient constants (a, b, c), une inconnue (x), des variables x1 et x2, le symbole du discriminant et les oprations lmentaires sur lensemble des nombres rels (<, >, =, +, -, *, /). On dira que les types de donnes sont des constantes et des variables de type rel. Lalgorithme emploie aussi des structures de contrle conditionnelles : Si (condition) alors instruction sinon instruction.. Un instruction est soit une affectation = b2-4ac; , soit un test si = 0 alors .Le langage de programmation devra fournir des quivalents de toutes ces entits. Enfin le langage doit permettre de crer un programme qui reoive des paramtres saisie de la valeur des coefficients et retourne des rsultats lutilisateur affichage. Un langage de programmation graphique Traduisons dabord lalgorithme de factorisation dans un langage graphique lmentaire, bien adapt lexpression des algorithmes peu complexes.
Structures de contrle initialisation; test
OUI

?
NON

instruction;

(Branchement)

Chaque bote peut contenir une ou plusieurs instructions excutes squentiellement, cest--dire successivement dans lordre de lecture de haut en bas. Un test est une expression de type boolen, savoir prenant la valeur VRAI ou la valeur FAUX lors de son valuation. Enfin les branchements sont parcourus dans le sens des flches. Il suffit dexcuter chaque instruction la lettre, en suivant les flches dsignes la suite de chaque test pour rsoudre le problme de factorisation. On constate que cette reprsentation fait lconomie dun test par rapport la rsolution mathmatique. Cependant peu nombreux sont les programmes capables dinterprter directement un langage graphique, aussi faut-il exprimer le programme dans un langage littral.

Factorisation d'un polynme du second degr coefficients rels

a,b,c rels; a0;


NON

=b*b-4*a*c;

NON

OUI

(>0)
OUI

(=0)

x1=-b/2*a; x2=-b/2*a;

x1=(-b+)/2*a; x2=(-b-)/2*a;

x1=(-b+i(-))/2*a; x2=(-b-i(-))/2*a; Afficher a (x-x1) (x-x2); FIN DU PROGRAMME;

Jean Fruitet - IUT de Marne La Valle - 15

Introduction la programmation

Modle d'ordinateur abstrait et langage de programmation Passons donc la traduction de lalgorithme dans un langage de programmation lmentaire, le langage de la machine RAM (Random Acces Machine : Machine Accs Direct, voir le cours dalgorithmique). Les algorithmes sont crits pour une machine abstraite qui a les caractristiques d'une machine de Von Neumann. Elle comprend : - des organes d'entre et de sortie (interface avec l'utilisateur) ; - une mmoire unique pour le programme et les donnes ; - une unit centrale comportant notamment un compteur dinstruction, un processeur arithmtique et logique, des registres et des ttes de lecture et d'criture et un moyen d'accs la mmoire ; - un jeu d'instructions excutables par l'unit centrale.
Organe d'entre

Tte de lecture Mmoire Unit centrale Compteur UAL Donnes Programme

Tte d'criture

Organe de sortie

La mmoire est une suite de cases dont les indices sont appels adresses. Une partie de la mmoire contient le programme, traduction de l'algorithme au moyen des instructions de la machine. Le compteur dinstruction contient l'adresse de la prochaine instruction excuter. L'autre partie de la mmoire contient les donnes. Caractristiques : - l'unit centrale accde directement (en temps constant) une case mmoire partir de son adresse [random acces]. - La mmoire est infinie (mais le programme est fini). - Chaque case mmoire contient une donne lmentaire de taille arbitraire. On peut ainsi y mmoriser des entiers arbitrairement grands. - Chaque instruction s'excute en temps constant. Variables et types Une case mmoire de la machine abstraite est aussi appele une variable. Dans les programmes on dsigne une variable par un identificateur littral plutt que par son adresse, et, par abus de langage, on dit "la variable x " plutt que "la variable d'identificateur x ". Le type d'une variable dfinit l'ensemble des valeurs qu'elle peut prendre du point de vue implantation en machine, le type dcide aussi de la taille de lespace mmoire occup par la donne.

Jean Fruitet - IUT de Marne La Valle - 16

Introduction la programmation

Types simples et types combins Les types simples sont - l'entier {....,-1 000 000,... -1 000,... -3,-2,-1, 0, 1, 2, 3, ..10, ..,100, .., 1 000, .....} - le boolen {VRAI, FAUX} [boolean {TRUE, FALSE}] - le caractre {'0','1','2',..,'9',..,'A','B',..,'Z',..,'a','b',...} - l'numr (Ex.: [violet,bleu,vert,jaune,rouge]) - le 'rel' flottant (Ex.: valeur approche de PI 0.3141592 E+1) A partir des types simples des oprateurs permettent de construire des types plus complexes : - couples d'entiers (rationnels) - couples de flottants (nombres complexes) - chanes de caractres (Ex.: "CECI EST UNE CHAINE DE CARACTERES") - tableaux (Ex.: les 8 premires puissances de 2 en base 10 : [1, 2, 4, 8, 16, 32, 64, 128]) - ensembles (Ex.: ensemble de couples d'entiers :{ (0,1), (1,2), (2,4), (3,8), (4,16), (5,32), (6,64), (7,128)} - structures (Ex.: fiche de rpertoire : (Nom, Prnom, Date de naissance, Adresse, Tlphone)) Sur chaque type est dfini un domaine et un ensemble d'oprations : - Addition, multiplication, successeur sur les entiers naturels - Addition, soustraction, multiplication, successeur, prdcesseur, modulo sur les entiers relatifs - Addition, soustraction, multiplication, division, exponentiation, logarithme sur les rels - Oprations logiques ET, OU, NON sur les boolens - Union, intersection, complmentation, produit cartsien sur les ensembles - Concatnation sur les chanes de caractres, etc. Oprations de bases Les oprations de base sur tous les types de variables sont les oprations d'entre-sortie et l'affectation.. Soient x et y des identificateurs de variables. lire(x) signifie : copier la valeur qui est en face de la tte de lecture (sur l'organe d'entre) dans la case-mmoire identifie par x ; puis placer la tte de lecture sur la donne suivante. crire(x) signifie : copier la valeur contenue dans la case mmoire identifie par x sur l'organe de sortie en face de la tte d'criture ; puis avancer cette tte. x = expression se lit x reoit expression et signifie : valuer l'expression et placer la valeur obtenue dans la case-mmoire identifie par x.. Si y apparat dans l'expression, la valeur contenue dans la case-mmoire correspondant y est utilise pour l'valuation : Ex : x = x + y : Le contenu de la case mmoire dsigne par x est remplac par la somme des valeurs contenues dans les cases mmoires dsignes par x et par y. Le contenu original de x est perdu, celui de y est conserv. (2) Les structures de contrle du langage - composition squentielle { instruction1; instruction2; ...; instructionN;} - composition conditionnelle : {SI (condition) ALORS (instruction1) SINON (instruction2)} - composition itrative {POUR (numration) FAIRE (instruction)} {TANT QUE (test) FAIRE (instruction)} - des appels de fonctions et sous-programmes .

2Pour

prparer le lecteur aux conventions du langage C, nous conviendrons de noter laffectation par un signe = et lgalit par ==. Jean Fruitet - IUT de Marne La Valle - 17

Introduction la programmation

De faon plus prcise la syntaxe du langage est dfinie par la grammaire formelle suivante (simplifie du langage C) : type du rsultat identificateur (type paramtre); { suite d'instructions spares par des points-virgules } <instruction> ::= <instruction lmentaire> | { suite d'instructions spares par des points-virgules } | si (test) <instruction> sinon <instruction> | pour (i =d f ) faire <instruction> | tant que (test) faire <instruction> <instruction variable =expression | lmentaire> ::= lire(identificateur) | crire(expression) | retour(expression); L'instruction retour(expression); a pour effet d'arrter l'excution de l'algorithme et de produire la valeur de l'expression. Une expression est bien parenthse au sens de lalgbre et prend une valeur du type des lments qui la composent. <programme> ::= Avec ce langage, traduisons lalgorithme de factorisation. Nous obtenons une fonction qui retourne un couple de polynmes (ventuellement complexes) de degr 1. Fonction factorisation dun polynme rel de degr 2 couple de polynmes de degr 1 factorisation ( polynme rel de degr 2 ax2+bx+c);
{ rel D; D =b2-4ac si (D==0) retour((x+b/2a), (x+b/2a); sinon si (D>0) retour((x-(-b+D)/2a), (x-(-b-D)/2a) ); sinon retour((x-(-b+i (-D))/2a), (x-(-b-i (-D))/2a)); }

Traduit dans le langage de la machine RAM, lalgorithme de factorisation reste encore trs proche de ses origines mathmatiques. Lultime transformation va le traduire dans un langage effectif, le langage C, pour obtenir un programme excutable par une machine relle. Conclusion Cet expos de la factorisation dun polynme nous a permis de passer par les trois tapes de cration dun programme numrique : dfinition du problme, rdaction de lalgorithme en termes mathmatiques, traduction dans un langage de programmation (la traduction en langage C sera aborde au chapitre suivant). Il faut insister ici sur lextrme rigueur de la syntaxe des langages de programmation. Toutes les constantes, variables et fonctions utilises doivent tre types et dfinies avant appel. Les instructions respectent une grammaire prcise, qui caractrise le langage ; les fonctions disponibles (plusieurs centaines en C) fournissent une grande varit doutils dont la matrise ne peut sacqurir que peu peu... Cet apprentissage ne doit pas tre confondu avec une formation lart de la programmation qui peut dbuter avec des exercices plus simples et moins rebutants.
Jean Fruitet - IUT de Marne La Valle - 18

Introduction la programmation

Le langage C. Le langage C est un langage dingnieur destin la cration dapplications informatiques. Beaucoup douvrages lui ont t consacrs. Le plus important est d aux crateurs du langage euxmme, Denis Ritchie et Brian Kerninghan. On en trouvera la rfrence dans la bibliographie. Un programme en C est constitu dun (ou plusieurs) fichiers sources organiss dune faon conventionnelle. Voici une traduction en C de lalgorithme de factorisation. Les cadres (qui ne sont pas ncessaires dans un programme, mais permettent ici de fixer les ides) dlimitent cinq parties fonctionnellement interdpendantes du fichier source.
/* entte : fichiers inclus */ #include <stdio.h> #include <math.h> /* etc. */

(1)

/* dclarations de constantes et de variables globales */ #define FALSE 0 #define TRUE 1 float a, b, c;

(2)

/* prototypes de fonctions */ void factorisation(float a, float b, float c);


void main (void) /* programme principal */ { printf("Factorisation d'un polynme rel de degr 2\n"); printf("Entrez trois nombres rels a, b, c (a0)\n"); scanf("%f %f %f", &a, &b, &c); if (a==0) { printf("Erreur de saisie\n"); exit(0); } factorisation(a, b, c); } /* fin du programme */

(3)

(4)

/* dfinition des fonctions */ void factorisation(float a, float b, float c) /* on assume que a est non nul */ { float delta = b*b - 4*a*c; /* delta est le discriminant */ /* c'est une variable locale */ printf("La factorisation donne \n"); if (delta==0) printf(" (%f)(x-(%f))(x-(%f))\n", a,-b/(2*a),-b/(2*a)); else if (delta>0) printf(" (%f)(x-(%f))(x-(%f))\n", a,(-b-sqrt(delta))/2*a, (-b+sqrt(delta))/2*a); else printf(" (%f)(x+(%f)+(%f)i)(x+(%f)-(%f)i)\n", a, b/(2*a), sqrt(-delta)/2*a, b/(2*a), sqrt(-delta)/2*a); }

(5)

Le bloc (1) est celui des fichiers inclus. Sa premire ligne, #include <stdio.h>, invoque la bibliothque des fonctions dentre-sortie (saisie au clavier scanf() et affichage lcran
Jean Fruitet - IUT de Marne La Valle - 19

Introduction la programmation

printf()). La deuxime ligne, #include mathmatiques (sqrt() : racine carre).

<math.h>,

fait appel aux fonctions

Vient ensuite bloc (2) la dfinition des constantes et des variables globales, cest--dire vues depuis tous les points du programme : #define FALSE 0 #define TRUE 1 float a, b, c; Puis on trouve le prototype de la fonction factorisation() : void factorisation (float a, float b, float c); Celle-ci prend trois paramtres a, b, c : les coefficients du polynme factoriser de type float; mais comme elle ne retourne aucune valeur, elle est type void. Enfin cest le bloc (4) de la fonction main(). Cest le point dentre du programme. Tout programme en Langage C a une fonction main() et une seule. Celle-ci affiche deux lignes de message et lit ensuite le clavier scanf(%f %f %f, &a, &b, &c); jusqu lentre de trois nombres flottants. Aprs avoir test la condition (a0) la fonction factorisation() est appele et le programme se termine. Le dernier bloc (5) est le code de la fonction factorisation(). Le lecteur reconnatra la dfinition du discriminant et lexpression des diffrentes factorisations selon la valeur de . Nous nentrerons pas maintenant dans le dtail de la syntaxe des fonctions printf() et scanf(), qui sont parmi les plus compliques du langage C. Je renvoie le lecteur aux ouvrages cits en rfrence et au support du cours de langage C. Les tapes suivantes consistent compiler ce programme source, puis lier le fichier objet obtenu aprs compilation avec les bibliothques standard et mathmatique, ce qui produit un programme excutable. En cas derreur, ou pour modifier ce programme, il faut reprendre toute la squence en rditant le fichier source... C est troitement associ UNIX Le Systme d'Exploitation (Operating System) UNIX dvelopp aux Laboratoires Bell (ATT Corporation - USA) par B.W. Kernigham et D.M. Ritchie dans les annes 70, a t crit en C, dvelopp pour l'occasion. Unix est multi-tches et multi-utilisateurs, sur mini et stations de travail. Sa diffusion a assur le succs de C chez les universitaires et les ingnieurs. Unix est aujourd'hui fortement concurrent d'OS2 sur micros puissants... Caractristiques succintes du langage C Le langage C est un langage des annes 70, donc 'moderne' par rapport FORTRAN ou BASIC, procdural (description linaire des tats de la mmoire, comme Fortran, Basic, Lisp, Pascal..., contrairement aux langages dclaratifs comme SQL ou Prolog (ensemble de faits et de rgles + moteur d'infrence). C est structur en blocs fonctionnels imbriqus. C fait appel des variables locales chaque bloc ou des variables globales plusieurs blocs. C supporte l'appel de fonctions et c'est un langage typ : les variables et les fonctions utilises doivent tre dclares et leur types et vrifi la compilation. C est un langage compil : le code source est transform en code objet et li pour produire un excutable. Compar PASCAL, C est plus CONCIS mais plus obscur. C est mieux standardis, mais les compilateurs C sont plus libraux que les compilateurs Pascal pour la vrification des types de donnes.
Jean Fruitet - IUT de Marne La Valle - 20

Introduction la programmation

Pour s'assurer du portage d'un programme en C sur d'autres compilateurs, il est fortement conseill de respecter les spcifications ANSI et de tenir compte des avertissements (warnings) la compilation. C est le langages des programmeurs systme... mais sa disponibilit sur tous les systmes informatiques en fait un langage indispensable (avec Fortran pour les applications scientifiques). C n'est pas un langage objets comme C++ ou Java. Evolutions Le futur de C est li la programmation parallle, au dveloppement des rseaux et la Programmation Oriente Objets (C++, Java). L'apprentissage de C est un bon investissement pour l'ingnieur logiciel ou le chercheur amen utiliser des stations de travail, condition de programmer souvent. Structures en blocs Un bloc est une squence d'une ou plusieurs instructions commenant par une accolade ouvrante { termine par une accolade fermante }. Exemple de structure en blocs pour un programme de jeu d'checs
/* Programme Jeu d'checs */ Initialiser_Variables Initialiser_Affichage TANT_QUE (La_Partie_Continue) { SI (C_est_mon_Tour) { Dterminer_mouvement_Suivant (); Mettre__jour_Affichage (); Mettre__jour_Variables (); } SINON { Attendre_Dplacement_Adverse(); Vrifier_Validit(); Mettre__jour_Affichage(); Mettre__jour_Variables(); } }

Chaque Fonction() peut son tour tre dcompose en blocs :


/* Fonction */ Dterminer_mouvement_Suivant() { Chercher_Tous_les_coups_Autoriss(); POUR (Tous_ces_Coups) { Evaluer_la_Position(); SI (Meilleure_Position_Jusque_l) { Mettre__Jour_le_Mouvement_Slectionn (); } } RENVOI (Mouvement_Slectionn); }

Variables locales et variables globales Dans chaque bloc il est possible de dfinir des variables locales - dont l'accs n'est licite qu' l'intrieur du bloc considr- dont la valeur est indtermine sauf affectation explicite, - dont l'emplacement mmoire est libr la sortie du bloc. Les variables globales plusieurs blocs sont connues - dans le bloc englobant o elles sont dfinies, - dans les blocs internes au bloc englobant, sauf en cas de masquage par une redfinition sous le mme nom de variable. Dans l'exemple suivant on vrifie que la variable globale i vaut 1 en entre et en sortie du premier bloc et n'est pas affecte par la variable i interne au deuxime bloc.

Jean Fruitet - IUT de Marne La Valle - 21

Introduction la programmation /* Structure en Blocs -- EXO1.C */ #include <stdio.h> main() /* Programme principal */ { /* Dbut du premier bloc */ int i, n; /* Dfinition */ i=1; /* Affectations */ n=5; printf("Entre du 1er Bloc\n"); printf("Variable i=%d\n",i); printf("Nombre d'itrations %d\n",n); { /* second bloc */ int i; /*i Redfini */ /* Oubli de l'affectation */ printf("Entre du 2me Bloc: i redfini et non affect=%d\n",i); for (i=0; i<n; ++i) printf(" %d dans boucle\n",i); printf("Sortie du 2me Bloc: i=%d\n",i); } /* Fin du second bloc */ printf("Sortie du 1er Bloc: i=%d\n",i); } /* Fin du premier bloc */

L'excution de ce programme produit :


Entre du 1er Bloc Variable i=1 Nombre d'itrations 5 Entre du 2me Bloc: i redfini et non affect=80 0 dans boucle 1 dans boucle 2 dans boucle 3 dans boucle 4 dans boucle Sortie du 2me Bloc: i=5 Sortie du 1er Bloc: i=1

Jean Fruitet - IUT de Marne La Valle - 22

Introduction la programmation

Constantes et variables Le langage C utilise les constantes numriques et les constantes caractres - entiers : 0, 1, 2, -1, -2, etc. - flottants : 0.0, 0.3141592E1, - caractres : 'a', 'b', 'c',..., 'A', 'B', 'C', etc., - constantes chanes de caractres : "CECI est une chane de caractres". Les variables sont des adresses de la mmoire dsignes par des identificateurs littraux commenant par une lettre (exemple : i, j, x, y, entier1, entier_2, bilan_energetique) Mots rservs Les mots rservs ne peuvent pas servir de noms de variables. auto extern short break float sizeof case for static char goto struct continue if switch default int typedef do long union double register unsigned else return while Mots rservs supplmentaires pour la norme ANSI const signed volatile enum void Mots rservs supplmentaires pour le compilateur Turbo C asm huge pascal cdecl interrupt far near Types de donnes Il faut dclarer le type de toutes les variables et de toutes les fonctions, qui indique la fois l'intervalle de dfinition et les oprations licites Types simples Signification Taille (bits) Valeurs limites Type -32768 +32768 entier 16 int -32768 +32768 entier 16 short -2 147 483 648 +2 147 483 648 entier 32 long -128..+127 caractre 8 char +-10 E-37 +-10 E+38 rel float +-10 E-307 +-10 E+308 double rel Une variable entire peut tre dclare 'unsigned' unsigned int 16 0 .. 65535 Le type BOOLEAN est simul en donnant la valeur 0 (FAUX) ou la valeur 1 (VRAI) une variable entire. Les constantes de type caractre ont une valeur entire dans la table ASCII char c1 = 'A', c2 = '\x41'; /* reprsentation hexadcimale */ Caractres spciaux caractres nom
\n \t \b \r \f \a \\ \' \" newline tabulation backspace return form feed bell backslash single quote double quote

symbole
LF HT BS FF BEL 5C 27 22

code
0A 09 08 CR 0C 07 92 39 34

code hexa
10 9 8 0D 12 7

dcimal

13

Jean Fruitet - IUT de Marne La Valle - 23

Introduction la programmation

Instruction d'affectation L'assignation est une instruction qui affecte une valeur une variable. Cette valeur peut provenir de l'valuation d'une constante, d'une expression ou d'une fonction. Le symbole = dsigne l'affectation (assignation). int i, j, k; /* dclaration */ i = j = 5; /* assignation de 5 j et de j i */ k = 7; /* assignation de 7 k */ Transtypage (cast) C permet des assignations entre variables de types diffrents.Une variable dclare char, occupant un octet de mmoire, peut tre transtype en int, occupant deux octets de mmoire. Rgles de transtypage (casting) char --> int le char se retrouve dans l'octet le moins significatif ; si le caractre a t dclar unsigned char, il n'y a pas d'expansion du signe, sinon on retrouve le bit de poids fort rpt 8 fois dans l'octet le plus significatif. int --> char perte de l'octet le plus significatif int --> long expansion du bit de signe long --> int rsultat tronqu (perte des deux octets les plus significatifs) unsigned --> long les deux octets les plus significatifs sont mis 0 int --> float exemple : 15 --> 15.0 float --> int perte de la partie dcimale : 2.5 --> 2 Si la partie entire du rel est suprieure 32767 le rsultat sera aberrant. float --> double pas de difficult double --> float perte de prcision Quand des expressions mlangent les types, le transtypage est automatique. Oprateurs C emploie plusieurs oprateurs : arithmtiques, de comparaison, logiques... La priorit des oprateurs entre eux permet d'valuer d'une expression. Oprateurs arithmtiques Par ordre de priorit dcroissante Symbole Signification * / multiplication + addition % reste de la division entire (modulo) Oprateurs de comparaison Si une expression est FAUSSE elle renvoie une valeur nulle , si elle est VRAIE elle renvoie une valeur non nulle. Les oprateurs && et || permettent de combiner des expressions logiques Par ordre de priorit dcroissante : Symbole Signification ! NON (inverse une condition) > >= < <= sup / sup ou egal / inf / inf ou egal = = != gal / diffrent && || ET logique / OU logique

division (entire et relle) soustraction

Jean Fruitet - IUT de Marne La Valle - 24

Introduction la programmation

Table de vrit de l'oprateur FAUX && FAUX FAUX && VRAI VRAI && FAUX VRAI && VRAI Table de vrit de l'oprateur FAUX || FAUX FAUX || VRAI VRAI || FAUX VRAI || VRAI L'instruction i = i +1; s'crire i++; ou ++i; De mme i = i - 1;

ET

AND && == FAUX == FAUX == FAUX == VRAI || FAUX VRAI VRAI VRAI

OU : OR : == == == ==

Incrmentation et dcrmentation remplace la valeur de i par i+1 ; c'est une incrmentation qui peut aussi i - -; ou - - i;

peut s'crire

Remarque: avec l'instruction i++, i est affect puis incrment, avec ++i, i est incrment puis affect, avec l'instruction i--, i est affect puis dcrment, avec - -i, i est dcrment puis affect et enfin avec i- - , i est affect puis dcrment. Si (e1) et (e2) sont des expressions et "op" une opration prise parmi la liste + - * / % << >> & | ^ alors (e1) = (e1) op (e2); peut s'crire (e1) op = (e2); On conomise une valuation de e1. Attention aux parenthses : x *= y + 1; est quivalent x = x * (y+1); et non x = x * y + 1; Autrement dit si x==3, y==4 le rsultat de cette instruction remplacera x par 15 et non pas par 13 ! Structures conditionnelles Pour les structures conditionnelles, la condition value doit tre de type entier (short, int, long) ou char. Toute fonction qui renvoie une valeur d'un de ces types peut tre teste dans la condition. if / else if (condition) /* commentaire de la condition si */ instruction; if (condition) { /* dbut de bloc*/ instruction1; instruction2; } /* fin de bloc */ if (condition) instruction_si; else /* sinon */ instruction_sinon;

Jean Fruitet - IUT de Marne La Valle - 25

Introduction la programmation

Conditions imbriques if (condition1) inst1; else if (condition2) inst2; else if (condition3) inst3; else /* chaque else se rapporte au if le plus proche sauf si on utilise des accolades comme dans l'exemple suivant */ inst4; Regroupement d'instructions if (cond1) /* premier if */ { if (cond2) inst1; else if (cond3) inst2; } else /* sinon se rapportant au premier if */ inst3; Affectation conditionnelle if (i>j) z = a; else z = b; est quivalent

z = (i>j) ? a : b;

Slection (switch) L'instruction switch est une sorte d'aiguillage. Elle permet de remplacer plusieurs instructions imbriques. La variable de contrle est compare la valeur des constantes de chaque cas (case). Si la comparaison russit, l'instruction du case est excute jusqu' la premire instruction break rencontre. switch (variable_controle) { case valeur1 : instruction1; break; /* sortie du case */ case valeur2 : instruction2; break; case valeur3 : /* plusieurs */ case valeur4 : /* tiquettes */ case valeur5 : instruction3; /* pour la mme instruction */ break; default : instruction4; /* cas par dfaut */ break; /* facultatif mais recommand */ } variable_controle doit tre de type entier (int, short, char, long). break fait sortir du slecteur. En l'absence de break, l'instruction suivante est excute ; on peut ainsi tester plusieurs cas diffrents et leur attribuer la mme instruction.
Jean Fruitet - IUT de Marne La Valle - 26

Introduction la programmation

Boucles et sauts Les boucles consistent rpter plusieurs fois la mme squence d'instructions. La sortie de boucle est ralise en testant une condition (de type boolen VRAI ou FAUX). While, Tant que . while (condition) instruction; while (condition) { instruction1; instruction2; } La condition est value avant d'entrer dans la boucle. La boucle est rpte tant que la condition est VRAIE. For, Pour. for (initialisation; condition d'arrt; incrmentation) instruction; for (initialisation; condition d'arrt; incrmentation) { instruction1; instruction2; ... } La condition est value avant d'entrer dans la boucle. L'incrmentation de la variable de contrle est faite la fin de chaque tour de boucle. Exemple : int i; for (i=1; i<10; i++) printf("%d ",i); /* ce programme affiche 1 2 3 4 5 6 7 8 9 */ Do ... While, Faire ... tant que. do { instruction1; instruction2; } while (condition d'arrt); La condition est value aprs le passage dans la boucle. Exit Un programme peut tre interrompu par l'instruction exit(code de retour); de retour est un entier qui peut tre teste par le programme appelant. La valeur du code

Jean Fruitet - IUT de Marne La Valle - 27

Introduction la programmation

Tableaux Un tableau est une suite de cellules conscutives en mmoire pouvant contenir des donnes de type identique. La taille du tableau et le type des donnes doivent tre dclars en mme temps que le tableau. Le nombre de dimensions n'est pas limit. L'indice (adresse relative de chaque cellule par rapport au dbut du tableau) doit tre une expression entire ; la premire cellule a l'indice 0. Tableaux une dimension Exemples : int t[5]; Nom du tableau est t ; les cellules sont de type entier (int) ; la taille 5 ; indexe de 0 4 long l[2]; Nom du tableau est l; les cellules sont de type entier (long) ; la taille 2; indexe de 0 1 char hexa[17]; Nom du tableau est hexa ; cellules de type char ; taille 17 Un tableau peut tre affect en mme temps qu'il est dclar : int tabint[5] = {0, 10, 100,}; /* les autres cellules 0 */ char binaire[2] = {'0', '1'}; Affectation Pour initialiser un tableau, il faut dsigner ses diffrentes cellules :
t[0] = tabint[4] = 10000; hexa[0] = '0'; for (i=0; i<5; i++) tabint[i] = i*i; /* affectation en cascade */

Attention : les dpassements des bornes d'indice des tableaux ne sont pas dtects la compilation. C'est donc au programmeur d'ajouter les instructions de contrle des bornes avant d'affecter une variable un tableau. Chanes de caractres Les chanes sont des tableaux de caractres termins par le caractre NULL ('\0'). Il faut dclarer leur taille, c'est--dire le nombre de caractres plus un pour stocker la fin de chane. char decimal[11] /* dclaration : 11 = 10 caractres + '\0' */ = "0123456789"; /* cette affectation : est quivalente */ char decimal[11] = {'0','1','2','3','4','5','6','7','8','9','\0'}; char alpha[6] = "ABCDE" 5 caractres; compose de 6 octets identiques au code ASCII de chaque caractre sot 65 66 67 68 69 00 en dcimal, et 0x41 0x42 0x43 0x44 0x45 0x00 en hexadcimal. Tableaux plusieurs dimensions Deux dimensions (matrice) int a[3][3] = {{1,2,-1},{-2,3,4},{5,0,6}}; a[0] dsigne la 1re ligne : {1,2,0}. a[0][2] dsigne le 3me lment de la 1re ligne : 1. a[2][1] dsigne le 2me lment de la 3me ligne : 0. Trois dimensions int parallelepipede[3][2][4]; 3 couches de 2 lignes de 4 colonnes chacune. parallelepipede[0][0][0] dsigne la premire colonne de la premire ligne de la premire couche. parallelepipede[2][1][3] dsigne la dernire colonne de la dernire ligne de la dernire couche...

Jean Fruitet - IUT de Marne La Valle - 28

Introduction la programmation

Pointeurs Un pointeur est une variable qui contient l'adresse d'une autre variable. Selon le type de donne contenu l'adresse en question, on aura un pointeur d'entier, de float, double, char, ou de tout autre type. En accdant cette adresse, on peut accder indirectement la variable et donc la modifier. Dclaration de pointeur Pour dclarer un variable pointeur on utilise l'oprateur * plac aprs le type du pointeur. Un pointeur sur entier est dclar par int *p; Un pointeur sur rel float *p; Un pointeur sur caractre char *p; Pointeur sur pointeur de type double double **tab; la variable tab est un pointeur pointant sur un pointeur qui pointe sur un flottant double ! La dclaration int *p signifie que *p est un entier et donc que p est un pointeur sur un entier. Oprateur adresse (&) On dispose de deux oprateurs unaires pour manipuler les pointeurs, & et * L'oprateur d'adresse & renvoie l'adresse de l'objet dsign. int i, j; /* dclarations d'entiers i et j */ int *p1, *p2; /* dclaration de pointeurs sur des entiers */ i = 5; /* affectation */ j = 2 * i; /* affectation */ p1 = &i; /* p1 contient l'adresse de i */ p2 = &j; /* p2 pointe sur j */ Cet oprateur & ne peut tre employ que sur les variables et les lments de tableaux ; les constantes &3 et les expressions &(i+1) sont interdites. Oprateur valeur (*) L'oprateur * considre son oprande comme un pointeur et en renvoie le contenu. p1 = &i; reoit l'adresse de i; donc pointe sur i j = *p1; j prend la valeur contenue l'adresse pointe par p1, donc la valeur de i ;:cette instruction est quivalente j = i; int *p, *q, x, y; Partout o un entier peut tre employ, *p peut l'tre aussi : p = &x; /* p pointe sur x */ x = 10; /* x vaut 10 */ y = *p1 - 1;/* y vaut 9 */ *p += 1; /* incrmente x de 1 : x vaut 11 */ (*p)++; /* incrmente aussi de 1 la variable pointe par p, donc x vaut 12. */ Attention aux parenthses : *p++ est TRES DIFFERENT de (*p)++ car ++ et * sont valus de droite gauche et *p++ incrmente le pointeur p (l'adresse) et non le contenu de p *p = 0; /* comme p pointe sur x, maintenant x vaut 0 */ q = p; /* p et q pointent maintenant sur la mme adresse donc *q devient zro ! */ Pointeurs et tableaux En C le compilateur transforme toute dclaration de tableau en un pointeur sur le premier lment du tableau. int tabint[10]; est donc quivalent int *tabint; ( la rservation mmoire prs).
Jean Fruitet - IUT de Marne La Valle - 29

Introduction la programmation

Exemples : int i, j, *p; p = &tabint[0]; p pointe sur le premier lment de tabint i = *p; recopie le contenu de tabint[0] dans i p++; p pointe sur le second lment de tabint p+j; adresse de tabint[j] *(p+j); contenu de tabint[j] Tableaux de pointeurs Un tableau de pointeurs est un tableau dont les lments sont des pointeurs. char *mois[13]; int *valeurs[5]; Allocation dynamique de mmoire Quand on utilise des pointeurs il est indispensable de toujours savoir quels lments sont manipuls dans les expressions et si de l'espace mmoire a t rserv par le compilateur pour stocker les objets points. En effet, alors qu'une dclaration de tableau rserve de l'espace mmoire dans l'espace des donnes pour la variable et ses lments, celle d'un pointeur ne rserve que la place pour une adresse ! La dclaration double x[NOMBRE]; rserve un espace de stockage pour NOMBRE lments de type rel double et la variable x[0] stocke l'adresse de l'lment n zro (le premier lment). Par contre la dclaration double *x; ne rserve que le seul espace destin au pointeur x, AUCUN espace n'est rserv pour une ou plusieurs variables en double prcision. La rservation d'espace est la charge du programmeur qui doit le faire de faon explicite, en utilisant les fonctions standard malloc(), calloc(), ou realloc(). Ces fonctions sont prototypes dans <stdlib.h> et <alloc.h> char * malloc( unsigned taille); rserve taille octets, sans initialisation de l'espace char * calloc( unsigned nombre, unsigned taille); rserve nombre lments de taille octets chacun ; l'espace est initialis 0. void * realloc( void *block, unsigned taille); modifie la taille affecte au bloc de mmoire fourni par un prcdent appel malloc() ou calloc(). void free( void *block); libre le bloc mmoire point par un prcdent appel malloc(), calloc() ou realloc(). Ces fonctions doivent tre transtypes pour rserver de l'espace pour des types de donnes qui sont diffrents du type (char *). Elles retournent le pointeur NULL (0) si l'espace disponible est insuffisant. Exemples : char *s, *calloc(); s = (char *) calloc(256, sizeof(char)); /* rserve 256 octets initialiss '\0' */ float *x; x = (float *) malloc(sizeof(float)); /* rserve un espace pour un rel de type double */ L'allocation dynamique de mmoire se fait dans le tas (mmoire systme dynamique) ; la taille de celui-ci varie en cours d'excution, et peut n'tre pas suffisante pour allouer les variables, provoquant le plantage du programme. Il faut donc tester le retour des fonctions d'allocation et traiter les erreurs.

Jean Fruitet - IUT de Marne La Valle - 30

Introduction la programmation

Exemple de traitement d'allocation dynamique.


#define BUFSIZE 100 long *numero; if (!(numero = (long *) calloc(BUFSIZE, sizeof(long))) ) /* Si chec rservation de BUFSIZE emplacement de type long */ { fprintf(stderr, "ERREUR espace mmoire insuffisant !\n"); exit (1); /* fin anticipe du programme ; code de retour 1 */ } else /* le programme continue */

L'espace allou une variable peut tre libr par free(), dont l'argument est un pointeur rserv dynamiquement. free(s); free(x); free(numero); Programme principal et fonctions Les fonctions permettent de dcomposer un programme en entits restreintes. Une fonction peut se trouver : - dans le mme module de texte (toutes les dclarations et instructions qui la composent s'y trouvent), - tre incluse automatiquement dans le texte du programme (#include) - ou compile sparment puis lie (linked) au programme. Une fonction peut tre appele partir du programme principal, d'une autre fonction ou d'ellemme (rcursivit). Elle peut retourner une valeur (int par dfaut) ou ne pas en retourner (dclare void, assimilable une procdure Pascal). Une fonction peut possder ses propres variables ; elle n'a qu'un seul point d'entre et peut avoir plusieurs points de sortie. Dclaration de fonction avec prototypage Le prototypage permet au compilateur de faire une vrification de type au moment de la dfinition et de l'appel.
/* prototype de fonction : entte de dclaration suivi par ';' dclaration avec les types des arguments entre les parenthses */ type_retourn nom_fonction (type variable1, type variable2, ...)';'

Dfinition La dfinition de la fonction (la liste des instructions) reprend le mme texte que pour le prototype sans ';' type_retourn nom_fonction (type variable1, type variable2, ...)
{ /* corps de la fonction */ /* dclarations de variables locales la fonction */ /* initialisations */ /* instructions; */ return (valeur_retourne); }

Arguments et valeur retourne. Les arguments de la fonction sont passs par VALEUR ; une copie provisoire de chaque argument est passe la fonction qui ne peut donc pas modifier l'argument initial d'une fonction appelante. Mais si on passe un pointeur (une adresse) une fonction,celle-ci modifiera ainsi l'argument : c'est un passage par VARIABLE ou par ADRESSE. On obtient le mme rsultat en passant un tableau
Jean Fruitet - IUT de Marne La Valle - 31

Introduction la programmation

la fonction, puisque les tableaux sont considrs par le compilateur comme un pointeur sur le premier lment du tableau. Une fonction dclare void ne retourne rien. La valeur retourne peut tre ignore par la fonction appelante. Si la fonction ne contient pas de return( ); la valeur retourne n'a pas de sens particulier.
/* Appel de fonction */ #include <stdio.h> /* Entres/Sorties */ /* prototype */ int demo (int i, double n); void main(void) /* Programme principal */ { int i; /* Dfinitions */ double n; i=2; /* Affectations */ n=10.0; printf("APPEL DE FONCTIONS \n"); printf("Valeurs avant appel\n"); printf("Variable i=%d\n",i); printf("Variable n=%f\n",n); if (i) printf("Valeur renvoye par fonction =%d\n",demo(i,n)); printf("Valeurs aprs appel\n"); printf("Variable i=%d\n",i); printf("Variable n=%f\n",n); printf("\n"); } int demo (int i, double n) /* dfinition de fonction */ { n = n / i; printf("\nValeurs dans la fonction\n"); printf(" Variable i=%d\n",i); printf(" Variable n=%f\n",n); return((int)n); } ----------------------------------------------APPEL DE FONCTIONS Valeurs avant appel Variable i=2 Variable n=10.000000 Valeurs dans la fonction Variable i=2 Variable n=5.000000 Valeur renvoye par fonction =5 Valeurs aprs appel Variable i=2 Variable n=10.000000 ----------------------------------------------

Remarque : La fonction demo(i,n) fait la division de n par i, retourne le rsultat transtyp entier mais ne modifie ni la valeur de n ni celle de i. Le contrle de i avant la division est indispensable pour viter une division par zro. L'exemple suivant propose une fonction qui modifie (par permutation) les lments d'un tableau; le tableau est pass la fonction qui renvoie un tableau modifi.
/* Appel de fonction */ Jean Fruitet - IUT de Marne La Valle - 32

Introduction la programmation #include "stdio.h" /* Entres/Sorties */ #define MAXTAB 10 /* Constante */ int echange (int i, int n[]); /* prototype de fonction */ /* dfinition de la fonction */ int echange (int i, int n[]) /* un tableau en argument */ { int j, aux; for (i=0, j=MAXTAB-1; i < j; i++, j--) { printf(" Echange %4d et %4d\n",n[i],n[j]); aux = n[i]; n[i] = n[j]; n[j] = aux; } return(i); } void main(void) /* Programme principal */ { /* Dfinitions */ int i; int tabint[MAXTAB] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; /* Affectations */ printf("APPEL DE FONCTION PAR VARIABLE \n"); printf("Valeurs du tableau avant appel\n"); for (i=0; i<MAXTAB; i++) printf("%4d%c",tabint[i], (i%5==4 || i==MAXTAB-1) ? '\n' : ' '); printf("Nombre d'changes = %d\n",demo(i,tabint)); printf("Valeurs aprs appel\n"); for (i=0; i<MAXTAB; i++) printf("%4d%c",tabint[i], i%5==4 || i==MAXTAB-1) ? '\n' : ' '); } --------------------------------------------APPEL DE FONCTION PAR VARIABLE Valeurs du tableau avant appel 0 1 2 3 4 5 6 7 8 9 Echange 0 et 9 Echange 1 et 8 Echange 2 et 7 Echange 3 et 6 Echange 4 et 5 Nombre d'changes = 5 Valeurs aprs appel 9 8 7 6 5 4 3 2 1 0 ---------------------------------------------

Pointeurs et arguments de fonctions En raison de l'appel par valeur, une fonction ne peut pas modifier ses arguments. L'utilisation de pointeurs permet de tourner la difficult. Soit par exemple la fonction echange(x,y) qui est cense changer ses arguments :
void { int aux y = x = } echange (int x, int y) /* INCORRECT */ aux; = y; x; aux;

Jean Fruitet - IUT de Marne La Valle - 33

Introduction la programmation

L'appel de echange(i,j) avec i et j entiers n'aura aucun effet car ces paramtres sont passs par valeur et ne sont pas modifis en dehors de echange().
void echange (int *x, int *y) /* CORRECT */ { int aux; aux = *y; *y = *x; *x = aux; }

Maintenant l'appel de echange(&i,&j) modifie les variables i et j car les adresses des paramtres sont passes la fonction (on parlera de passage par VARIABLE ou par ADRESSE). Fonctions rcursives Si le texte de la fonction fait appel la fonction elle-mme, la fonction est rcursive. A chaque appel rcursif, l'ensemble des variables locales est sauvegard dans une pile et restaur au sortir de l'appel rcursif. C'est le compilateur qui se charge de grer la pile ; l'utilisateur doit veiller ce que les appels rcursifs se terminent . Sinon une erreur d'excution se produit quand la pile des appels est pleine (stack overflow).
/* version rcursive de la fonction factorielle */ #include <stdio.h> unsigned long fact(unsigned long n); /* factorielle */ void main(void) { unsigned long u; printf("Entrez un nombre "); scanf("%ld ",&u); printf("Factorielle %ld : %ld\n",u, fact(u)); } unsigned long fact(unsigned long n) { if (n <=1) return (1); else return (n*fact(n-1)); }

Quelle est la condition d'arrt de la rcursion ? Combien d'appels rcursifs pour (4!) ? Arguments sur la ligne de commande Un programme en langage C une seule entre : c'est la fonction main(), qui doit tre unique dans tous les fichiers du programme, et se charge d'appeler les autres fonctions. On peut transmettre des paramtres un programme C par le biais des paramtres de cette fonction : void main(int argc, char *argv[]) argc est le nombre d'arguments de la commande + 1. Si argc > 1, la commande a des arguments. argv est un pointeur sur un tableau de chanes de caractres contenant les arguments de la commande : argv[0] est le nom de la commande. argv[1] est le premier argument argv[argc-1] est le dernier argument.

Jean Fruitet - IUT de Marne La Valle - 34

Introduction la programmation

Exemple : Que fait le programme ci-dessous ?


#include <stdio.h> #include <stdlib.h> char *nom_de_mois(int n) { static char *mois[13] = {"erreur", "janvier", "fvrier", "mars", "avril", "mai", "juin", "juillet", "aot", "septembre" "octobre", "novembre", "dcembre" }; return ((n < 1 || n > 12) ? mois[0] : mois[n]); } main(int argc, char *argv[]) { char *nom_de_mois(); if (argc > 1) printf( "<%s>\n", nom_de_mois(atoi(argv[1]))); else printf("Usage %s numro\n", argv[0]); }

Structure Une structure est une collection de donnes regroupes sous un seul nom. Dclaration Le type hms (heure, minute, seconde) struct hms { /* dclaration et nom de la structure */ int h, m, s; /* champs de la structure */ } heurelocale; /* nom de variable */ Le type date utilise aussi le type hms : struct date { char *nom_jour, nom_mois[4]; int jour, mois, annee; struct hms heure; /* structure dans une structure */ }; /* le nom de variable est facultatif */ Affectation L'oprateur . (point) permet d'accder aux composantes d'une structure.
heurelocale.h = 10; heurelocale.m = 07; heurelocale.s = 55; printf("%02d:%02d%:%02d\n",heurelocale.h,heurelocale.m,heurelocale.s) ;

L'oprateur -> (Flche = MoinsSuprieur) permet d'accder aux composants d'un pointeur sur une structure.
struct date * ddnaissance = (struct date) *calloc(1, sizeof(struct date)); strcpy(ddnaissance->nom_jour, "Lundi"); strcpy(ddnaissance->nom_mois, "MAR"); ddnaissance->jour=19; ddnaissance->mois=3; ddnaissance->annee=1999;

Union Une union est une variable qui peut contenir ( diffrents moments) des objets de types et de tailles diffrents. Exemple :
Jean Fruitet - IUT de Marne La Valle - 35

Introduction la programmation union mot_machine { char quatrecar[4]; int deuxentier[2]; long unlong; } *mot;

Cette union, dont l'encombrment mmoire est de 4 octets, peut tre initialise de diffrentes faons. Soit octet par octet :
mot->quatrecar[0] mot->quatrecar[1] mot->quatrecar[2] mot->quatrecar[3] = = = = 'a'; 'b'; 'c'; 'd';

Soit par sries de deux octest :


mot->deuxentier[0] = 0; mot->deuxentier[1] = 1;

soit d'un seul coup :


mot->unlong = 1234567;

De plus l'espace mmoire dsign par l'union peut tre interprt selon chacun de ces aspects par le compilateur... Directives de compilation Typedef Le mot rserv typedef cre de nouveaux noms de types de donnes (synonymes de types dj dfinis). Exemple : typedef char * STRING; fait de STRING un synonyme de "char * " #define #define et #include sont des commandes du prprocesseur de compilation. #define est un mot rserv qui permet de dfinir une macro Exemple : #define ESC 27 A la compilation la chaine ESC sera remplace par 27 dans tout le fichier contenant cette dfinition de macro. Attention : une macro n'est pas une instruction donc il ne faut pas terminer la dfinition d'une macro par le caractre ';' #define sum(A,B) ((A) + (B)) Cette macro remplace tous les appels de sum() avec deux paramtres par l'expression somme. Les parenthses ( ) vitent les erreurs d'association... #include #include <nom.h> Inclusion du fichier nom.h situ dans le rpertoire spcifi par l'option de compilation -I en TURBOC. #include "nom.h" Inclusion du fichier nom.h cherch dans le rpertoire courant puis dans les rpertoires spcifis par l'option de compilation -I en TURBOC. Directives de compilatio Les directives de compilation permettent d'inclure ou d'exclure du programme des portions de texte selon 'valuation de la condition de compilation. #if defined (symbole) /* inclusion si symbole est dfini */ #ifdef (symbole) /* idem que #if defined */ #ifndef (symbole) /* inclusion si symbole non dfini */
Jean Fruitet - IUT de Marne La Valle - 36

Introduction la programmation

#if (condition) /* inclusion si condition vrifie */ #else /* sinon */ #elif /* else if */ #endif /* fin de si */ #undef symbole /* supprime une dfinition */ Exemple :
#ifndef (BOOL) #define BOOL char /* type boolean */ #endif #ifdef (BOOL) BOOL FALSE = 0; BOOL TRUE = 1; #else #define FALSE 0 #define TRUE 1 #endif /* type boolean */ /* dfinis comme des variables */ /* dfinis comme des macros */

#if 0 Cette partie du texte sera ignore par le compilateur cela permet de crer des commentaires imbriqus et d'carter momentanment du texte source des parties deprogramme. #endif

Les entres/ sorties et les fichiers Pour des questions de portabilit du langage C, les entres sorties (affichage ; saisie de caractres ; lecture/criture de fichiers) qui sont tout fait dpendantes du matriel, n'ont pas t inclusent dans le langage... Il n'y a pas de mots rservs pour les raliser. Cependant chaque compilateur fournit une bibliothque de fonctions standard ralisant les principales entres sorties. Cette bibliothque est dsigne sous le nom de fichier stdio.h Tout fichier source qui fait rfrence une fonction de la bibliothque standard doit donc contenir la ligne #include <stdio.h> en dbut de fichier. Un faon lgante de considrer les entres / sorties - c'est--dire le clavier, l'cran, les mmoires de masse - c'est de les traiter soit comme des fichiers squentiels (clavier, cran) soit comme des fichiers accs direct (la mmoire). Le langage C fournit pour chaque type de fichier une collection de fonctions ralisant les oprations lmentaires de lecture et d'criture. Ces entres / sorties ont pour support des flux (de caractres, de blocs, etc.). Un flux est reprsent de faon logique par un type FILE du fichier stdio.h. FILE est un nom pour une structure dont les champs (tampon, caractre courant, nom du flux...) sont utiliss par les fonctions d'entre sortie 3. Trois flux sont prdfinis : stdin, stdout, stderr, qui sont respectiveemnt l'entre standard, la sortie standard et la sortie erreur standard. A ces flux sont associs par le systme d'exploitation, et ceci indpendamment du programme, des fichiers ou des priphriques au moment du lancement du programme. Les affectations par dfaut sont le clavier (stdin) et l'cran (stdout et sdterr), mais elles peuvent tre modifies par des redirections. Fonctions d'entres / sorties Les principales fonctions d'entres / sorties [input / output] concernent la lecture des caractres au clavier et l'criture des caractres l'cran.

Je ne saurais trop conseiller l'apprenti programmeur l'excellent ouvrage de Jacquelin Charbonnel "Langage C, les finesses d'un langage redoutable" Collection U Informatique - Armand Colin 1992 Jean Fruitet - IUT de Marne La Valle - 37

Introduction la programmation

Les fonctions de lecture getchar(), gets() et scanf() lisent leurs donnes sur stdin. Les fonction getc(), fgets() et fscanf() leur sont apparentes pour les flux non prdfinis de type FILE *. Les fonctions d'criture putchar(), puts() et printf() crivent leurs donnes sur la sortie standard stdout. Les fonctions putc(), fputc() et fprintf() s'adressent des flux non prdfinis, de type FILE *. Les fonctions fread() et fwrite() permettent de lire et d'crire des blocs d'enregistrements. La fonction fseek() positionne le pointeur de flux une position donne (dplacement de la tte de "lecture / criture") ; la fonction ftell() indique la position courante du pointeur de flux. Lecture du clavier / criture l'cran : getchar() et putchar(), gets() et puts() getchar() : lecture (par le processeur) d'un caractre au clavier, "l'entre standard" Syntaxe : int getchar(void); Renvoie un entier sur l'entre standard (cet entier est un code ASCII) ; renvoie EOF quand elle rencontre la fin de fichier ou en cas d'erreur. putchar() : criture (par le programme) d'un caractre sur l'cran, "la sortie standard" Syntaxe : int putchar(int c); Place son argument sur la sortie standard. Retourne c si la sortie est raliss, EOF en cas d'erreur. Les entres de getchar() et les sorties putchar() peuvent tre rediriges vers des fichiers. gets() : lecture d'une chaine de caractres au clavier. Syntaxe : char *gets(char *s); Lit une chaine depuis l'entre standard stdin et la place dans la chane s. La lecture se termine la rception d'un NEWLINE (saut de ligne) lequel est remplac dans s par un caractre ASCII nul '\0' de fin de chane. Renvoie NULL quand elle rencontre la fin de fichier ou en cas d'erreur. puts() : criture d'une chaine de caractres l'cran. Syntaxe : int puts(const char *s); Recopie la chaine s dans la sortie standard stdout et ajoute un saut de ligne. Renvoie le dernier caractre crit ou EOF en cas d'erreur. Formatage des entres clavier / sorties cran : printf() et scanf() Les fonctions de la famille de printf() et de scanf() permettent les sorties et les entres formates de chanes de caractres. Un tableau de leurs caractristiques assez complexes est donn en annexe. Fichiers de donnes Il s'agit de fichiers non prdfinis, par exemple des donnes traiter par programme. On distingue selon le type de support et de contenu les fichier squentiels : squence d'enregistrements auxquels on accde dans l'ordre squentiel, c'est--dire du premier au dernier en passant par tous les enregistrements intermdiaires. Par exemple une bande magntique (K7 audio). Le clavier est vu par l'ordinateur comme un fichier squentiel en lecture. L'cran est un fichier en criture (pas ncessairement squentiel). les fichier accs direct : squence d'enregistrements sur mmoire externe ou interne auxquels on accde directement, par l'adresse individuelle de chaque enregistrement (mmoire vive RAM : Random Access Memory) ou par indirection (tableau index). les fichier binaires : ce sont des fichiers structurs sous forme d'enregistrements (struct en langage C), dont le contenu doit tre interprt par le programme qui les a crs. les fichiers textes : ce sont des documents textuels en ASCII, qu'une commande comme TYPE peut afficher.

Jean Fruitet - IUT de Marne La Valle - 38

Introduction la programmation

Oprations sur les fichiers Un fichier est caractris par un nom et une adresse logique attribus par le propritaire du fichier et convertis en adresse physique absolue dans le systme de fichiers de l'ordinateur (rle du systme d'exploitation [Operating System]). Les opration de base sur les fichiers sont : - cration du fichier (attribution d'un nom et d'une adresse logique / physique) ; - ouverture du fichier en criture, en lecture, en mode ajout ; - lecture d'un enregistrement ; - criture d'un enregistrement ; - positionnement de la tte de lecture (le tampon) en dbut, en fin, une adresse relative au dbut ou la fin du fichier ; - fermeture du fichier ; - suppression du fichier. L'accs aux enregistrements constitutifs du fichier traiter se fait au travers d'une fentre appele tampon [buffer] (de lecture ou d'criture, selon l'opration ralise), qui est une variable du mme type que les enregistrements constitutifs du fichier, ce qui conduit voir ce tampon comme contenant un lment du fichier. Descripteurs et flux La gestion des fichiers tant troitement dpendante de la plateforme matrielle et logicielle (systme d'exploitation), nous ne prsenterons ici que ce qui concerne MS-DOS. On dispose de fonctions quivalentes dans les autres systmes d'exploitation. Deux mthodes de gestions de fichiers sont possibles dans l'envionnement MS-DOS : - par descripteur de fichier [handler] - par association au fichier d'un bloc de contrle [File Control Block] et d'un pointeur de flux [FILE *] Fonctions C utilisant un descripteur Ce sont des fonctions de bas niveau. Leur emploi est plutt destin la programmation systme. Fonctions C utilisant un flux Ces fonctions accdent des flux, donc manipulent des objets de type FILE - type dfini dans le fichier stdio.h. fopen() : ouvre un fichier dont le nom et le mode sont passs en paramtres. Syntaxe : FILE *fopen(char * nomfichier, char * mode); mode dfinit les attributs du fichier ; il peut prendre les valeurs
"r" fichier binaire, ouverture en lecture [read] partir du dbut "w" fichier binaire, cration et ouverture en criture [write] (s'il existe le fichier est vid) "a" fichier binaire, ouverture en ajout [append] partir de la fin du fichier "r+" fichier binaire, ouverture en lecture / criture partir du dbut "w+" fichier binaire, recr en lecture / criture [write] (s'il existe le fichier est vid) "a+" fichier binaire, ouverture en lecture / criture partir de la fin "rt" "wt" "at" "r+t" "w+t" "a+t" fichier texte, ouverture en lecture [read] partir du dbut fichier texte, cration et ouverture en criture [write] (s'il existe le fichier est vid) fichier texte, ouverture partir de la fin du fichier fichier texte, ouverture en lecture / criture partir du dbut fichier texte, recr en lecture / criture (s'il existe le fichier est vid) fichier texte, ouverture en lecture / criture partir de la fin

Un pointeur sur un tampon de type FILE est cr et renvoy par la fonction fopen() qui retourne NULL si l'opration a chou.
Jean Fruitet - IUT de Marne La Valle - 39

Introduction la programmation

Exemple :
#include <stdio.h> #include <errno.h> #include <stddef.h> #define MAXNOM 40 #define MAXMODE 4 int main(void) /* ouverture d'un fichier texte en mode ajout */ { FILE *fichier; char nomfichier[MAXNOM] = "biblio.txt"; if ((fichier = fopen(nomfichier, "a+t")) != NULL) { /* le fichier est accessible */ fprintf(fichier,"%s, %d pages\n","Langage C",50); fclose(fichier); } else fprintf(stderr,"Ouverture de %s impossible \n",nomfichier); }

fwrite() : criture d'enregistrements dans le fichier Syntaxe : int fwrite(type_tampon *tampon, int longueur, int nombre, FILE *fichier); le tampon a le mme type que les enregistrements dans le fichier la longueur est obtenue avec sizeof(type_tampon) nombre est le nombre d'enregistrements crits la fois, fwrite() retourne le nombre d'enregistrements crits dans le fichier ou -1 en cas d'erreur. fread() : lire des enregistrements dans un fichier Syntaxe : int fread(type_tampon *tampon, int longueur, int nombre, FILE *fichier); le tampon a le mme type que les enregistrements dans le fichier la longueur est obtenue avec sizeof(type_tampon) nombre est le nombre d'enregistrements lus la fois, fread() retourne le nombre d'enregistrements lus dans le fichier ou -1 en cas d'erreur. fclose() : fermeture du fichier Syntaxe : int fclose(FILE *fichier); fclose() retourne 0, ou -1 en cas d'erreur. fseek() : dplacement de la tte de lecture sur le fichier Syntaxe : int fseek(FILE *fichier, long distance, int position); fseek() fait pointer le pointeur associ au fichier la position situe distance octets au-del de l'emplacement position. distance : diffrence en octets entre position d'origine du pointeur fichier et la nouvelle position. En mode texte, distance doit tre 0 ou une valeur renvoye par ftell(). position : une des trois positions d'origine pour le pointeur de fichier (Dbut : SEEK_SET, Curseur : SEEK_CUR, Fin : SEEK_END) L'opration suivant un appel fseek() sur un fichier ouvert en mode mise jour peut aussi bien tre une lecture qu'une criture. fseek() renvoie 0 si succs (pointeur repositionn), non 0 si chec. Voir aussi fgetpos(), fopen(), fsetpos(), ftell(), lseek(), rewind(), setbuf(), tell(). Exemple : Dterminer la taille d'un fichier
#include <stdio.h> long filesize(FILE *f); int main(void) { FILE *fichier; fichier= fopen( "biblio.txt", "a+t"); if (fichier != NULL) { fprintf(fichier,"%s, %d pages\n","Langage C",50); fprintf(fichier,"%s, %d pages\n","Algorithmique" ,80); printf("La taille du fichier %s est %ld octets\n", filesize(fichier)); fclose(fichier); } return (0); } long filesize(FILE *f) { long curpos, l; curpos = ftell(f); /* indique la position courante */ fseek(f, 0, SEEK_END); /* fin du fichier */ l = ftell(f); /* rcupre la position en octets */ fseek(f, curpos, SEEK_SET); /* replace la tte */ return (l); }

Jean Fruitet - IUT de Marne La Valle - 40

Introduction la programmation

Formatage des entres / sorties dans des fichiers : fprintf() et fscanf() Les fonctions fprintf() et de fscanf() permettent les sorties et les entres formates sur les fichiers. Elles s'emploient comme les fonctions printf() et scanf() en indiquant en plus la rfrence du flux trait. Exemple : Lecture d'un fichier de tempratures temp.dat
/* temp.dat --17/11/1997 13 18/11/1997 18 19/11/1997 17

--------------- */ #include <stdio.h> int main(void) { int temp; char jour[12]; FILE *ft;

ft=fopen("temp.dat", "rt"); if (ft==NULL) return(-1); /* erreur de lecture */ while (! feof(ft)) /* jusqu' la fin du fichier */ { fscanf(ft,"%s %d\n",jour,&temp); printf("La temprature du %s est %d degrs\n", jour, temp); } fclose(ft); return (0); }

Compilation La compilation de programmes en C s'effectue en plusieurs tapes. 1) Prcompilation Le prcompilateur supprime les commentaires des fichiers sources, inclut les fichiers #include et substitue les dfinitions #define dans tout le fichier <Source> (*.C) 2) Compilation (compile) Les fichiers sont alors recods en fichiers <Objet> (binaire) (*.OBJ). Les noms de fonctions sont remplacs par des tiquettes. 3) Liaison (link) Les diffrents fichiers objets sont ensuites "lis", c'est--dire que les tiquettes d'appel de fonctions sont remplaces par l'adresse de celles-ci dans leur propre fichier objet. On obtient un fichier excutable (*.EXE). La compilation est interrompue en cas d'erreur fatale. Les "warnings" sont des erreurs non fatales dont il faut tenir compte pour avoir un programme peu prs fiable et portable. Mais ce n'est pas parce que la compilation s'est passe sans erreur que le programme est correct. Le compilateur ne vrifie pas les dbordements de tableau (Range Check error), ni bien sr les erreurs d'allocation en mmoire dynamique ou la cohrence du programme. Interdpendance de fichiers Il est possible en C de partager un programme en plusieurs fichiers. Exemple de fichiers interdpendants.
TEST.H =========================== #define TRUE 1 #define FALSE 0 extern void test(char *msg); /* la fonction est dclare extern : son code de dfinition est dans un autre fichier */ TEST.C =========================== /* Code de la fonction test() Peut tre inclus dans une bibliothque (Library) test.lib avec l'utilitaire TLIB.EXE ou directement nomm dans le fichier projet (en TURBOC) */ Jean Fruitet - IUT de Marne La Valle - 41

Introduction la programmation #include <stdio.h> void test(char *msg) { printf("%s\n",msg); } DEMO.C ========================= /* --- Fichier Source du Programme Principal DEMO.C ---Programme excutable appelant la fonction test() Doit contenir une fonction main() */ #include <stdio.h> #include "test.h" /* dclaration de la fonction externe test() */ void main (void) { test("ceci est un test"); } =================================

Pour que la compilation se passe correctement, le compilateur doit pouvoir retrouver ses petits... En TURBOC sous diteur vous pouvez dfinir un fichier de PROJET (Alt P) associ DEMO.C qui indique les dpendances entre les diffrents fichiers du programme.
DEMO.PRJ ======================== demo.c (test.h) test.c =================================

COMPILATION : de test.c avec Alt C : compile to obj de demo.c avec F9

Jean Fruitet - IUT de Marne La Valle - 42

Introduction la programmation

Processus itratifs. Dans tous les exercices suivants, nous reprenons la mme mthode pour introduire de nouvelles notions de programmation : noncer un problme numrique, en donner un algorithme, le traduire dans les diffrents langages de programmation notre disposition. Exemple : Ecrire un programme qui affiche les 10 premiers nombres entiers naturels [0, 1, 2, .., 9]. 1. Rappels mathmatiques Lensemble des entiers naturels IN est infini. Il a un plus petit lment, not 0 ; tout lment a un successeur. Il ny a pas de plus grand lment. Les lments sont ordonns. IN={0, 1, 2, 3, 4, ..., n, (n+1), ...} Enoncer lensemble des entiers naturels nest pas une tche que puisse raliser un ordinateur, car cet ensemble est infini. Par contre il ny a pas de difficult noncer un sous-ensemble de IN. Il nous faut cependant introduire une recette de gnration des entiers, cest--dire un algorithme. Il est assez lgitime de considrer la construction de IN partir de son plus petit lment, 0, en appliquant laxiome tout lment a un successeur. Soit le premier lment 0 Dbut du processus successeur(0) = 0 + 1 == 1 successeur(1) = 1 + 1 == 2 successeur(2) = 2 + 1 == 3 .. successeur(8) = 8 + 1 == 9 Fin du processus. On a mis en vidence un processus rptitif, nous dirons itratif, selon un terme propre linformatique. Toute constante en membre droit dune affectation passe en membre gauche litration suivante. Nous devons rsoudre deux difficults. Initialiser le processus, puis linterrompre quand la borne 9 est atteinte, ce qui implique de compter le nombre ditrations. 2. Types de donnes et algorithmes Dfinissons les types de donnes qui seront utiliss. 0 et 1 sont des constantes numriques. Nous utilisons aussi deux oprateurs, laddition entre entiers et laffectation. Enfin il nous faut dfinir un compteur, qui comptera les itrations et permettra dinterrompre le processus. Ce programme pourrait donc se traduire par Initialiser un compteur 0. Tant que le compteur est infrieur 9, incrmenter le compteur de 1. Traduit de cette faon, le programme est un processus dynamique, cest--dire qui volue au cours du temps. Le compteur, une variable entire, prend successivement les valeurs 0, 1, .., 9. Laffichage de la valeur du compteur rpond au problme. Il reste traduire cet algorithme en programme (4) ce qui est fait la figure suivante.

4 Il faut insister ici sur le caractre trs spcial de linstruction daffectation qui se trouve dans la bote (1). Il ne sagit pas dune galit au sens mathmatique. On doit plutt la traduire par : le contenu de ladresse mmoire dsigne par lidentifieur compteur est augment de 1. Pour nous conformer la syntaxe du langage C nous reprsenterons dornavant laffectation (ou assignation) par le symbole =, et lgalite (comparaison) par ==. Jean Fruitet - IUT de Marne La Valle - 43

Introduction la programmation
ENTIER compteur; compteur=0;

Ecrire(compteur); compteur=compteur+1;

(1)

Traduit en langage de la machine RAM cela donne : ENTIER compteur; POUR (compteur=0 9) { ECRIRE(compteur); } FIN;

OUI
(compteur <= 9)

NON FIN DU PROGRAMME;

et en langage C:
#include <stdio.h> /* Fichier inclus : bibliothque des Entres/Sorties */

void main(void) /* Programme principal */ { int compteur; /* Dclaration */ for (compteur=0; compteur<10; compteur++) printf("%d \n",compteur); } /* Fin du programme */

Nous aurions videmment pu traduire cet algorithme en utilisant les structures de contrle TANT QUE (test) FAIRE instruction ; nous en laisserons le soin au lecteur. Fonctions et sous-programmes Lexercice suivant va introduire la notion de fonction en programmation. Certains problmes sont tellement complexes quil est prfrable de les dcomposer en sousproblmes. Cette forme de programmation, dite programmation descendante, sattache exprimer le cadre gnral de rsolution dun algorithme puis dtailler les sous-programmes rsolvant les questions techniques. Donnons un exemple. Exemple Ecrire un programme qui affiche les 10 premiers nombres premiers [2, 3, 5, 7,.., 29]. Comme convenu, commenons par un rappel mathmatique. Un nombre premier est un nombre entier naturel qui nest divisible que par 1 et par lui-mme (1 nest pas considr comme premier). Rsoudre lexercice peut se traduire premire vue par : TANT QUE (compteur<10) { Gnrer_un_nouvel_entier_premier; Incrmenter(compteur); } Le sous-programme Gnrer_un_nouvel_entier_premier; ncessite dtre formul plus prcisment : tant donn un nombre (ventuellement premier), il sagit de trouver le nombre premier immdiatement suprieur. nombre=1; TANT QUE (compteur<10) { nombre = Gnre_premier_suivant(nombre); Incrmenter(compteur); } ce qui, traduit en langage graphique, donne
Jean Fruitet - IUT de Marne La Valle - 44

Introduction la programmation
ENTIER compteur; compteur=0; ENTIER nombre; nombre=1; nombre = GENERE_PREMIER_SUIVANT (nombre); compteur=compteur+1;

(1)

OUI
(compteur <= 9)

NON FIN DU PROGRAMME;

La boucle est triviale, peu de chose prs cest celle de lexercice prcdent, avec un compteur comptabilisant les nombres premiers gnrs. Par contre le sous-programme de la bote (1), gnrant des nombres premiers, doit maintenant tre prcis. Pour tester si un nombre nest pas premier, il suffit de lui trouver un diviseur autre que 1 et luimme. Ainsi lexception du nombre entier 2, tous les nombres pairs sont non premiers ; idem des multiples de 3, 5, 7, etc. Cest le crible dEratosthne, qui consiste liminer les multiples dun nombre premier de la liste des nombres entiers. A la fin seuls les nombres premiers subsistent. Mais ce procd ne convient pas un ordinateur, car llimination des nombres pairs est en soi un processus infini. Il faut utiliser une autre mthode, tester par exemple pour chaque nombre sil est divisible par lun de ses prdcesseurs infrieurs n (ou infrieurs ou gaux n pour gagner quelques itrations)... Cet algorithme nest pas trs efficace, mais il est simple programmer. Il fait appel une fonction qui retourne VRAI si un nombre est premier, FAUX sinon. On introduit ici la notion de fonction, qui par construction est un sous-programme retournant une valeur dun type lmentaire (entier, rel, boolen, caractre, numr, pointeur). Programmons donc la fonction GENERE_PREMIER_SUIVANT(n) qui retourne le nombre premier strictement suprieur n :
ENTIER GENERE_PREMIER_SUIVANT(ENTIER n) n n=n+1;

NON
(2)

(PREMIER(n)) OUI RETOUR(n);

Le test (2) fait appel une fonction, PREMIER(n), qu'il nous faut programmer. Cette fonction retourne VRAI si n est premier et retourne FAUX sinon, elle est donc de type BOOLEEN, c'est pourquoi elle est utilisable dans le test. Lalgorithme de cette fonction consiste rechercher si une division par un entier compris entre 1 et n 2, 3, etc. tombe juste...

Jean Fruitet - IUT de Marne La Valle - 45

Introduction la programmation

BOOLEEN premier(ENTIER n)
ENTIER diviseur; diviseur=1;

NON
diviseur=diviseur+1;

(diviseur<n)

RETOUR(VRAI);

OUI

NON
((n MODULO diviseur)==0)

(3)

OUI RETOUR(FAUX);

En langage RAM ces fonctions scrivent :


BOOLEEN premier (ENTIER n) /* n est un entier strictement suprieur 1 */ { ENTIER diviseur; diviseur = 2; TANT QUE (diviseur < n) { SI ((n MODULO diviseur)==0) RETOUR (FAUX); SINON diviseur = diviseur + 1; } RETOUR(VRAI); } ENTIER genere_premier_suivant (ENTIER n) /* retourne le nombre premier strictement suprieur n */ { n = n + 1; TANT QUE ( NON premier(n)) n= n + 1; RETOUR(n); } PROGRAMME Liste_10_Premiers_Version1 { ENTIER nombre, compteur; nombre=1; compteur=0; TANT QUE (compteur < 10) { nombre=genere_premier_suivant(nombre); ECRIRE(nombre); compteur=compteur+1; }

Jean Fruitet - IUT de Marne La Valle - 46

Introduction la programmation

Ce programme est donc trs proche de celui de la gnration des dix premiers entiers tudi auparavant. Seule la ligne nombre=GENERE_PREMIER_SUIVANT(nombre); est modifie. C'est bien sr elle qui fait presque tout le travail ! Expliquons en dtail sa syntaxe... GENERE_PREMIER_SUIVANT(nombre) est une fonction. Elle reoit en paramtre d'entre un nombre entier qui doit tre suprieur 0. Elle calcule son successeur, (n+1), teste la primalit de ce nombre et retourne ce nombre si le test russit ; sinon le successeur est test, jusqu'au succs du test. Le succs est garanti car la suite des nombres premiers na pas de majorant... Le nombre ainsi gnr est retourn au programme appelant et plac dans la case mmoire dsigne par l'identifieur 'nombre'. L'instruction ECRIRE(nombre) affiche ensuite ce rsultat. Simplification du programme Aprs avoir minutieusement dtaill ce programme, nous pouvons essayer de le simplifier. Remarquons d'abord que la fonction GENERE_PREMIER_SUIVANT () est une simple boucle qui peut tre remplace par une instruction et un test. Le programme devient :
PROGRAMME Liste_10_Premiers_Version2 { ENTIER nombre, compteur; nombre=1; compteur=0; TANT QUE (compteur < 10) { nombre=nombre + 1; SI (premier(nombre)) ECRIRE(nombre); compteur=compteur+1; }

Puis, en considrant qu'au del de 3, les valeurs successives de n sont des nombres impairs on peut rcrire ce programme :
PROGRAMME Liste_10_Premiers_version3 { ENTIER nombre, compteur; nombre=3; compteur=2; ECRIRE(2); ECRIRE(3); TANT QUE (compteur < 10) { nombre=nombre + 2; SI (premier(nombre)) ECRIRE(nombre); compteur=compteur+1; }

C'est la version que nous traduisons en Langage C.


/* Liste des dix premiers nombres premiers */ /* Fichier Prem_10.c */ #include <stdio.h> #define VRAI 1 #define FAUX 0 int premier(int n); /* n strictement suprieur 1 retourne VRAI si n est premier */ void main(void) /* Programme principal */ { int compteur, nombre; /* Dclarations */ nombre = 3; compteur = 2;

Jean Fruitet - IUT de Marne La Valle - 47

printf("10 nombres premiers : 2, 3, "); while (compteur < 10) { nombre++; if (premier(nombre)) { compteur++; printf("%d, ",nombre); } } } /* Fin du programme */

Introduction la programmation int premier(int n) /* assume que n>1 *) { int diviseur=2; while (diviseur < n) { if ((n % diviseur)==0) return(FAUX); else diviseur++; } return(VRAI); }

Ce programme peut tre amlior en recherchant les diviseurs de n infrieurs Racine(n). Nous laisserons le lecteur sy exercer... Notion de complexit. Amlioration dun algorithme. Nous avons observ dans le calcul des nombres premiers quun algorithme pouvait tre parfois amlior en tirant partie de certaines proprits. Cela nous amne a prciser la notion defficacit dun algorithme. Par dfinition, on appelle complexit en temps le nombre dinstructions lmentaires mises en oeuvre dans un algorithme. Une instruction lmentaire sera une affectation, un comparaison, un saut. Lvaluation dune expression, par exemple, nombre = indice * 2 + 1; est dcomposable en une multiplication, une addition et une assignation, soit trois instructions. Mais comme le dcompte prcis de toutes les instructions dun programme risque dtre assez pnible, et quentre deux excutions du mme algorithme avec un jeu de paramtres diffrent, le nombre dinstructions excutes peut changer, on se contentera en gnral dapprcier un ordre de grandeur de ce nombre dinstructions. Cest ce quon dsignera sous le terme de complexit en temps de lalgorithme. (deux instructions lmentaires tant supposes avoir la mme dure). Exemple : Programmer une fonction qui retourne le PGCD de deux entiers naturels non nuls. Pour trouver le plus grand commun diviseur de deux entiers a et b non nuls il suffit de lister les diviseurs de a qui divisent b et den trouver le plus grand. Par exemple pour a=12 et b=18 on trouve D12= {1, 2, 3, 4, 6, 12} ; D18= {1, 2, 3, 6, 9, 18} soit le pgcd(12,18)=6. Programmons cet algorithme. ENTIER pgc_diviseur (ENTIER a, ENTIER b) /* on considre que a>0; b>0; a<=b */ {ENTIER diviseur , pgcd; POUR (diviseur=1 A a) FAIRE SI ((a MODULO diviseur)==0) ALORS SI ((b MODULO diviseur)==0) ALORS pgcd = diviseur; RETOUR(pgcd); } Evaluons la complexit de cet algorithme sur un jeu de donnes. Les cas considrer sont : a et b premiers entre eux ; a diviseur de b ; a et b non premiers entre eux sans quaucun ne soit diviseur de lautre ; Notons entre parenthses () le nombre dinstructions. Un test sur le modulo compte pour 3 car il faut lvaluer, comparer sa valeur 0 et faire un saut.
Jean Fruitet - IUT de Marne La Valle - 48

a 3

b 4

a 3

b 6

a 4

b 6

Introduction la programmation diviseur (a% div.) (b% div.) pgcd Instructions 1 (1) 0 (3) 0 (3) 1 (1) (8) 2 (1) 1 (3) (4) 3 (1) 0 (3) 1 (3) RETOUR 1 (5) (1) Total (17) diviseur (a% div.) (b% div.) pgcd 1 (1) 0 (3) 0 (3) 1 (1) (8) 2 (1) 1 (3) (4) 3 (1) 0 (3) 0 (3) 3 (1) RETOUR 3 (8) (1) Total (20) diviseur (a% div.) (b% div.) pgcd 1 (1) 0 (3) 0 (3) 1 (1) (8) 2 (1) 0 (3) 0 (3) 2 (1) (4) 3 (1) 1 (3) (4) 4 (1) 0 (3) 1 (3) RETOUR 2 (8) (1) Total (24)

On peut aussi envisager les cas limites : a=1 et b>1 : le pgcd retourn est 1 aprs 8 instructions. a=b : le pgcd retourn est a, et le nombre dinstructions est de lordre de a*6, si on considre quen moyenne il y a 6 instructions par ligne du tableau. On voit sur cet exemple que la complexit de lalgorithme est proportionnelle au nombre de boucles effectues dans linstruction POUR (diviseur=1 A a) FAIRE ... qui dpend du plus petit des deux nombres a et b, chaque boucle cotant entre 4 et 8 instructions, selon le rsultat du modulo. On dira que cet algorithme est en O(n) -prononcer GRAND O de n- cest--dire dune complexit linaire, avec n le plus petit des deux entiers considrs. Amlioration de lalgorithme. Considrant que le PGCD est le plus grand des diviseurs communs il suffit de renverser lordre de parcours de la boucle et de sarrter ds quun diviseur commun est trouv. Lalgorithme devient : ENTIER pgc_diviseur (ENTIER a, ENTIER b) /* on considre que a>0; b>0; a<=b */ {ENTIER diviseur = a; TANT QUE (diviseur>=1) FAIRE { SI ((a MODULO diviseur)==0) ALORS SI ((b MODULO diviseur)==0) ALORS RETOUR(diviseur); diviseur = diviseur -1; } } Si a est diviseur de b, cet algorithme produit la rponse au premier tour de boucle ; sinon sa complexit est en moyenne meilleure, sauf pour les nombres premiers entre eux, pour lesquels il ny a aucun gain. En conclusion, dans le moins favorable des cas les deux algorithmes sont dune complexit en O(n).

Jean Fruitet - IUT de Marne La Valle - 49

Introduction la programmation

Des donnes aux structures de donnes Le programme de gnration des nombres premiers peut tre grandement amlior si plutt que de rediviser tous les nombres par leurs prdcesseurs on emploie les nombres premiers dj trouvs comme diviseurs. Autrement dit si dans la fonction premier(nombre) ce sont des nombres premiers qui sont les diviseurs tests. Cela suppose de ranger en mmoire la liste des nombres premiers au fur et mesure quils sont gnrs. Mais la solution qui consisterait dfinir au pralable autant de variables que de nombres trouver nest ni lgante ni pratique. Un tableau dentiers est une structure de donnes bien adapte nos besoins. Tableaux. Le terme de tableau a une signification spciale en informatique. Au sens mathmatique usuel du terme, un tableau est une matrice de nombres, cest--dire un objet deux dimensions (lignes et colonnes), le mot vecteur tant rserv aux objets reprsentables par une liste de coordonnes, cest-dire la liste des nombres (scalaires) obtenus par projection du vecteur sur chacun des axes de lespace considr. En informatique, ce mme objet est dnomm tableau une dimension, une matrice tant assimile un tableau deux dimensions. Et bien sr la notion peut se gnraliser aux tableaux d dimensions. Mais quel que soit le nombre de dimensions, tous les tableaux informatiques sont des objets destins stocker des donnes informatiques en mmoire de lordinateur. Par dfinition un tableau de n lments est une collection de n cellules mmoires conscutives, de mme type (de la mme taille). La premire cellule du tableau reoit ladresse 0, la suivante ladresse 1, etc. Les n cellules sont donc indexes de 0 n-1. Ladressage direct des lments dun tableau permet daccder en temps constant chacun deux, sans quil soit ncessaire de parcourir toutes les cellules prcdant celle quon veut consulter.
Un tableau une dimension est un vecteur

12
0 1

9
2

13

...
6

5
7

15

Liste des notes de llve Dupont

Un tableau deux dimensions est une matrice


0 1 2 3 Colonne 4 0 Ligne 1

10 20 30

0 90 20

0 0 10

0 40 20

0 0 50

0 0 0

La cellule dadresse (1,3) contient la valeur 40.

Jean Fruitet - IUT de Marne La Valle - 50

Introduction la programmation

Tableau trois dimensions


0 Colonne Ligne 0 1 1

10 10 10

10 10 10

10 10 10

Profondeur

Dclaration dun tableau. Avant toute utilisation dans un programme, les structures de donnes doivent tre dclares au compilateur. Selon le langage de programmation, cette dclaration prend diffrentes formes. Le principe tant de fournir au compilateur une indication de lespace mmoire qui sera rserv au stockage des donnes. Nous verrons plus loin que le type dun tableau nest pas ncessairement un type simple. Il faut donc distinguer la dclaration du type lmentaire (une cellule) et celle du tableau compos de ces mmes cellules (qui est aussi le type du tableau). Un tableau est une suite de cellules conscutives en mmoire
Contenu de la cellule

B
0 1 Dbut du tableau

o
2

n
3

n
4

Adresse de la cellule

Chaque cellule peut contenir une variable du type de la cellule. Exemple : En langage RAM, un tableau dentiers de 100 cellules sera dclar : ENTIER table_entier[100]; tab1e_entier est un identifieur, dont la syntaxe doit respecter la syntaxe des noms de variables. 100 est ncessairement une constante numrique entire. ENTIER est un mot rserv caractrisant le type du tableau. On retrouve une dclaration similaire en langage C : int table_entier[100]; Il faut insister ici sur le caractre statique dune telle dclaration. En effet il nest pas possible en cours dexcution du programme de modifier la taille du tableau, mme sil savre que lespace rserv est insuffisant. Tableau de tableaux On a dit quun tableau est constitu de cellules contiges en mmoire qui peuvent elles-mmes tre dun type non simple. Exemple : Dclaration dun tableau de tableaux de rels. Soit par exemple stocker les 10 notes obtenues en informatique par 30 tudiants. Les dclarations suivantes sont quivalentes en espace mmoire : REEL notes_eleves[30][10]; REEL eleves_notes[10][30]; Dans le premier cas on considre un tableau deux dimensions de rels constitu par 30 lignes de 10 colonnes ; dans le second cas de 10 lignes de 30 colonnes.

Jean Fruitet - IUT de Marne La Valle - 51

Introduction la programmation

Assignation un tableau Assigner une valeur un tableau cest placer cette valeur dans une cellule disponible du tableau. Pour cela on dispose du mcanisme dindexation. Chaque cellule est dsigne par son indice, cest-dire son rang partir de la premire cellule, qui elle a lindice 0 (5). Exemple : Placer les 5 premiers nombres impairs dans un tableau dentiers. { ENTIER tab[5]; ENTIER indice; POUR (indice=0 4) FAIRE tab[indice] = (indice * 2) + 1; } En fin de processus le tableau contient [1, 3, 5, 7, 9]. La premire cellule est tab[0] ; elle vaut 1. La cellule tab[3] contient 7. Exercice Ecrire en C un programme qui range les 100 premiers nombres premiers dans un tableau. Algorithme : Initialiser le tableau 2, 3, 5, 7 puis gnrer la suite des nombres entiers impairs, en testant pour chaque nombre sil est divisible par lun de ses prdcesseurs premiers rangs dans le tableau et infrieur ou gal Racine(n) (justifiez dabord cet algorithme).
Corrig /* Nombres premiers */ #include <stdio.h> #include <math.h> /* F. Mathma. */ #define MAXTAB 100 void main(void) /* Programme principal */ { int i=4, j, n=9; int premier[MAXTAB]={2,3,5,7,}; /* Dclarations */ printf("2, 3, 5, 7,"); do { j=0; while ((n%premier[j]) && (premier[j]<=sqrt(n)) && (j<i)) j++; if (n%premier[j]) { printf(" %d,",n); premier[i++]=n; } n+=2; } while (i<MAXTAB); } /* Fin du programme */

Nous conserverons la convention du langage C qui est de numroter 0 la premire cellule.Par consquent pour un tableau de 10 cellules, la dernire a lindice 9. Jean Fruitet - IUT de Marne La Valle - 52

Introduction la programmation

Calcul matriciel (6) Une matrice relle est un tableau deux dimensions M x N (M lignes et N colonnes) d'lments de type flottant. Un vecteur rel est une matrice relle une dimension Nx1 (vecteur colonne de N lignes et 1 colonne) ou 1xN (vecteur ligne de 1 ligne et N colonnes). Une matrice carre relle d'ordre N est un tableau NxN deux dimensions, dont le nombre de lignes et de colonnes sont gaux N. Un certain nombre d'oprations algbriques sont dfinies sur les matrices, selon les tailles respectives des lignes et des colonnes : - somme et diffrence de matrices de mme dimension et de mme taille ; - produit d'une matrice MxN par un vecteur colonne Nx1 ; - produit d'un vecteur ligne 1xN par une matrice NxM ; - produit d'une matrice MxN par une matrice NxP ; - triangularisation d'une matrice ; - diagonalisation ; - transposition ; - inversion, - puissance d'une matrice carre ; - calcul du dterminant d'une matrice. Le calcul matriciel ayant normment d'applications importantes, nous prsentons quelques algorithmes et des reprsentations informatiques de matrices. Oprations sur les matrices Type de donnes matrice Une matrice NxM est un tableau de flottants deux dimensions #define MAXLIGNE 5 #define MAXCOL 3 typedef float mat_MxN[MAXLIG][MAXCOL]; Une matrice carre d'ordre N est un tableau de flottants #define ORDRE 5 typedef float mat_carree[ORDRE][ORDRE]; Un vecteur ligne est une matrice une dimension #define MAXELEMENT 10 typedef float vecteur_1xN[MAXELEMENT]; Un vecteur colonne est aussi une matrice une dimension, mais ce sont les lments d'une colonne qui sont rangs dans le tableau ! On peut aussi transformer les matrices NxM en un tableau une dimension, de taille N*M, structure bien adapte pour reprsenter aussi bien les matrices MxN que NxM, mais avec l'inconvnient important d'avoir grer l'adressage dans le tableau, m[i][j] devant alors s'crire m[i*MAXCOL+j]. #define MAXLIGNE 5 #define MAXCOL 3 typedef float m[MAXLIG * MAXCOL];

6 Ce chapitre est repris in extenso de l'excellent ouvrage de Cohen J.H., Joutel F., Cordier Y., Jech B. "Turbo Pascal, initiation et applications scientifiques", Ellipses, 1989. J'ai seulement traduit les programmes en C. Jean Fruitet - IUT de Marne La Valle - 53

Introduction la programmation

On aura intrt dans tous les cas dfinir un type structur contenant la fois le tableau des donnes et la dimension de la matrice. Par exemple on pourra aussi bien reprsenter
1.0 -1.4 0.0 0.0 1.2 0.9 0.0 0.0 0.5 2.1 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.2 0.9 0.0 0.0 0.5 2.1 -3.5 0.0 -5.1 0.7 4.0 1.0

avec la mme structure de donnes.


#define MAXLIGNE 4 #define MAXCOL 4 typedef struct matrice { int l; int c; float m[MAXLIGNE] [MAXCOL]; }t_matrice;

Avec cette mthode la premire matrice 2x3 est dclare et initialise par :
matrice mat_2x3 = {2, 3, {1.0, 1.2, 0.5, 0.0, -1.4, 0.9, 2.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};

Bien sr toutes les valeurs ne sont pas significatives, mais le tableau de donnes doit tre complt avec des valeurs nulles, et c'est par programme qu'on se restreint aux lignes et colonnes utiles... Produit de deux matrices Il suffit de trois boucles imbriques pour calculer le produit de deux matrices. Avant appel il faut rserver l'espace mmoire pour la matrice produit
z = (t_matrice *) calloc(1, sizeof (t_matrice)); /* Produit de deux matrices */ /* D'aprs Cohen J.H., Joutel F., Cordier Y., Jech B. "Turbo Pascal, initiation et applications scientifiques", Ellipses, 1989 */ #include <stdio.h> #include <conio.h> #define MAXLIGNE 4 #define MAXCOL 4 typedef struct matrice { int l; int c; double m[MAXLIGNE] [MAXCOL]; } t_matrice; t_matrice unite = {3, 3, { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}}; t_matrice x = {2, 0.5, 0.0, -1.4, 0.9, 0.0, 0.0, 0.0, 0.0, t_matrice y = {3, 0.5, 0.0, -1.4, 1.0, -0.5,-2.0, 0.0, 0.0, 3, { 1.0, 1.2, 2.1, 0.0, 0.0, 0.0, 0.0, 0.0}}; 3, { 1.0, 1.4, 2.0, 0.0, 1.0, 0.0, 0.0, 0.0}}; /* sources */ int produit_matrice (t_matrice *x, t_matrice *y, t_matrice *z) /* retourne 0 si erreur ; resultat dans z, dont l'allocation doit etre faite avant appel */ { int i, j, k; if (x->c != y->l) return (0); /* erreur produit impossible */ z->l=x->l; z->c=y->c; for (i=0; i < x->l; i++) for (k=0; k < y->c; k++) { z->m[i][k] = 0.0; for (j=0; j < x->c; j++) z->m[i][k]=z->m[i][k] + x->m[i][j] * y->m[j][k]; } return (1); } void affiche_matrice(t_matrice *x) { int i, j; printf("\t------\n"); for (i=0; i < x->l; i++) { printf("\t"); for (j=0; j < x->c; j++) { printf("%2.2f ",x->m[i][j]); } printf("\n",x->m[i][j]); } } Jean Fruitet - IUT de Marne La Valle - 54

/* prototype */ int produit_matrice (t_matrice *x, t_matrice *y, t_matrice *z); void affiche_matrice(t_matrice *x);

/* Programme principal */ void main (void) { t_matrice *z; clrscr(); affiche_matrice(&x); affiche_matrice(&y);

Introduction la programmation z = (t_matrice *) calloc(1, sizeof (t_matrice)); if (produit_matrice (&x, &y, z)) affiche_matrice(z); if (produit_matrice (&y, &x, z)) affiche_matrice(z); getch(); }

Puissance d'une matrice carre On peut utiliser l'algorithme dichotomique rcursif de calcul de la puissance entire d'un rel en l'adaptant au produit de matrices. Si n=0 xn = Identit Sinon si n est impair xn = x . xn/2 . xn/2 si n est pair xn = xn/2 . xn/2 Rsolution d'un systme d'quations (mthode de Cramer) Pour rsoudre un systme d'quations linaires Ax = b, o A est une matrice rgulire carre d'ordre N, et x et b des vecteurs colonnes N lignes, on transforme le systme originel par manipulation de lignes (mthode du pivot partiel) ou par manipulation de lignes et de colonnes (mthode du pivot de Gauss). Le systme d'quations obtenu est Tx = c o T est une matrice triangulaire qui possde les mmes solutions que le premier systme et se rsoud alors facilement par substitutions. La mthode du pivot partiel Soient A une matrice carre et x et b deux vecteurs colonnes. a11 ... a1n b1 x1 A = a21 ... a2n , b= b2 et x= x2 , . . . . an1 ... ann bn xn Si a11 est non nul, en multipliant la premire quation par les coefficients appropris et en retranchant les quations obtenues aux autres quations du systme, on obtient un systme quivalent, mais o x1 n'apparat plus que dans la premire quation: Eliminons x1 dans la ime quation. Multiplions la premire quation par (ai1/a11) et retranchons l'quation qui en rsulte cette quation, nous obtenons : ai2(1) * x2 + ai3(1) * x3 + ... + ain(1) * xn = bi(1) o aij(1) = aij - (ai1/a11) * a1j avec j {2, ..., n} et bi(1) = bi- (ai1/a11) * b1 Si, enfin, tous les lments de la premire colonne de A sont nuls, la matrice n'est pas rgulire et on s'arrte. Si tout s'est bien pass, on obtient un nouveau systme, quivalent au premier : A(1)x=b(1) avec a11(1) a12(1) ... a1n(1) (1) A = 0 a22(1) ... a2n(1) . . . (1) 0 an2 ... ann(1) a11(1) 0 s'appelle le pivot de la premire limination. On recommence alors l'opration sur le systme
Jean Fruitet - IUT de Marne La Valle - 55

Introduction la programmation

a22 . an2(1)

(1)

a2n . * (1) ann

(1)

x2 . xn

b2 . bn(1)

(1)

qui est un systme de Cramer, si la matrice A tait rgulire... On aboutit en n-1 tapes un systme triangulaire, avec les lments non nuls sur la diagonale : a11(1) a12(1) ... a1n(1) b1(1) 0 a22(2) ... a2n(2) * x2 = b2(2) . . . . . 0 0 ... ann(n-1) xn bn(n-1) o ann(n-1) aii(i) , (i {1, ..., n-1}), sont les pivots successifs des diffrentes liminations (le coefficient s'appelle aussi un pivot par souci de simplification). xn = (bn(n-1)) / (ann(n-1)) et xi = (bi(i) - j=i+1 aij(i)) / (aii(i)) avec i = n-1, n-2, .., 1

On rsout ce systme directement pour trouver la solution du systme de dpart.


n

En principe les pivots doivent tre simplement choisis parmi les lments non nuls de la premire colonne de la matrice considre, mais pour des raisons numriques, on prend l'lment qui possde la plus grande valeur absolue : en effet par exemple en supposant a11 non nul et en le chosissant comme pivot, on obtient comme nouveaux lments de la ime ligne : aij(1) = aij - (ai1/a11) * a1j avec j {2, ..., n} Les coefficients de la matrice A et du vecteur b pouvant tre des approximations (ce qui sera le cas si A et b proviennent d'une tape numrique antrieure), on obtient (en supposant que ai1 0) en ne considrant que les erreurs du premier ordre dues aux approximations : aij(1) = aij - (ai1/a11) ai1- (ai1/a11) a1j + (ai1 aij/a211) a11 = aij + (ai1/a11) (a1j a11/a11 - a11 ai1/ai1 - a1j) Le terme (ai1/a11) apparat donc comme un coefficient multiplicatif d'un terme dont un majorant de la valeur absolue est |a1j| ( |a11/a11| + |ai1/ai1|) + |a1j| est symtrique en a11 et ai1. En supposant, en outre, que les termes a1j et ai1 (j {2, ..., n}) ont des tailles et des incertitudes semblables, on a intrt prendre le rapport (ai1/a11) le plus petit possible en valeur absolue (une tude plus approfondie confortant ce choix). De plus, les lments de la matrice, dans l'une des tapes de l'limionation, sont obtenues par soustraction. On peut donc craindre que plus les coefficients sont petis, plus les erreurs relatives qui leur sont attaches sont importantes. Ces deux raisons qui se renforcent mutuellement, justifient le choix du pivot prconis. Pour amliorer la mthode on peut, c'est la mthode du pivot, chercher le plus grand lment, en valeur absolue, dans la matrice, et permuter les lignes et les colonnes pour l'amener en premire position. Algorithme Il y a deux tapes : triangularisation de la matrice de dpart (mthode du pivot partiel) puis rsolution d'un systme triangulaire d'quations. Rsolution
#define N 5 typedef double matrice_carree[N][N]; typedef double vecteur[N]; void resolution_triangulaire (int ordre, matrice_carree a, vecteur b, vecteur x) { Jean Fruitet - IUT de Marne La Valle - 56

Introduction la programmation int i, j; for (i=ordre-1; i>=0; i--) { for (j=i+1; j<ordre; j++) b [i] = b [i] - a[i][j] * x [j]; x[i] = b[i] / a[i][i]; } }

Triangularisation La triangularisation de la matrice est une tape pralable la rsolution d'un systme d'quations linaires. Implantation
/* Rsolution d'un systme d'quations Mthode du pivot partiel */ #include <stdio.h> #include <math.h> #include <conio.h> #define EPSILON 0.0000001 #define N 3 typedef float matrice[N][N]; typedef float vecteur[N]; matrice unite = { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; matrice a = { 1.0, 2.0, 3.0, 2.0, 3.0, 1.0, 3.0, 2.0, 1.0}; vecteur b = { 1.0, 1.0, 1.0}; /* Prototypes */ void affiche_matrice(int ordre, matrice x); void affiche_vecteur(int ordre, vecteur x); void affiche_systeme(int ordre, matrice a, vecteur b); void resolution_triangulaire (int ordre, matrice a, vecteur b, vecteur x); int gauss_partiel(int ordre, matrice a, vecteur b, vecteur x); /* Sources */ /* -------------------------------- */ void affiche_matrice(int ordre, matrice x) { int i, j; printf("\t------\n"); for (i=0; i < ordre; i++) { for (j=0; j < ordre; j++) printf("\t%2.3f ",x[i][j]); printf("\n"); } } /* -------------------------------- */ void affiche_vecteur(int ordre, vecteur x) { int i, j; printf("\t------\n"); for (i=0; i < ordre; i++) printf("\t%2.3f ",x[i]); printf("\n"); } /* -------------------------------- */ void affiche_systeme(int ordre, matrice a, vecteur b) { int i, j; printf("\n"); for (i=0; i < ordre; i++) { for (j=0; j < ordre; j++) { printf("\t%2.3f * x%d ",a[i][j], i); if (j<ordre-1)printf(" +"); } printf("= %2.3f\n",b[i]); } printf("\n"); } /* ------------------------------- */ void resolution_triangulaire (int ordre, matrice a, vecteur b, vecteur x) { int i, j; for (i=ordre-1; i>=0; i--) { for (j=i+1; j<ordre; j++) b [i] = b [i] - a[i][j] * x [j]; x[i] = b[i] / a[i][i]; } } /* -------------------------------- */ int gauss_partiel(int ordre, matrice a, vecteur b, vecteur x) Jean Fruitet - IUT de Marne La Valle - 57

/* triangularise et resout une systme d'quations lineaires ; la taille de la matrice carree est ordre x ordre ; Les entrees sont modifiees par effet de bord ! retourne 0 si erreur */ { int i, j, k, imax; float maxi, temp; for (k=0; k<ordre; k++) { imax = k; maxi = fabs(a[k][k]); /* recherche pivot dans colonne k */ for (i=k+1; i<ordre; i++) if (fabs(a[i][k]) > maxi) { imax = i; maxi = fabs(a[i][k]); } if (maxi < EPSILON) { for (i=0; i<ordre; i++) x[i] = 0.0 ; return (0); /* matrice singuliere */ } for (j=k; j<ordre; j++) /* echange de la ligne k et de la ligne imax */ { temp = a[k][j]; a[k][j] = a[imax][j]; a[imax][j] = temp; } temp = b[k]; b[k] = b[imax]; b[imax] = temp; /* second membre */

Introduction la programmation for (i= k+1; i<ordre; i++) /* eliminer dans la colonne k les termes sous la ligne k */ { temp = a[i][k] / a[k][k]; for (j=k; j< ordre; j++) a[i][j] = a[i][j] - a[k][j] * temp; b[i] = b[i] - b[k] * temp; } } /* matrice triangulaire superieure */ resolution_triangulaire (ordre, a, b, x); return (1); } /* -------------------------------- */ /* Programme principal */ void main (void) { vecteur x; clrscr(); printf("Systme rsoudre \n"); affiche_systeme(N, a, b); if (gauss_partiel(N, a, b, x)) { printf("Triangularisation\n"); affiche_matrice(N,a); affiche_vecteur(N,b); printf("Solution du systme \n"); affiche_vecteur(N, x); } getch(); }

Calcul du dterminant La mthode de Gauss permet galement de calculer le dterminant et l'inverse d'une matrice carre rgulire d'ordre N. En effet, changer deux lignes d'une matrice transforme le dterminant en son oppos ; ajouter une ligne une combinaison linaire des autres lignes ne modifie pas le dterminant. Ainsi, lorsque dans la mthode du pivot partiel on obtient une matrice triangulaire, le dterminant de celle-ci est, au signe prs, le dterminant de la matrice dont on tait parti ; ce signe dpend du nombre d'changes de lignes fait lors de la recherche des diffrents pivots : si p est ce nombre le dterminant cherch est le produit de (-1)p et des n pivots trouvs. Exercice : Ecrire la fonction double determinant(int ordre, matrice_carree x) qui calcule le dterminant d'une matrice carre d'ordre N par l'algorithme du pivot. Inversion de matrice Les manipulations des lignes d'une matrice reviennent multiplier celle-ci gauche par des matrices convenables. Il n'est pas difficile de prouver que le produit de ces matrices est la matrice inverse de la matrice de dpart lorsque par des manipulations de lignes on transforme cette matrice en l'identit. Pour effectuer ce produit (et en garder la trace) il suffit donc d'appliquer l'ensemble de ces manipulations la matrice identit : le rsultat final est bien ma matrice inverse cherche. Le code de la fonction
int matrice_inverse(int ordre, matrice_carree a, matrice_carre inv) se dduit donc directement de la fonction gausspartiel() : Jean Fruitet - IUT de Marne La Valle - 58

Introduction la programmation /* Rsolution d'un systme d'quations Mthode du pivot partiel */ #include <stdio.h> #include <math.h> #include <conio.h> #define EPSILON 0.0000001 #define N 3 typedef float matrice[N][N]; matrice unite = { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; matrice a = { 1.0, 2.0, 3.0, 2.0, 3.0, 1.0, 3.0, 2.0, 1.0}; /* Prototypes */ int produit_matrice (int ordre, matrice x, matrice y, matrice z); void affiche_matrice(int ordre, matrice x); int matrice_inverse(int ordre, matrice a, matrice inv); /* Sources */ /* ------------------------------ */ int produit_matrice (int ordre, matrice x, matrice y, matrice z) /* retourne 0 si erreur ; resultat dans z */ { int i, j, k; for (i=0; i < ordre; i++) for (k=0; k < ordre; k++) { z[i][k] = 0.0; for (j=0; j < ordre; j++) z[i][k] += x[i][j] * y[j][k]; } return (1); } /* ------------------------------ */ void affiche_matrice(int ordre, matrice x) { int i, j; printf("\t------\n"); for (i=0; i < ordre; i++) { for (j=0; j < ordre; j++) printf("\t%2.3f ",x[i][j]); printf("\n"); } } /* ----------------------------- */ int matrice_inverse(int ordre, matrice input, matrice inv) /* inversion de matrice par la methode du pivot ; la taille de la matrice carree est ordre x ordre ; la matrice entree est prserve ; retourne 0 si erreur */ { int i, j, k, imax; float maxi, temp; matrice a; /* recopie des entrees */ for (i=0; i<ordre; i++) for (j=0; j<ordre; j++) a[i][j] = input[i][j]; /* matrice inverse */ for (i=0; i<ordre; i++) for (j=0; j<ordre; j++) inv[i][j] = 0.0; for (i=0; i<ordre; i++) inv[i][i] = 1.0; /* matrice identite */ for (k=0; k<ordre; k++) { imax = k; maxi = a[k][k]; /* recherche pivot dans colonne k */ for (i=k+1; i<ordre; i++) if (fabs(a[i][k]) > fabs(maxi)) { imax = i; maxi = a[i][k]; } if (fabs(maxi) < EPSILON) { return (0); /* matrice singuliere */ } for (j=0; j<ordre; j++) /* echange ligne k et ligne imax */ { temp = a[k][j]; a[k][j] = a[imax][j]; a[imax][j] = temp; temp = inv[k][j]; inv[k][j] = inv[imax][j]; inv[imax][j] = temp; } for (j=0; j<ordre; j++) /* normalisation */ { a[k][j] = a[k][j] / maxi; inv[k][j] = inv[k][j] / maxi; } for (i=0; i<ordre; i++) /* eliminer dans la colonne k les termes hors diagonale */ if (i != k) { temp = a[i][k]; for (j=0; j< ordre; j++) { a[i][j] = a[i][j] - a[k][j] * temp; Jean Fruitet - IUT de Marne La Valle - 59

Introduction la programmation inv[i][j] = inv[i][j] inv[k][j] * temp; } } } return (1); } /* ---------------------------- */ /* Programme principal */ void main (void) { matrice inv; matrice z; int i, j, k; clrscr(); printf("Matrice inverser \n"); affiche_matrice(N, a); if (matrice_inverse(N, a, inv)) { printf("Matrice inverse \n"); affiche_matrice(N,inv); printf("Verification \n"); produit_matrice (N, a, inv, z); affiche_matrice(N,z); } getch(); }

Jean Fruitet - IUT de Marne La Valle - 60

Introduction la programmation

Calcul numrique et programmation de fonctions mathmatiques Jusqu prsent pour prsenter les concepts fondamentaux ditration, instruction conditionnelle et dcomposition en sous-programmes nous avons trait de problmes d'arithmtiques et d'algbre. Abordons maintenant quelques notions de calcul numrique. Cela pourra paratre paradoxal mais lordinateur, qui fut conu comme un calculateur numrique, nest pas vraiment loutil idal pour effectuer des calculs. Ou plutt lordinateur tout faire dusage courant nest pas adapt aux calculs trs prcis sur les trs grands nombres. Cela vient des limitations en espace mmoire et du mode de reprsentation des nombres en binaire. Mais ce dfaut nest pas propre lordinateur. Par exemple le nombre (1/3) na pas de reprsentation dcimale exacte, ce qui ne nous empche pas de calculer 15 * 0,3333. Bien sr il vaudrait mieux calculer 15/3 = (5*3) / 3 = 5 * (3/3) = 5... Il faudra donc distinguer entre calculs formels, qui mettent en jeu des expressions algbriques, et calculs numriques, qui utilisent des approximations binaires (retranscrites en dcimal laffichage). En ce sens lordinateur calculateur est mieux adapt lvaluation de grandeurs physiques (ventuellement approches) quau calcul mathmatique exact, bien que des programmes comme Mathematica ou Maple soient spcialiss en calcul formel. Je renvoie le lecteur son cours dinformatique pour les questions de codage des nombres en binaire. Le programmeur devra toujours avoir lesprit (et prendre en compte dans ses programmes) que lintervalle de dfinition des entiers sur 2 octets est [-32768 .. 32767] et que les nombres rels ne sont que partiellement reprsents par le type FLOTTANT, cest--dire par un couple (mantisse, exposant) de longueurs fixes. Commenons par un exercice de calcul numrique simple : Exercice Ecrire en C un programme qui range 10 nombres rels saisis au clavier dans un tableau, puis en affiche le minimum, le maximum, la moyenne et lcart-type. Rappels : La moyenne (ou esprance) dune distribution (Xi) sobtient en calculant

1 n 1 x = xi n i =0
n 1

Lcart type est la racine carre de la variance :

1 = n

(x i x ) 2 i =0

Le minimum (respectivement le maximum) dune distribution est la grandeur Xmin (Xmax) qui est infrieure (respectivement suprieure) ou gale toutes les autres valeurs Xi. La seule difficult de lexercice consiste dfinir correctement les structures de donnes permettant : 1) de stocker la distribution en mmoire REEL tab[10]; et en langage C float tab[10]; 2) restituer les grandeurs demandes. REEL moyenne(); float moyenne(); REEL min(); float min(); REEL max(); float max(); REEL sigma(); float sigma(); Le tableau de rels simpose. Mais le type rel ntant pas disponible en langage C, il faudra utiliser le type flottant (float). Pour que le programme conserve une certaine gnralit, on dfinira une
Jean Fruitet - IUT de Marne La Valle - 61

Introduction la programmation

constante entire TAILLE de valeur 10 et on crira les calculs sous forme de fonctions indpendantes lisant leurs entres dans la variable globale tableau[], recevant le nombre dlments du tableau en paramtre, et retournant un flottant.

Jean Fruitet - IUT de Marne La Valle - 62

Introduction la programmation Corrig /* Moyenne, Min, Max, Ecart-type de 10 nombres dcimaux rangs dans un tableau de flottants */ #include <stdio.h> #include <math.h> /* variables globales */ #define TAILLE 10 float tableau[TAILLE]; /* macro : carr de deux nombres */ #define CARRE(x) ((x)*(x)) /* prototypes */ float min_tab(int n); float max_tab(int n); float moyenne_tab(int n); float ecart_type_tab(int n); void main(void) /* Prog. principal */ { int a, i; /* variables locales */ printf("Entrez une liste de %d nombres rels \n", TAILLE); for (i=0; i<TAILLE; i++) scanf("%f",&tableau[i]); printf("Min : %f, MAX : %f, Moyenne : %f, Ecart-type : %f\n", min_tab(TAILLE), max_tab(TAILLE), moyenne_tab(TAILLE), ecart_type_tab(TAILLE)); } /* Fin du programme */ float min_tab(int n) { int i; float m = tableau[0]; for (i=1; i<n; i++) if (tableau[i]<m) m=tableau[i]; return (m); } float max_tab(int n) { int i; float m = tableau[0]; for (i=1; i<n; i++) if (tableau[i]>m) m=tableau[i]; return (m); } float moyenne_tab(int n) { int i; float m = 0.0; for (i=0; i<n; i++) m += tableau[i]; return (m/n); } float ecart_type_tab(int n) { int i; float m = moyenne_tab(n); float s=0.0; for (i=0; i<n; i++) s += CARRE(tableau[i] - m); return (sqrt(s)/n); }

Remarques La bibliothque mathmatique est indispensable pour la fonction sqrt() qui retourne la racine carre dun nombre flottant. La dclaration de constante #define TAILLE 10 permet de modifier aisment en une ligne la taille du tableau float tableau[TAILLE]. La dfinition de macro #define CARRE(x) ((x)*(x)) rend la lecture du programme plus claire. Les fonctions float min_tab(int n); float max_tab(int n); float moyenne_tab(int n); float ecart_type_tab(int n); calculent entre lindice 0 et lindice (n-1) du tableau, ce qui permet une certaine souplesse. Par contre il faudra veiller, si on reprend ces fonctions dans un autre programme, ce que le paramtre n ne soit jamais nul lappel de moyenne_tab (int n) et ecart_type_tab (int n) sous peine davoir une division par zro et larrt brutal du programme.

Jean Fruitet - IUT de Marne La Valle - 63

Introduction la programmation

Calcul des termes dune suite et problmes de dbordement Le calcul des termes dune suite numrique a dj t abord pour les nombres premiers. Si une suite est dfinie de faon rcurrente, le programme informatique est trivial. Par contre les problmes de dpassement de reprsentation des entiers peuvent rendre le calcul absurde. Voyons cela sur un exemple. Conjecture polonaise Ecrire un programme qui teste la conjecture polonaise : " La suite (ui) converge vers 1" avec u0= n entier strictement positif; SI (ui est pair) ui+1= ui/2; SINON ui+1= 3ui + 1; Considrons la suite (u0= 3) ; on obtient la suite (ui) = (3,10, 5, 16, 8, 4, 2, 1). Considrons la suite (u0= 7) ; on obtient la suite (ui) = (7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1). Considrons la suite (u0= 9) ; on obtient la suite (ui) = (9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1). Considrons la suite (u0= 15001) ; on obtient la suite (ui) = (15001, 45004, ...). 45004 est en dehors de lintervalle de dfinition des entiers sur deux octets [-32768.. 32767]. Donc mme si lalgorithme est correct, le calcul nest pas possible. Il faudrait programmer les oprations avec des entiers longs (4 octets), ce qui ne fait que repousser les difficults des nombres plus grands. Et lutilisation de nombres flottants ne rsoudrait rien. Fonctions rcursives Certaines suites ont une dfinition rcurrente qui se prte bien la programmation dite rcursive. Factorielle Programmer factorielle(n) note (n!) dfinie par : (0!) = 1; (1!) = 1; (2!) = 2 x (1!); ...; n!= n x ((n-1)!) Cela se traduit directement en langage C par int factorielle (int n) { if (n<=1) return(1); else return(n * factorielle(n-1)); } Nous dirons que la fonction factorielle est une fonction rcursive car sa dfinition contient un appel la fonction factorielle elle-mme. Une fonction rcursive doit contenir un test darrt de la rcursion, sinon elle entre dans une suite infinie dappels rcursifs (en pratique, jusqu ce que tout lespace mmoire disponible pour la pile des appels soit occup). Le test darrt pour la fonction factorielle est : if (n<=1) return(1); Ce type de programmation est trs naturel et nous aurons dautres occasions de lemployer. Malheureusement ce programme ne peut calculer au del de (7!), pour des questions de dpassement de reprsentation. On retombe l dans une situation dj voque.
Jean Fruitet - IUT de Marne La Valle - 64

Introduction la programmation

Exercices de programmation numrique Surface et volume dune sphre Ecrire un programme qui calcule et affiche la surface et le volume dune sphre au moyen des formules : Surface = 4 r 2 Volume = 4 r 3 /3 Pour la valeur de on pourra utiliser la fonction arctan(1) = /4. Polynme Evaluer le polynme suivant : y = (x-1)/x + 1/2 ((x-1)/x)2 + 1/3((x-1)/x)3 + 1/4 ((x-1)/x)4 Pour simplifier le programme, dfinir une variable U telle que : U= (x-1)/x. Racine carre dun nombre rel positif On peut calculer la racine carre de x par la formule itrative suivante : racine = (x / racine + racine) / 2. o la premire approximation de la racine est gale 1. Cette boucle est excute jusqu ce que la valeur absolue de (x / (racine * racine) -1) devienne infrieure un donn. Ecrire une fonction racine_carree (x) qui retourne la racine carre de x par cette mthode. Surface dun triangle La surface dun triangle peut se faire de la manire suivante : Surface = racine carre de(S (S-a) (S-b) (S-c)), avec S = (a+b+c) / 2 et a, b , c les cts du triangle. Ecrire un programme qui calcule et affiche la surface dun triangle aprs avoir lu les valeurs a, b et c. On pourra utiliser la fonction racine_carree() dfinie dans lexercice prcdent. Cette exercice ne prsente aucune difficult... Limite dune suite
i =

Sn =

Calculez la limite de la suite sachant que lon arrte lexcution lorsque

i2 i =1

S n+1 S n < avec un rel proche de zro .


1 = 1 ; S 12 1 = S n1 + n 2 1 1 = 1+ 2 4 2 1 1 1 1 + = 1+ + 2 4 4 9 3

Commenons par lanalyse de ce problme. Les premiers termes de la suite sont :


S S
1

= 1 +

; S

= 1+

On peut donc mettre en vidence une formule de rcurrence : quand

S i = S i1 +

1 i 2 . Le calcul sarrte

S n+1 S n

1 < < cest--dire quand n 2

Programmons cet exercice.


PROGRAMME suiteS(ENTIER n) Jean Fruitet - IUT de Marne La Valle - 65

Introduction la programmation { ENTIER i=1; REEL S=0.0; REEL EPSILON=0.000001; TANT QUE ((1/(i*i)>EPSILON) FAIRE { S=S + 1 / (i*i); i=i+1; } ECRIRE (S); }

Valeur approche de 2 /6

i =

Sn =

Vrifiez exprimentalement que Pour la valeur de on pourra utiliser la fonction arctan(1) = /4. Cet exercice est une variante du prcdent. Il suffit de tester la diffrence entre Sn et */6 jusqu ce quelle soit infrieure en valeur absolue un donn. Valeur approche de log(n)

i2 i =1

est une bonne approximation de 6 .

Sn =

Calculer une prcision fixe la diffrence entre la somme et Ln(n). Dans cet exercice, la convergence de Sn vers Ln(n) logarithme nprien de n nest pas du tout garantie. Il faut donc choisir soigneusement le test darrt, par exemple en vrifiant la croissance respective de la srie et de la fonction. Termes dune suite Ecrire un programme qui calcule et affiche les valeurs de la suite (un)n1 dfinie par (n donn par lutilisateur)

i i =1

u n = 1+ 2 + 3 + 4 + . .. + n
Contrairement lexercice prcdent, il ny a pas de formule de rcurrence immdiate entre les termes de la suite Un ; par contre il est facile dvaluer le n-ime terme de la suite par une itration avec un invariant de boucle sous le radical : U = n de i = n 1 faire

U = (i 1) + U Ce qui donne en langage RAM :


REEL suiteU(ENTIER n) { ENTIER i=n; REEL U=n; TANT QUE (i>0) FAIRE { U=(i-1)+U; i=i-1; } RETOUR (U); } PROGRAMME ListeUn(ENTIER n) { ENTIER i=1; REEL S=0.0; REEL EPSILON=0.000001; POUR (i=1 jusqu n) FAIRE { ECRIRE(suiteU(n); }
Jean Fruitet - IUT de Marne La Valle - 66

Introduction la programmation

} Puissance n-ime dun nombre Programmer une fonction Puissance(x,n) qui retourne la puissance entire positive n dun nombre rel x en tirant partie de la proprit : x0=1; xn=xp xp si n=2p et xn=x xp xp si n=2p+1 Estimer la complexit de lalgorithme. Cest un exemple de programmation rcursive. REEL Puissance (REEL x, ENTIER n) /* n entier positif ou nul */ { SI (n==0) RETOUR (1); SINON { SI ((n MODULO 2) == 0 ) RETOUR(Puissance(x, n/2) * Puissance(x, n/2)); SINON RETOUR(x * Puissance(x, n/2) * Puissance(x, n/2)); } } Chaque appel rcursif divisant le paramtre n par deux, il y a 2*log2(n) appels, soit une complexit en O(log2(n)), meilleure que celle du produit x*x..*x qui est en O(n). Nombre dor

Soit un-1 + un-2 pour n2.

1+ 5 2 le nombre dor et (un)n la suite de Fibonacci dfinie par u0 = 0, u1 = 1 et un =

n Ecrire un programme qui affiche n, un et 5


La suite de Fibonacci peut se programmer de faon rcursive.
ENTIER Fibonacci (ENTIER n) { SI (n==0) RETOUR(0); SINON SI (n==1) RETOUR (1); SINON RETOUR(Fibonacci(n-2) + Fibonacci(n-1)); }

n
On pourra utiliser la fonction Puissance(x,n) de lexercice prcdent pour calculer Nous laissons au lecteur le soin de vrifier la convergence des deux suites.

5.

Dcomposition dun cube en somme de nombres impairs Le mathmaticien grec Nikomakhos (1er sicle aprs JC) crit dans son Introduction Arithmtique que tout cube est gal la somme de nombres impairs conscutifs. Par exemple :
13 = 1 = 1 23 = 8 = 3 + 5 33 = 27 = 7 + 9 + 11 Jean Fruitet - IUT de Marne La Valle - 67

Introduction la programmation 43 = 64 = 31 + 33 = 1 + 3 + 5 + 7 + 9 + 11 + 13 = 13 + 15 + 17 + 19

Ecrire un programme qui lit un entier n et donne une dcomposition de n3 (on pourra utiliser une boucle TANT QUE et un BOOLEEN trouv qui indiquera que lon a trouv une solution). Le cas des cubes pairs est trivial, il suffit de dcomposer n3 en (n3/2 - 1) et (n3/2 +1). Pour les cubes impairs, on peut chercher dcomposer partir de 1 : S = (1 + 3 + ... + (2p-1) + (2p+1)) en incrmentant p jusqu ce que S n 3...En cas de dpassement, il faut alors liminer les nombres impairs les plus faibles gauche : S = ((2q-1) + (2q+1) + ... + (2p-1) + (2p+1)) jusqu ce que S n 3. En incrmentant successivement q et p on finit par atteindre n3 exactement. Rsolution de f(x)=0 (7) Soit f une fonction continue dans lintervalle [a,b] avec a<b et telle que f(a).f(b)<0 ; il existe donc un rel x compris strictement entre a et b vrifiant f(x) = 0. Trouver cette valeur x cest rsoudre lquation f(x)=0. Plusieurs mthodes numriques sy emploient. La mthode dichotomique est la plus simple programmer. Cependant le test darrt doit tre soigneusement slectionn pour viter les erreurs dues la reprsentation approche des nombres rels par des flottants... Mthode dichotomique Considrons c = (a+b) / 2. Si f(c).f(a) 0, il existe une racine de lquation dans lintervalle ]a, c], sinon il en existe une dans lintervalle ]c, b[. On recommence alors la recherche dans lintervalle qui contient srement une racine, intervalle dont la longueur est la moiti de celle de lintervalle de dpart. En un nombre fini dtapes, on arrive encadrer une racine de lquation par deux rels dont la diffrence est plus petite que la prcision demande pour la recherche.

f(b) f(c) a f(a) c b

y=f(x)

c = (a+b)/2. PROGRAMME Dichotomie(REEL a, REEL b, REEL epsilon) { REEL c; SI (f(a)*f(b)) < 0.0 { TANT QUE(b-a>epsilon) { c=(a+b) / 2;
7J.-H.

Cohen, F. Joutel, Y. Cordier, B. Jech, Turbo Pascal, initiation et applications scientifiques, Elipses, pp127Jean Fruitet - IUT de Marne La Valle - 68

131

Introduction la programmation

SI (f(a)*f(c)<=0.0) b=c; SINON a=c; } } } Linconvnient de cette mthode est que si f(x) est de croissance (respectivement dcroissance) lente la prcision sur x sera trs longue atteindre. Dautre part il peut se produire que (b/2) et (a/2) soient reprsents par le mme nombre flottant (la mme reprsentation binaire). En ce cas lalgorithme echoue ! On prfrera donc tester une valeur de f(x) proche de zro prs. Exercice : Programmer cet algorithme en Langage C pour les fonctions y= x5/100 et y=2sin(x)1 sur un intervalle convenable avec une prcision de 10-5. Indiquer le nombre ditrations.
/* Rsolution de f(x) = 0 */ /* Mthode Dichotomique */ /* f continue dans l'intervalle [a,b] et (f(a).f(b)<0 La mthode consiste calculer c= (a+b)/2 et f(c) et remplacer a par c si f(a).f(c)>=0, b par c sinon. */ #include <stdio.h> #include <math.h> #define EPSILON 0.00001 #define A -3.0 #define B 3.0 #define FONCTION(x) (pow((x),5.0) 1) /* expression de la fonction f(x) */ #define MSG_FONCTION "x5/100" /* texte de la fonction */ int main (void) { int d=0; float a=A, b=B, c; float fa, fb, fc; printf("Mthode dichotomique f(x)=%s\n\ta=%2.3f b=%2.3f\n",MSG_FONCTION,a,b); printf("Calcul EPSILON=%2.6f prs\n",EPSILON); fa=FONCTION(a); fb=FONCTION(b); if ((fa*fb)>=0.0) { printf("Mthode dichotomique inapplicable \n"); return(0); } do { d++; c = (a+b)/2.0; fc= FONCTION(c); /* printf("i:%d c:%f fc:%f",d,c,fc); */ if ((fa*fc) >= 0.0) { a = c; fa = fc; } else b = c; } while (fabs(fc)>EPSILON); printf("\n\t%d itrations, racine:%2.6f \n",d,c); return(1); }

Remarque : Pour rendre le programme plus souple on dfinit la fonction traiter sous forme de macro-instructions : #define EPSILON 0.00001 #define A -3.0 #define B 3.0 #define FONCTION(x) (pow((x),5.0) - 1) /* expression de la fonction f(x) */ #define MSG_FONCTION "x5/100" /* texte de la fonction */ Il suffit de modifier ces cinq ligne de programme pour traiter tout autre fonction. Mthode du balayage f continue dans lintervalle [a,b] et f(a)f(b)<0.
Jean Fruitet - IUT de Marne La Valle - 69

Introduction la programmation

La mthode consiste dterminer n intervalles sur [a,b], calculer c = a + k*(b-a)/n et d = a + (k+1)*(b-a)/n et f(c) et f(d) tant que f(c).f(d)>0 et remplacer a par c et b par d sinon. Mthode par balayage avec n=3
y=f(x)

f(b) f(d) f(c) a f(a) c d b

Mthode des parties proportionnelles Les mthodes de recherche par dichotomie convergent lentement. Pour les amliorer on essaie de trouver le point c qui partage lintervalle de dpart le plus prs possible dune racine de lquation. ba c = a f (a ) f (b) f (a) est un bon candidat, gal la racine si la fonction est On trouve que affine. f continue dans lintervalle [a,b] et f(a)f(b)<0. La mthode consiste calculer c, intersection de la droite ((a, f(a)), (b,f(b))) avec laxe des x ; puis f(c) et remplacer a par c si f(a).f(c) 0, b par c sinon.
Y

f(b) f(c) a f(a) c b

y=f(x)

Mthode de Newton La mthode de Newton abandonne lide de lencadrement, pour essayer daugmenter la vitesse de convergence. Cette mthode nassure plus la dcouverte systmatique de la racine, mais lorsquelle le fait elle est en gnral plus rapide que les mthodes prcdentes. Supposons f suffisament drivable. La formule de Taylor applique au point a scrit : h2 f (a + h ) = f (a) + hf ' (a) + f "(a + h), ]0, 1[ 2 Si on suppose que a+h est une racine, h est solution de lquation f(a+h) ; en supposant h f (a ) h = f ' (a ) suffisament petit , on en dduit, en premire approximation :
Jean Fruitet - IUT de Marne La Valle - 70

Introduction la programmation

On espre ainsi une aproximation dordre 2 en h de la racine (si f(a+h) est suffisament petit). Implantation f continue et drivable sur lintervalle [a,b]. Drive f de signe constant (0) sur ]a, b[ La mthode consiste construire la tangente T en B(b, f(b)) et prendre comme valeur approche de la racine lintersection de T avec laxe des X. b est remplac par cette valeur et on ritre le processus jusqu concidence.
Y

T
f(b) a c f(c) f(a) b X y=f(x)

/* Rsolution de f(x) = 0 */ /* Mthode de Newton */ #include <stdio.h> #include <math.h> #defineEPSILON0.00001 #defineA -3.0 #defineB 3.0 #defineFONCTION(x) (pow((x),5.0) - 1) /* A remplacer par la fonction calcule */ #defineDERIVEE(x) (5*pow((x),4.0)) /* A remplacer par drive calcule */ #defineMSG_FONCTION "(x^5 - 1)" /* A remplacer par texte de fonction */ /* prototype */ float intersection_tangente_x(float a, float fa, float dfa); void main (void) { int d=0; float a=A, b=B; float fb, dfb;

printf("Mthode de Newton f(x)=%s=0\n\t a=%2.3f b=%2.3f\n",MSG_FONCTION,a,b); printf("Calcul EPSILON=%2.6f prs\n",EPSILON); do { d++; fb= FONCTION(b); dfb=DERIVEE(b); if (dfb != 0.0) b = intersection_tangente_x(b,fb,dfb); else exit(0); } while (fabs(fb)>EPSILON); printf("\t%d itrations, racine:%2.6f \n",d,b); } float intersection_tangente_x(float a, float fa, float dfa) /* renvoie l'abscisse du point d'intersection de la droite passant par[(a, fa)] et de pente dfa, avec l'axe des x. Assume que dfa != 0 */ { return (a - fa / dfa); }

Jean Fruitet - IUT de Marne La Valle - 71

Introduction la programmation

Intgration numrique Soient a et b deux rels (a<b), f une fonction numrique continue sur [a,b] ; on cherche approximer

b a h= et x k = a + kh , n pour tout entier k compris entre 0 et n.


On a :

a f (t )dt .
a
b

Prenons une subdivision rgulire de [a,b] en n

intervalles

posons

f (t)dt =

x k =0

n1

x k+1
k

f (t)dt

Mthode des rectangles Appliquons la formule de la moyenne sur lintervalle [xk,xk+1], k[1, 2, 3, ..., n-1] :

k [ x k , x k +1 ] :

Le rel k tant en gnral inconnu, on cherche une approximation. La plus simple des approximations que lon peut faire est de choisir xk ou xk+1, cest la mthode communment appele mthode des rectangles (intressante quand la fonction est monotone, puisque lon obtient une borne de la valeur de lintgrale) ; une autre possibilit est (xk+xk+1)/2, qui est le centre de lintervalle (mthode des rectangles modifis) et on peut penser a priori que ce choix est meilleur puisque lincertitude est alors (xk-xk+1)/2 = h/2. On montre quun majorant de lerreur commise, en prenant comme valeur approche de lintgrale lune des valeurs hf(xk) ou hf(xk+1) , est h2M/2, o M est un majorant de f(en supposant f continment drivable, tandis que des mthodes danalyse plus labores montrent que le choix du milieu de lintervalle conduit une incertitude de h3M/24 o M est un majorant de f(sil existe). On voit donc que si la fonction est suffisamment rgulire, le choix du milieu est meilleur. En itrant cette approximation sur chaque subdivision, on obtient alors un majorant de lerreur totale qui est M(b-a)2/2n (mthode des rectangles ordinaires) et M(b-a)3/24n 2 (mthode des rectangles modifie). Mthode des rectangles ordinaires En prenant, par exemple, systmatiquement les bornes gauches des sous-intervalles, lapproximation est :

x k +1
k

f (t )dt = ( x k +1 x k ) f ( k )

f (a + kh )
k=0

n1

Mthode des rectangles modifie Lapproximation est ici :

f ( a + 2 + kh)
k=0

n1

Mthode des trapzes On approxime la fonction elle-mme par une fonction affine sur lintervalle [xk,xk+1], k[1, 2, 3, ..., n-1] (interpolation linaire) :
Jean Fruitet - IUT de Marne La Valle - 72

f (x ) = f1 ( x ) =

f ( x k +1 ) f ( x k ) ( x xk ) + f ( xk ) x k+1 x k
xk +1
k

Introduction la programmation

on pense alors obtenir :

x k+ 1
k

f (t) dt =

f 1 (t )dt = h

f ( x k ) + f ( x k +1 ) 2

On trouve quun majorant de lerreur faite est h3M/12 o M est une majorant de f (si f est de classe C2). En itrant lopration sur tout lintervalle [a,b], on obtient donc une incertitude totale M(b-a)3/12n 2. Lapproximation obtenue est donc :

1 h f (a ) + 2

n 1

f (a + kh ) + 2 f ( b) ) k=1
1

Mthode de Simpson Cest une gnralisation de la mthode des trapzes consistant approximer la fonction sur chaque sous-intervalle [xk,xk+1] de la subdivision par un polynme du second degr (interpolation de Lagrange avec les points xk, (xk+xk+1)/2 et xk+1). Interpolation (8) Supposons quen tudiant un certain phnomne, on ait dmontr lexistence dune dpendance fonctionnelle entre des grandeurs x et y exprimant laspect quantitatif de ce phnomne ; la fonction y=f(x) nest pas connue, mais on a tabli en procdant une srie dexpriences que la fonction y=f(x) prend respectivement les valeurs y0, y1, y2, y3, ..., yn quand on donne la variable indpendante les valeurs diffrentes x0, x1, x2, x3, ..., xn appartenant au segment [a, b]. Le problme qui se pose est de trouver une fonction aussi simple que possible (un polynme par exemple), qui soit lexpression exacte ou approche de la fonction inconnue y=f(x) sur le segment [a, b]. Dune manire plus gnrale le problme peut tre pos comme suit : la valeur de la fonction y=f(x) est donne par n + 1 points diffrents x0, x1, x2, x3, ..., xn du segment [a, b] : y0 = f(x0), y1 = f(x1), ..., yn = f(xn) ; on demande de trouver un polynme P(x) de degr n exprimant dune manire approche la fonction f(x). Il est tout naturel de choisir le polynme de manire quil prenne aux points x0, x1, x2, x3, ..., xn les valeurs y0, y1, y2, y3,. .., yn de la fonction f(x).
Y y=f(x)

y0

y1

yn
y=P(x)

ax x
0

x b

Ce problme, qui sappelle problme dinterpolation de la fonction, peut tre formul de la manire suivante : trouver pour une fonction donne f(x) un polynme P(x) de degr n qui prenne aux points x0, x1, x2, x3, ..., xn les valeurs y0 = f(x0), y1 = f(x1), ..., yn = f(xn). A cette fin, choisissons un polynme de degr n de la forme
8

N. Piskounov, Calcul diffrentiel et intgral, T1, Editions Mir, pp.264 Jean Fruitet - IUT de Marne La Valle - 73

P( x ) = C0 ( x x1 )( x x 2 ). . . ( x x n ) + C1 (x x 0 )( x x 2 ). . . ( x x n ) +

Introduction la programmation

dterminons les coefficients C 0 , C1 , . . ., Cn de manire que soient vrifies les conditions

+C 2 ( x x 0 )(x x 1 )(x x 3 ). . . ( x x n ) + C n ( x x1 )(x x 2 ). . . ( x x n1 ) (1) eet

P( x 0 ) = y 0 , P( x1 ) = y1 , . .. , P( x n ) = y n .

(2 )

Faisons dans la formule (1) x=x0 ; alors, en vertu des galits (2), nous avons :

y 0 = C0 ( x 0 x1 )(x 0 x 2 ).. .(x 0 x n ),


y0 ( x 0 x1 )(x 0 x 2 ). . . (x 0 x n )

do

C0 =

Faisons ensuite x=x1, nous avons :

y1 = C1 ( x 1 x 0 )( x1 x 2 ). . . (x 1 x n ) y1 (x 1 x 0 )( x1 x 2 ). . . ( x1 x n )

d' o C1 =

En procdant de cette manire, nous trouvons successivement y2 C2 = ( x 2 x 0 )( x 2 x1 ). .. (x 2 x n )

. .. . . . .. . .. .. . . . . .. yn Cn = ( x n x 0 )( x n x1 ). .. (x n x n1 )
En substituant les valeurs ainsi trouves des coefficients dans la formule (1) nous avons :

P( x ) =

( x x1 )( x x 2 ). .. ( x x n ) ( x x 0 )( x x 2 ). . . ( x x n ) y0 + y ( x 0 x1 )( x 0 x 1 ). .. ( x 0 x n ) ( x 1 x 0 )( x1 x 2 ). .. ( x 1 x n ) 1 ( x x 0 )( x x 1 ). .. ( x x n1 ) yn . ( x n x 0 )( x n x1 ). . . ( x n x n1 ) ( 3)

+. .. .. . . +

Cette formule est appele formule dinterpolation de Lagrange. Rappelons que si aux points considrs (x0, y0), (x1, y1), ..., (xn, yn), P(x) et f(x) concident, en tout autre point de lintervalle [a, b] il peut en aller tout autrement. Il existe dautres formules dinterpolations, dont celle de Newton. Pour programmer la formule dinterpolation de Lagrange il faut saisir les points (x0, y0), (x1, y1), ..., (xn, yn), dans un tableau de couples de flottants et calculer le tableau des coefficients.
/* Interpolation de Lagrange */ #include <stdio.h> #define MAXPOINT 10 float point2D[MAXPOINT][2]; /* tableau des coordonnes des points 2D */ float coeff_lagrange[MAXPOINT]; /* coefficients du polynme */ void saisie_points(int n) /* assume que les points saisis ont des abscisses diffrentes */ { int i; for (i=0; i<n; i++) { printf("Abscisse du point N %d:",i); scanf("%f",&point2D[i][0]); printf("Ordonne du point N %d:",i); scanf("%f",&point2D[i][1]); Jean Fruitet - IUT de Marne La Valle - 74

} } } int coefficients_lagrange(int n) /* le nombre de points est pass en paramtre */ /* retourne 0 en cas derreur */ { int i,j; float d_lagrange; for (i=0; i<n; i++) { d_lagrange = 1; for (j=0; j<n; j++) if (j!=i) d_lagrange*=(point2D[i][0]point2D[j][0]); if (d_lagrange != 0.0) coeff_lagrange[i]=point2D[i][1] / d_lagrange; else return (0); } return (1); } float affiche_lagrange(int n) /* Expression littrale du polynme */ { int i,j; printf("P(x)="); for (i=0; i<n-1; i++) { printf("(%f) ",coeff_lagrange[i]); for (j=0; j<n; j++) if (j!=i) printf("(x(%f))",point2D[j][0]); printf(" +\n"); } printf("(%f) ",coeff_lagrange[n1]); for (j=0; j<n-1; j++) printf("(x(%f))",point2D[j][0]);

Introduction la programmation printf("\n"); float polynome_lagrange(int n, float x) /* retourne la valeur du polynme pour une valeur x de la variable */ { int i,j; float c, p=0.0; for (i=0; i<n; i++) { c=coeff_lagrange[i]; for (j=0; j<n; j++) if (j!=i) c*=(x-point2D[j][0]); p+=c; } return(p); } void main (void) { int i,j,n; float x; printf("Interpolation polynmiale de Lagrange\n"); printf("Nombre de points interpoler [%d]\n" , MAXPOINT); scanf("%d",&n); saisie_points(n); if (coefficients_lagrange(n)) { /* Expression du polynme */ affiche_lagrange(n); /* Utilisation du polynme */ printf("Entrez une valeur pour la variable x \n"); scanf("%f",&x); printf("P(%f)=%f",x, polynome_lagrange(n,x)); } else printf("Erreur dans la saisie des points\n); }

Jean Fruitet - IUT de Marne La Valle - 75

Introduction la programmation

Structures de donnes Il est souvent ncessaire en programmation de stocker des informations complexes. Par exemple un rpertoire tlphonique. Chaque fiche rassemble les informations caractristiques dune entit, en loccurence une personne, nom, prnom, adresse, date de naissance, tlphone. Chaque champ dune fiche est un attribut, exactement dfini par son domaine (les valeurs acceptables), sa taille (espace mmoire occup), et sa valeur (ou occurence). Linformation est structure, puisque chaque fiche est organise dune manire fige. Le rpertoire tlphonique lui-mme est une collection de fiches de mme structure. [CHAMP] [TAILLE] Nom Prnom Adresse Date de nais. Tlphone 20 car. 10 car. 40 car. date 10 num. Dupont T. Moulinsart 28/2/1900 12 34 56 78 Dupond D. Moulinsac 24/12/1901 98 76 54 32 Chaque ligne (ou tuple) du tableau deux dimensions correspond une fiche. Structures Le type du langage C struct permet de reprsenter en machine la fiche que nous venons dvoquer (en Pascal lui correspond le type record enregistrement). struct fiche { char nom[20]; char prenom[10]; char adresse[40]; char ddn[6]; long tel; } personne; On peut aussi inclure dans la dfinition dune structure la rfrence dautres structures, par une sorte dimbrication. Par exemple prs avoir dfini un type de donnes date plus appropri, struct date { int jour; int mois; int annee; } ; sy rfrer dans la dfinition dun type fiche. struct fiche { char nom[20]; char prenom[10]; char adresse[40]; struct date ddn; char tel[10]; } personne; Une personne est alors une variable occupant 86 octets en mmoire (20+10+40+6+10). La mise jour de la fiche de Dupond D. est ralise par les instructions : strcmpy(personne.nom,Dupond); strcmpy(personne.prenom,D.); strcmpy(personne.adresse,Moulinsac); personne.ddn.jour=24; personne.ddn.mois=12; personne.ddn.annee=1901; strcmpy(personne.tel,98765432); Nous renvoyons le lecteur son cours de langage C pour les dtails de program-mation. Exercices Le type <Date> On considre le type <date> dfini par une structure C typedef struct date {int annee; int mois; int jour;} date; et la dclaration : date date_courante = (1997, 10, 26); 1) Quelles oprations sur ce type de donnes peut-on dfinir ?
Jean Fruitet - IUT de Marne La Valle - 76

Introduction la programmation

2) Est-il possible dadditionner deux dates ? Que signifierait : (1994, 10, 26) + (1994, 10, 26) ? 3) La diffrence de deux dates est une <dure> : long duree; /* exprime le nombre de jours entre deux dates */ duree = difference_date((1994, 10, 26), (1994, 09, 26)); duree = 30; /* en jours */ Connaissant la date de naissance dune personne et la date courante, il est possible dexprimer lge de cette personne en jours : age = difference_date(date_naissance, date_courante); Exercice 1: Ecrire en C les fonctions date *saisie_date(void); void affiche_date(date d); long difference_date(date d1, date d2); date *calcule_date(date d, long duree); date *ajoute_date_duree(date d, long duree); Exercice 2: Ecrire en C un programme qui calcule le calendrier. Exercice 3 : Dfinir le type de donne <heure> Le type <Nombre rationnel>. Dfinition Les nombres rationnels (ensemble Q) sont dfinis partir des entiers relatifs par une relation d'quivalence. Soient deux couples (a,b) et (c,d) d'entiers relatifs tels que b et d ne soient pas nuls. On appelle nombre rationnel q, not (a/b), la classe d'quivalence des couples de nombres entiers relatifs tels que : a*d = b*c Autrement dit on peut assimiler un nombre rationnel une fraction entire: a c = = q Q a d = c b avec a, b, c, d Z et b 0 et d 0 b d 1) Donnez lquivalent rationnel de deux tiers ; un quart ; 0,5 ; -0,3 2) Le nombre est-il un rationnel ? Estimez lerreur commise en prenant pour la fraction (22/7) ? 3) Quelles sont les oprations autorises sur les nombres rationnels ? On dfinit les oprations suivantes sur les rationnels : (a/b) * (c/d) = (a*c) / (b*d) (a/b) / (c/d) = (a*d) / (b*c) (a/b) + (c/d) = ((a*d) + (b*c)) / (b*d) (a/b) - (c/d) = ((a*d) - (b*c)) / (b*d) inverse(a/b)= b/a si a0, sinon indfini Q a une structure dordre Oprateurs de comparaison : > >=< <= |a/b| |c/d| si et seulement si |a*d| |b*c| si (a/b) ( c/d) alors ((-1)*(a/b)) ((-1) * (c/d)) Implmentation - Le couple (a,b) rationnel (a/b) est dfini par une structure en langage C : typedef struct {int n ; int d;} rationnel; Les oprations peuvent tre programmes comme des fonctions ; le produit de deux rationnels par exemple sera :
rationnel *produit(rationnel x, rationnel y ) { rationnel *z; z = (rationnel *) calloc(1, sizeof(rationnel)); *(z->n) = x.n * y.n; *(z->d) = x.d * y.d; return(z); Jean Fruitet - IUT de Marne La Valle - 77

} rationnel *inverse(rationnel x) /* retourne un pointeur NULL si inversion impossible */ { rationnel *z; if (x.n) {

Introduction la programmation z = (rationnel *) calloc(1, sizeof(rationnel)); *(z->n) = x.d; *(z->d) = x.n; return(z); } else return(NULL); }

Exercice 1 : Programmer l'galit, la division, l'addition, la soustraction et la simplification (en utilisant le pgcd) des rationnels. Exercice 2 : Programmer une calculette en nombres rationnels capable dvaluer lexpression ((21/3) - (4/8)) / (-24/12) en entrant la squence : (21,3) - (4,8) = 13/2 / (-24,12) = -13/4

Jean Fruitet - IUT de Marne La Valle - 78

Introduction la programmation

Ensembles La gestion dinformations structures est un domaine dans lequel les ordinateurs excellent, au prix dune reprsentation astucieuse des donnes. Nous allons passer en revue quelques structures de donnes classiques. Dfinition Un ensemble est une collection dobjets, appels lments de lensemble. Classiquement, un ensemble est dfini soit en intention, par une proprit vrifie par tous les lments de lensemble. Exemples : - ensemble des entiers naturels impairs I = {n / n=2p+1} avec p entier naturel ; - ensemble des nombre pairs M2 = {n / n=2p} ; - ensemble des multiples de trois M3 = {n / n = 3p} - ensemble des tudiants de Terminale B2 ; - ensemble des ouvrages de philosophie, etc. soit en extention, par lnumration exhaustive des lments (ce qui suppose que lensemble soit numrable). Exemple : - Arc_en_ciel = {violet, indigo, bleu, vert, jaune, orange, rouge} ; - Alphabet = {a, b, c, d, e, ...} ; - Famille Duraton = {Annie, Bernard, Camille, Dominique, Edmond} ; Cours des monnaies Change = {(Mark, 3.4553), (Ecu, 6.33), (Dollar, 4.89), (FB, 0.1680), ...} Oprations sur les ensembles Lalgbre sur les ensembles repose sur quelques oprations lmentaires dont : Lappartenance dun lment un ensemble (oprateur ) Exemple : (Lire, 0.00306) Change ; Patrick Duraton La runion de deux ensembles, oprateur Exemple : Alphabet = Voyelle Consonne Lintersection de deux ensembles, oprateur Exemple : M6 = M2 M3 Rappelons que la notion densemble nimplique pas de relation dordre entre les lments (bien quun ensemble puisse tre ordonn), et quun ensemble nadmet pas de doublons. Reprsentation des ensembles : tableaux, listes, piles, files Il faut distinguer dune part la reprsentation en machine des lments dun ensemble, et dautre part limplmentation des oprations lmentaires (appartenance, union, intersection). Ces oprations dpendront en partie de la reprsentation des donnes (les lments). Tableaux La reprsentation sous forme de tableau est la plus immdiate. En reprenant le cas dun rpertoire tlphonique, constitu de 200 fiches on peut dfinir : struct fiche personne[200]; Appartenance
Jean Fruitet - IUT de Marne La Valle - 79

Introduction la programmation

Vrifier lappartenance dun lment consistera alors parcourir tout le tableau (soit n comparaisons sil y a n fiches...) Il faut disposer dune fonction permettant de comparer deux lments, qui doit tre adapte aux donnes comparer, mais dont la spcification est en gnral toujours la mme : si a==b, comparer(a,b) retourne 0 si a<b, comparer(a,b) retourne -1 si a>b, comparer(a,b) retourne +1.
#define FAUX 0 #define VRAI 1 int comparer(struct fiche e1, struct fiche e2); /* retourne -1 si e1<e2 ; 0 si e1==e2; 1 si e1>e2 */ int appartient(struct fiche elt, int nbelt, struct fiche e[]) /* retourne FAUX si llment est absent */ { int i; for (i=0; i<nbelt; i++) if (comparer(elt, e[index])==0) return(VRAI); return(FAUX); }

Runion La runion de deux ensembles peut se concevoir de diffrentes faons, par exemple en insrant un un les lments de lun des ensembles dans lautre ensemble.
int inserer(struct fiche elt, int *p, struct fiche e[]) { e[(*p)++]=elt; } int union_ensemble (int nbeltA, int nbeltB, struct fiche eA[], struct fiche eB[]) { int i; for (i=0; i<nbeltA; i++) if (! appartient(eA[i], nbeltB, eB) inserer(eA[i], &nbeltB, eB); }

Intersection Lintersection de deux ensembles ncessite de crer un nouvel ensemble :


int inter_ensemble(int nbeltA, int nbeltB, int *nbelC, struct fiche eA[], struct fiche eB[], struct fiche eC[]) { int i; for (i=0; i<nbelementA; i++) if (appartient(eA[i], nbeltB, eB)) inserer(eA[i], &nbelC, eC); }

Complmentaire Le complmentaire de A dans B peut se programmer en calculant B-A ; il faut disposer en ce cas dune fonction de suppression dun lment dun ensemble. Lautre mthode consiste crer un nouvel ensemble C ne contenant que les lments de B nappartenant pas A :
int difference_ensemble(int nbeltA, int nbeltB, int *nbelC, struct fiche eA[], struct fiche eB[], struct fiche eC[]) { Jean Fruitet - IUT de Marne La Valle - 80

Introduction la programmation int i; for (i=0; i<nbeltB; i++) if (! appartient(eB[i], nbeltA, eA)) inserer(eB[i], &nbelC, eC); }

Complexit en temps des oprations ensemblistes Les oprations union, intersection, complmentaire utilisent loprateur appartenance, qui est en O(n). Pour des ensembles de taille respective n et m lments, ces oprations sont donc en O(n*m), ce qui est coteux au del de quelques dizaines dlments... La reprsentation des ensembles par des tableaux est pratique pour les ensembles dont la taille est rduite, dtermine a priori, et nvoluant pas trop en cours dexcution ; son inconvnient principal tient au cot lev de la recherche dun lment, si lensemble nest pas ordonn. Il faut dans le cas contraire envisager dautres structures de donnes mieux adaptes. Nous allons en tudier quelquesunes Listes chanes Si la taille de lensemble est susceptible dvoluer de faon dynamique ( lexcution), ou difficile dterminer a priori, il est plus judicieux de reprsenter un ensemble par une liste chaine par pointeur. Dfinition Une liste est une suite (finie) de cellules contenant un lment. Chaque lment a donc une position lintrieur de la liste. Tout lment de la liste (sauf le premier et le dernier) a un successeur et un prdcesseur. Un lment peut apparatre plusieurs fois (sauf si la liste implante un ensemble)... En Langage C, on dfinit le type abstrait cellule comme une structure struct cellule { type_donnee val; struct cellule *suiv ; } ; dont le premier champ val contient un lment de lensemble, et dont le deuxime champ suiv est un pointeur sur la cellule suivante. Un ensemble est une liste de cellules chanes par pointeur comme les perles dun collier.
Tete de Liste

100

200

20

350

300

600

355

Lordre sur les lments nest pas ncessaire pour implanter le type ensemble mais alors la liste ne doit pas contenir de doublon. Du point de vue informatique, lajout dun nouvel lment ncessite la cration dune nouvelle cellule, ce qui se ralise de faon dynamique par allocation de mmoire fonction malloc() ou calloc() en cours dexcution. Par ce procd la taille de lensemble nest limite que par lespace mmoire disponible ; elle na pas tre fixe a priori. Allocation Considrons par exemple un ensemble de nombres entiers. Une cellule sera dfinie par :
Jean Fruitet - IUT de Marne La Valle - 81

Introduction la programmation

typedef struct cellule { int elt; struct cellule *suiv ; } liste; Une fonction alloc_cellule(int x) d'allocation mmoire d'une cellule retour-nant un pointeur sur une cellule dont la valeur est x. sera dfinie en C par :
liste * alloc_cellule (int x) { liste *c; c = (liste *) calloc(1, sizeof(liste)); if (c!=NULL) { c->elt=x; /* assignation de x */ c->suiv = NULL; } return (c); }

Appartient Il nous faut crire une fonction int appartient(int x , listel ) qui renvoie VRAI si la valeur x appartient la liste l , FAUX sinon. Vrifier si x appartient la liste, cela consiste comparer x avec llment en tte de liste, puis parcourir la liste en suivant le chanage, soit jusqu trouver llment recherch, soit jusqu atteindre la fin de liste. La programmation rcursive simpose.
int appartient (int x, liste *l) { if ((l==NULL) return (FAUX); else if (l->elt==x) return (VRAI); else return (appartient(x, l->suiv)); }

Variante de la fonction appartient(), la fonction liste position_element(int x , listel ) renvoie un pointeur sur la cellule contenant x s'il se trouve dans la liste, et NULL sinon.
liste *position_element(int x, liste *l) { if ((l==NULL) return (NULL); else if (l->elt==x) return (l); else return (position_element(x, l->suiv)); }

Runion, intersection, complmentaire Insertion dun lment La runion, lintersection et le complmentaire ncessitent de disposer dune fonction dinsertion dun lment dans une liste. Si aucun ordre nest impos, linsertion en tte est la moins coteuse. liste * insere_en_tete(int x , liste *l ) insre un nouvel lment en tte de liste l et retourne un pointeur sur la liste.
liste *insere_en_tete(int x , liste *l ) { liste *c; Jean Fruitet - IUT de Marne La Valle - 82

Introduction la programmation c = (liste *) calloc(1, sizeof(liste)); if (c!=NULL) { c->elt=x; /* assignation de x */; c->suiv=l; /* assignation de suivant */ l=c; /* chainage */ } return (l); }

Insertion en tte de liste

.... (3)
Tte de liste

(2)
x

nouvelle_cellule

(1)
Insertion en tte : (1) crer une cellule ; (2) chaner avec la premire cellule de la liste ; (3) faire pointer la tte de liste vers la nouvelle cellule. Si lordre des lments doit tre respect, linsertion dans le corps de la liste simpose. Il faut alors reprer la cellule prcdant immdiatement la nouvelle cellule insrer, et modifier les liens comme indiqu sur le schma suivant.
liste *insere_en_place(int x , liste *l ) { liste *c, *aux; aux=l; /* tester si insere en tte */ if ((aux==NULL) || ((aux->elt)>x)) return(insere_en_tete(x,l)); /* sinon rechercher la position de x */ while ((aux->suiv)!=NULL) && ((aux->suiv->elt)<x)) aux=aux->suiv; /*1*/ c = (liste *) calloc(1, sizeof(liste)); if (c!=NULL) { c->elt=x; /* assignation de x */; /*2*/ c->suiv=aux->suiv; /* assignation de suivant */ /*3*/ aux->suiv=c; /* chainage */ } return (l); }

Jean Fruitet - IUT de Marne La Valle - 83

Introduction la programmation

Insertion dans le corps de la liste

(3)
cellule_courante

(2)

x
nouvelle_cellule

(1)

Suppression dun lment. La suppression dun lment ncessite de lisoler dans la liste, puis de supprimer le lien de cet lment avec son prdcesseur et son successeur. Nous laissons cet exercice au lecteur.
Suppression d'une cellule
(1)

(2)
cellule_courante

x
cellule_supprime

(3)

Programmons les oprations Runion, Intersection et Complmentaire.


liste *union_liste(liste *a, liste *b) { liste *aux, *c=NULL; /* recopie des lments de a dans c */ aux=a; while (aux!=NULL) { c=insere_en_tete(aux->elt, c); aux=aux->suiv; } /* recopie des lments de b dans c */ aux=b; while (aux!=NULL) { if (! appartient(aux->elt, a)) insere_en_tete(aux->elt, c); aux=aux->suiv; } return (c); } liste *inter_liste(liste *a, liste *b) { liste *aux, *c=NULL; /* recopie des lments de b appartenant a dans c */ aux=b; while (aux!=NULL) { if (appartient(aux->elt, a)) c=insere_en_tete(aux->elt, c); aux=aux->suiv; } return (c); } liste *difference_liste(liste *a, liste *b) { liste *aux, *c=NULL; /* recopie des lments de b nappartenant pas a dans c */ aux=b; while (aux!=NULL) Jean Fruitet - IUT de Marne La Valle - 84

Introduction la programmation { if (! appartient(aux->elt, a)) c=insere_en_tete(aux->elt, c); aux=aux->suiv; } } return (c);

Complexit La complexit de ces oprations est en O(n*m), avec n (respectivement m) lments dans A (respectivement B). Le programme complet suivant gnre deux ensembles dentiers tirs au hasard, et en calcule lunion, lintersection et la diffrence.
#include <stdio.h> #include <stdlib.h> #define VRAI 1 #define FAUX 0 typedef struct cellule { int elt; struct cellule *suiv ; } liste; liste *position_element(int x, liste *l) { if (l==NULL) return (NULL); else if (l->elt==x) return (l); else return (position_element(x, l>suiv)); } liste *insere_en_tete(int x , liste *l ) { liste *c; c = (liste *) calloc(1, sizeof(liste)); if (c!=NULL) { c->elt=x; /* assignation de x */; c->suiv=l; /* assignation de suivant */ l=c; /* chainage */ } return (l); } liste *insere_liste(int x , liste *l ) /* verifie si x appartient a l avant d'insrer */ { if (! appartient(x, l)) l=insere_en_tete(x, l); return (l); } liste *union_liste(liste *a, liste *b) { liste *aux, *c=NULL; /* recopie des lments de a dans c */ aux=a; Jean Fruitet - IUT de Marne La Valle - 85 return (appartient(x, l>suiv)); }

liste * alloc_cellule (int x ) ; int appartient (int x, liste *l); liste *position_element(int x, liste *l); liste *insere_en_tete(int x, liste *l ); liste *insere_liste(int x, liste *l ); liste *union_liste(liste *a, liste *b); liste *inter_liste(liste *a, liste *b); liste *difference_liste(liste *a, liste *b); int affiche_liste(liste *a); liste * alloc_cellule (int x ) { liste *c; c = (liste *) calloc(1, sizeof(liste)); if (c!=NULL) { c->elt=x; /* assignation de x */ c->suiv = NULL; } return (c); } int appartient (int x, liste *l) { if (l==NULL) return (FAUX); else if (l->elt==x) return (VRAI); else

Introduction la programmation while (aux!=NULL) { c=insere_en_tete(aux->elt, c); aux=aux->suiv; } /* recopie des lments de b dans c */ aux=b; while (aux!=NULL) { if (! appartient(aux->elt, a)) c=insere_en_tete(aux->elt, c); aux=aux->suiv; } return (c); } liste *inter_liste(liste *a, liste *b) { liste *aux, *c=NULL; /* recopie des lments de b appartenant a dans c */ aux=b; while (aux!=NULL) { if (appartient(aux->elt, a)) c=insere_en_tete(aux->elt, c); aux=aux->suiv; } return (c); } liste *difference_liste(liste *a, liste *b) { liste *aux, *c=NULL; /* recopie des lments de b nappartenant pas a dans c */ aux=b; while (aux!=NULL) { if (! appartient(aux->elt, a)) c=insere_en_tete(aux->elt, c); aux=aux->suiv; } return (c); } /* affiche une liste d'entiers ; retourne le nombre d'lments */ int affiche_liste(liste *l) /* version itrative */ { int n=0; liste *c; c=l; while (c != NULL) { printf("%d ",c->elt); c=c->suiv; n++; } return (n); } /* affiche une liste d'entiers */ int affiche_liste_r(liste *l) /* version rcursive */ { if (l != NULL) { printf("%d ",l->elt); affiche_liste_r(l->suiv); } printf("\n"); } void main (void) { liste *a, *b, *c; int i, j; int n; /* premier ensemble */ a=NULL; printf("Tapez un nombre [1..25] ?\n"); scanf("%d",&n); srand(n); for (i=0; i<n; i++) a=insere_liste(rand() % 10, a ); j=affiche_liste(a); printf("\n%d lments\n",j); /* deuxime ensemble */ b=NULL; printf("Tapez un nombre [1..25] ?\n"); scanf("%d",&n); /* cration de la liste b */ for (i=0; i<n; i++) b=insere_liste(rand() % 10, b ); j=affiche_liste(b); printf("\n%d lments\n",j); printf("/* union */\n"); c=NULL; c=union_liste(a, b); j=affiche_liste(c); printf("\n%d lments\n",j); printf("/* intersection */\n"); c=NULL; c=inter_liste(a, b); j=affiche_liste(c); printf("\n%d lments\n",j); printf("/* diffrence */\n"); c=NULL; c=difference_liste(a, b); j=affiche_liste(c); printf("\n%d lments\n",j); }

Jean Fruitet - IUT de Marne La Valle - 86

Introduction la programmation

Pile et file Si lordre dinsertion et de suppression des lments dans la liste importe, deux structures de donnes sont particulirement adaptes : la pile et la file. Pile [stack, lifo] Une pile est une liste qui respecte la rgle dernier arriv, premier sorti, alors que la file respecte la rgle premier arriv, premier sorti. La pile est une structure de donnes pour laquelle lajout et la suppression dun lment ne sont autoriss qu une seule extrmit, appele sommet de la pile. Les oprations sur les listes sont P est une pile, x un lment : Vider(P) [clear()] P ne contient plus aucun lment. Vide(P) VRAI ssi P est vide. Premier(P) retourne le premier lment de P. Dpiler(P) [pop()] retourne le premier lment de P et supprime celui-ci de P. Empiler(x, P) [push()] place x dans P comme premier lment.

Oprations sur une pile


x
sommet ... 2 1 0 sommet

dpiler
...

empiler

2 1 0

Il est assez facile de raliser limplantation dune pile laide dun tableau. Il faut seulement dfinir une variable auxiliaire, le pointeur de pile, qui indique ladresse du sommet de la pile (qui est aussi le nombre dlments de celle-ci).
/* Pile de flottants */ #include <stdio.h> #include <stdlib.h> #define MAXELEMENT 20 typedef float typepile; typepile pile[MAXELEMENT]; int pp=0 ; /* pointeur de pile */ return(pile[pp-1]); } typepile pop(void) /* ne doit pas tre utilis si la pile est vide */ { pp--; return(pile[pp]); } void push(typepile x) /* ne doit pas tre utilis si pile pleine */ { pile[pp]=x; pp++; } /* programme principal */ void main (void) { int i, j; int n; /* remplir la pile */ printf("Tapez un nombre [1..25] ?\n"); Jean Fruitet - IUT de Marne La Valle - 87

void clear(void) { pp=0; } int pile_vide(void) { return (pp==0); } int pile_pleine(void) { return (pp==MAXELEMENT); } typepile premier_pile(void) {

Introduction la programmation scanf("%d",&n); srand(n); for (i=0; i<n; i++) if (!pile_pleine()) push(rand() % 10); printf("\n%d lments\n",pp); /* vider la pile */ while(! pile_vide()) printf("%3.2f ",pop()); printf("\n");

Jean Fruitet - IUT de Marne La Valle - 88

Introduction la programmation

File, queue [queue, fifo] Une file est une structure de donnes pour laquelle lajout et la suppression dun lment ne sont autoriss quaux seules extrmits, appeles la tte et la queue de la file. Les lments sont ajouts en queue de file et sont retirs en tte de file. Les oprations sur les listes sont F est une file, x un lment: Vider(F)F ne contient plus aucun lment. Vide(F) VRAI ssi F est vide. Premier(F) retourne le premier lment de F. Dernier(F) retourne le dernier lment de F. Dfiler(F) retourne le premier lment de F et supprime celui-ci de F. Enfiler(x, F) place x dans F comme dernier lment. On dispose de deux index, tte et queue, et dun tableau de taille MAXELEMENT, dont les adresses sont dsignes modulo MAXELEMENT pour obtenir une structure de donnes circulaire...
File
0 1 2

Sens de la file qui se vide par la


3 tte .... MAXELT-1

x tte

x queue

Les nouveaux arrivants s'ajoutent en queue


x x x x

3 2 1 0

....

tte queue Sens de la file

MAXELT-1

File circulaire
/* File circulaire de flottants */ #include <stdio.h> #include <stdlib.h> #define MAXELEMENT 20 typedef float typefile; typefile file[MAXELEMENT]; int tf=0; /* tete de file */ int qf=0; /* queue de file */ void clear(void) { tf=0; qf=0; } int file_vide(void) { return (tf==qf); Jean Fruitet - IUT de Marne La Valle - 89 } int file_pleine(void) { return ((qf+1) % MAXELEMENT == tf); } typefile premier_file(void) { return(file[tf]); }

typefile dernier_file(void) { if (qf>0) return(file[qf-1]); else return(file[MAXELEMENT-1]); } typefile defile(void) /* ne doit pas tre utilis si la file est vide */ { if (tf<MAXELEMENT-1) { tf=tf+1; return(file[tf-1]); } else { tf=0; return(file[MAXELEMENT-1]); } } void enfile(typefile x) /* ne doit pas tre utilis si file pleine */ { file[qf]=x;

Introduction la programmation qf=(qf+1) % MAXELEMENT; } /* programme principal */ void main (void) { int i, j, n; /* remplir la file */ printf("Tapez un nombre [1..25] ?\n"); scanf("%d",&n); srand(n); j=0; for (i=0; i<n; i++) if (!file_pleine()) { enfile(rand() / 10.0); j++; } printf("\n%d lments\n",j); while(! file_vide()) printf("%3.2f ",defile()); printf("\n"); }

Limplantation dune pile ou dune file sous forme de liste chane ne prsente pas de difficult particulire.

Jean Fruitet - IUT de Marne La Valle - 90

Introduction la programmation

Hachage Vecteur boolen Soit E un sous-ensemble de lensemble dentiers {0, 1, 2,...,N}, par exemple E = {2, 7, 9} Pour reprsenter lensemble E, on utilise une fonction caractristique F: F :E --> {0, 1} x --> F(x)==0 si x nappartient pas E x --> F(x)==1 si x appartient E Dansnotre exemple E = {2, 7, 9} 0 0 0 1 1 2 0 3 0 4 0 5 0 6 1 7 0 8 1 9 0 10 ... ... 0 N

Si pour reprsenter la fonction F on utilise un vecteur de bits, il faut modifier la dclaration prcdente en regroupant 8 valeurs conscutive en un seul octet. Ainsi 0 0 0 1 1 2 0 3 0 4 0 5 0 6 1 7 0 8 1 9 0 10 ... ... 0 N

peut se reprsenter par binaire hexadcimal 0010 0000 20 1010 0000 A0 0000 0000 00 .... ...

Tri par distribution Le tri par distribution saparente au tri postal. Soit E un sous-ensemble de lensemble dentiers {0, 1, 2,...,N-1}. Lensemble E a n lments Card(E)=n classer dans lordre usuel sur les entiers (ordre croissant). La mthode procde en deux tapes : - distribution de E sur un vecteur de bits par une fonction caractristique F - collecte des lments non nuls du vecteur de bits parcouru dans lordre croissant

E={ 9, 2, 7} distribution 0010000101 collecte E={ 2, 7, 9}


La complexit de cet algorithme est proportionnelle au cardinal de E O(n) Hachage Pour mmoriser des ensembles dobjets (pas ncessairement des entiers) sur lesquels sappliquent les oprations ensemblistes AJOUTER, SUPPRIMER, ELEMENT, on reprend lide du vecteur boolen (ou vecteur de bits). Mais ici la fonction caractristique, appele fonction de hachage, est calcule pour un attribut de lobjet, qui peut tre numrique, considr comme une cl daccs
Jean Fruitet - IUT de Marne La Valle - 91

Introduction la programmation

lobjet. Typiquement, ce sera le cas des objets dune base de donnes, dont les tuples sont accessibles par une cl unique. Fonction de hachage La fonction de hachage rpartit les objets en paquets [buckets] do son nom dont ladresse est range dans une table de hachage. La fonction de hachage tablit une relation, pas ncessairement injective, entre la valeur de la cl et son indice dans la table ; plusieurs cls peuvent donc avoir la mme valeur de hachage (collision). On mmorise un sous-ensemble E du domaine D avec une table T de taille N. La fonction h associe chaque cl x une valeur de lintervalle [0.. N-1] D --> [0,1, ... ,N-1] x --> h(x) Le choix de la fonction de hachage doit tre considr avec soin. La taille de la table doit, si possible, tre de lordre de grandeur de lensemble E.Toutes les valeurs entre 0 et N-1 doivent tre quiprobables, cest--dire que pour toute cl x et pour tout i entre 0 et N-1, la probabilit que h(x) ait pour valeur i doit tre gale 1/N (h uniforme). Exemple Un sous-ensemble E du domaine D des prnoms E = {Anne, Guy, Lou, Luc} D = { x / x est un prnom cod en ASCII } h(x) = (Somme des codes ASCII de x ) MODULO 8 Une table de 8 lments suffit. Calcul des valeurs de hachage h(Anne)= (65+110+110+101) % 8 = 2 h(Guy)= (71+117+121) % 8 = 5 h(Lou)= (76+111+117) % 8 = 0 h(Luc)= (76+117+99) % 8 = 4 Lou Anne Luc Guy 0 1 2 3 4 5 6 7 Si la fonction nest pas injective ( xy et h(x)=h(y)) il se produit des collisions. h(Paul)= (80+97+117+108) % 8 = 2 = h(Anne) Exercice : Calculez la valeur de hachage de Noe et placez-le dans la table. T Adressage dispers Pour viter les collisions, on cherche parpiller au maximum les donnes, dans une table qui est de lordre de grandeur du domaine. Dans le cas des prnoms, avec une fonction de hachage h(x) = (Somme(Ascii(x[i])) % N quelle taille N donner la table pour disperser 200 prnoms ? Quel est lordre de grandeur de D ? Il y a au moins un prnom par jour du calendrier !. Re-hachage Pour rsoudre le problme des collisions, une mthode simple consiste reporter les cls qui entrent en collision sur les cases libres du tableau. Formellement, cela revient associer chaque valeur x une suite dindices dans la table ; le premier indice est h(x) ; les indices suivants sont obtenus par un nouveau hachage ou en recherchant la premire case libre suivante, circulairement... ( (h(x)+k) modulo N / k = 0, 1, 2, ...) T Lou Anne Paul Luc Guy Noe

Jean Fruitet - IUT de Marne La Valle - 92

Introduction la programmation

Aprs ajout de Paul et Noe, les cases 2, 3 et 6 sont occupes par des lments ayant une valeur de hachage identique. Pour retrouver Noe, il faut : - calculer h(Noe) = 2 - comparer T[h(Noe)] et Noe si identit SUCCES sinon parcourir le tableau circulairement jusqu - trouver Noe : SUCCES - trouver une case libre : ECHEC Suppression dun lment La suppression de llment Anne libre une case. Mais alors le fil conducteur jusqu Noe est coup. Donc les cases libres doivent tre marques VIDE, et les case qui nont jamais t occupes marques BLANC. T Lou 0 BLAN C 1 VIDE 2 Paul 3 Luc 4 Guy 5 Noe 6 BLAN C 7

Quelques fonctions de hachage Une fonction de hachage doit tre uniforme (la probabilit que h(x)=i doit tre proche de 1/N), dterministe (pour une cl donne elle calcule toujours la mme valeur), et facilement calculable. - Extraction de bits La cl est toujors reprsente par une suite de bits, dont on peut extraire p bits, rsultant un nombre entre 0 et 2p-1. Elle est simple calculer mais ne donne de bons rsultats que si les bits carts ne sont pas significatifs. - Compression de bits La reprsentation de la cl est dcoupe en q tranches de p bits, que lon combine par une opration telle que laddition ou le ou exclusif ; si x = t[1]t[2]...t[q] alors h(x) = t[1] xor t[2] xor ... xor t[q]. Pour briser certaines rptitions de bits, on peut dcaler circulairement les tranches avant de les combiner. - Division On prend le reste de la division par N de la reprsentation de la cl: h(x) = x mod N. Il faut faire attention aux effets indsirables daccumulation. - Multiplication soit un nombre rel r, tel que 0 < r < 1, on calcule h(x) = Troncature(((x*r) mod 1) * N) La valeur de r ne doit pas tre trop proche de 0 ou de 1 pour viter des accumulations aux extrmits du tableau. De bonnes valeurs pour r sont (5 - 1) / 2 et 1 - (5 - 1) / 2. Hachage ouvert On peut rsoudre le problme des collisions en associant une liste chane chaque case de la table de hachage.

Jean Fruitet - IUT de Marne La Valle - 93

Introduction la programmation

0 Lou 1

Hachage ouvert

VIDE Noe

2 Anne 3 Paul 4 5 6 7

Luc Guy VIDE VIDE

Tri lexicographique On considre un ensemble de mots ; une table indexe par les lettres de lalphabet et une fonction de hachage qui un mot fait correspondre sa ime lettre. Donner un algorithme permettant de classer les mots dans lordre lexicographique (alphabtique). Indication : pour classer des mots de mme longueur, il suffit de les classer successivement suivant la dernire lettre, puis avant-dernire lettre, etc. Dictionnaire dun texte On considre un texte T constitu de mots (chane ASCII alphanumrique) spars par des codes <ESPACE>, <TAB>, <NL>, <CR> Programmer en C le dictionnaire du texte par fonction de hachage ferme. A chaque mot sera associ un triplet <mot, position de la premire occurrence, nombre doccurrences> Les mots seront case sensitive (MAJUSCULES et minuscules) Proposer plusieurs fonctions de hachage et afficher la distribution des valeurs de hachage et le nombre de collisions en fonction de la taille de la table de hachage...

Jean Fruitet - IUT de Marne La Valle - 94

Introduction la programmation

Arbres et ensembles ordonns Il est souvent ncessaire dordonner les lments dun ensemble, par exemple pour amliorer la rapidid dune recherche... Or le maintien dun ordre entre les lments dun tableau ou dune liste est relativement coteux. Pour un tableau par exemple linsertion dun lment ncessite de dterminer sa place, en parcourant le tableau depuis le dbut (k comparaisons) puis de dcaler les (nk) lments successeurs pour mnager une place. Donc une complexit en O(n) avec n le nombre dlments du tableau. Les arbres de recherche sont des structures de donnes qui permettent de rduire la complexit en temps mais pas la complexit de la programmation ! des algorithmes dinsertion et de recherche en accdant aux donnes par dichotomie. Exemples darbres La structure de fichiers sous DOS inspire dUNIX organise les fichiers en collections hirarchises appeles rpertoires [directory]. Chaque rpertoire (sauf la racine qui na pas de pre) a un seul rpertoire pre et zro ou plusieurs sous-rpertoires fils. Les fichiers de donnes proprement dits sont les feuilles de larbre.
C:\ (Racine) +--IO.SYS +--DOS.SYS +--CONFIG.SYS +--AUTOEXEC.BAT +--DOS +--COMMAND.COM +--KEYB.EXE +--EDIT.COM +--FORMAT.EXE +-- ... +--TURBOC +--BIN +--TCC.EXE +--TC.EXE +--TCINST.EXE +--ESSAI_1.EXE +-- ... +--INCLUDE +-- ... +--LIB +-- ... +--SRC +--ESSAI_1.C +--ESSAI_2.C +--ESSAI_1.OBJ +--ESSAI_1.EXE
IO.SYS DOS.SYS CONFIG.SYS AUTOEXEC.BAT COMMAND.COM KEYB.EXE EDIT.COM ... DOS

racine

sous-rpertoire

TURBOC

BIN

INCLUDE

LIB

SRC

TCC.EXE TC.EXE TCINST.EXE ...

ESSAI_1.C

fichiers

ESSAI_1.EXE ...

La structure de fichiers et rpertoires DOS

Lintrt de cette organisation est de laisser lutilisateur le soin de regrouper les fichiers sa convenance tout en maintenant une structure hirarchique. Un arbre gnalogique reprsentant la relation de parent est la mre de est aussi une structure darbre quelconque. Par contre la relation a pour parents ne cre pas un arbre (au sens informatique) mais un graphe, un noeud pouvant avoir deux ascendants.

Jean Fruitet - IUT de Marne La Valle - 95

Introduction la programmation

Reprsentation symbolique des arbres


Arbre vide Arbre quelconque 23 Arbre singleton 23 12 -2 78 10 -77 12 CECI N'EST PAS UN ARBRE car 9 a deux pres 23 -2 78 10 -77

22

22

Arbre binaire 23 12 -2 10 78 -77

Arbre binaire de recherche racine 12 9 23 10 9 sous-arbre droit 78

22 9

-2 -77

22

sous-arbre gauche

Chaque tiquette d'un noeud du sous-arbre gauche est infrieure ou gale l'tiquette de la racine qui est infrieure aux tiquettes du sous-arbre droit... cette proprit est maintenue dans l'arbre tout entier.

Par dfinition un arbre est une structure de donnes constitue dun noeud appel racine et de sous-arbres fils de la racine. Cest donc une dfinition rcursive. Chaque noeud dun arbre a un ou zro pre et zro ou plusieurs fils. Un noeud sans pre est la racine de larbre. Un noeud sans fils est une feuille. Un noeud ayant un pre et au moins un fils est un noeud interne. Ltiquette dun noeud est un lment de lensemble reprsent par larbre. Les liens entre un noeud et ses sous-arbres fils sont les branches de larbre. La hauteur de larbre est le plus long chemin (sans retour en arrire) entre la racine et une feuille. Un arbre vide na aucun noeud. Un singleton a une racine sans fils. Un arbre binaire est un arbre dont chaque noeud a au plus deux fils. Un arbre binaire de recherche est un arbre binaire dont les tiquettes sont ordonnes selon une cl et tel que toutes les cls du sous-arbre gauche sont infrieures ou gales la cl de la racine, et celles du sous-arbre gauche sont suprieures, et ceci pour tous les sous-arbres... La hauteur de larbre permet destimer le nombre n dlments de celui-ci. En particulier si A est un arbre binaire complet de hauteur h (tous les noeuds ont zro ou deux fils) il a au plus 20 + 21 + 22 + .. + 2h-1 + 2h lments Card(A) i=0,h 2i = 2h+1 -1

Jean Fruitet - IUT de Marne La Valle - 96

Introduction la programmation
Arbre binaire de recherche complet racine 12 hauteur :3 -2 -77 9 feuilles 9 23 10 78 sous-arbre 1 noeuds 2 noeuds ... au plus 2*2*2 noeuds

22

Dfinition axiomatiques des arbres Ensembles Arbre : (N, P), N : ensemble de noeuds, P : relation pre de Arbre+ : Arbre - { } Arbre2 : Arbres binaires Element : Etiquette des noeuds de larbre. LA : Liste darbres. Oprations Arbre-vide : ...--> Arbre : Crer un arbre vide Racine : Arbre --> Noeud : Retourner le noeud racine dun arbre Fils : Arbre --> LA : Retourner la liste des sous-arbres de la racine Gauche : Arbre2+---> Arbre2 : Retourner le sous-arbre gauche de la racine Droit : Arbre2+--> Arbre2 : Retourner le sous-arbre droit de la racine Cons : Noeud x LA -->Arbre+ : Retourner larbre construit partir du noeud Cons2 :Noeud x Arbre2 x Arbre2 -->Arbre2+ : Retourner larbre binaire construit Vide : Arbre --> {VRAI, FAUX} : Tester si un arbre est vide Elt : Noeud --> Element : Retourner ltiquette dun noeud Nouveau : Element --> Noeud : Crer un nouveau noeud

Jean Fruitet - IUT de Marne La Valle - 97

Introduction la programmation

Reprsentation informatique La reprsentation informatique des arbres peut se faire laide de tableaux. On gagne alors en simplicit de programmation ce quon perd en souplesse. Mais les arbres tant trs bien adapts la programmation avec allocation dynamique de mmoire il est prfrable dimplanter les arbres sous forme de cellules (record, structure) et de pointeurs.
Arbre quelconque
23

Arbre binaire
D

12

-2

10

-2

22

-77

Pour viter davoir grer un nombre variable de pointeurs par noeud dun arbre quelconque, on peut prfrer la structure suivante fils gauche, frre droit
Arbre quelconque
23 Pointeur vers un frre

Pointeur vers le premier fils 12 -2 10

-2

22

-77

Implantation en Langage C Il faut dabord reprsenter un Noeud. Par exemple pour les arbres quelconques :
typedef struct cellule { type_element elt; struct cellule * fils_gauche; Jean Fruitet - IUT de Marne La Valle - 98

Introduction la programmation struct cellule * frere_droit;} noeud;

Et pour un arbre binaire :


typedef struct cellule { type_element elt; struct cellule * fils_gauche; struct cellule * fils_droit;} noeud;

Un Arbre est un pointeur sur un Noeud, la racine de larbre : typedef noeud *arbre; Un Arbre vide est un pointeur NULL : arbre = NULL; Oprations Vide consiste tester si la racine est un pointeur NULL :
int vide (arbre racine) { return (racine == NULL); }

Elt : consiste retourner ltiquette dun noeud : par exemple pour les arbres quelconques :
type_element element(arbre racine) { return (racine->elt); }

Nouveau : il faut faire une allocation mmoire et placer ltiquette. En cas derreur dallocation le
pointeur renvoy est NULL (larbre est vide) : arbre nouveau_binaire(type_element elt, arbre racine) { racine = (struct cellule *) calloc(1, sizeof (struct cellule)); if (! vide(racine)) { racine->elt = elt; racine->fils_gauche= NULL; racine->fils_droit=NULL; } return(racine); }

Cons : il faut relier un noeud un ou plusieurs sous arbres.


arbre cons_binaire(arbre racine, arbre ss_arbre_g, arbre ss_arbre_d) { racine->fils_gauche = ss_arbre_g; racine->fils_droit = ss_arbre_d; return(racine); }

Insertion
Les oprations dinsertion, suppression et recherche dun lment se programment de faon rcursive. Dans le cas dun arbre binaire de recherche, linsertion est guide au cours de la descente dans larbre par la relation dordre sur les cls. Il faut donc disposer dune fonction de comparaison des cls, qui de faon classsique en langage C retourne un entier ngatif, nul ou positif selon lordre sur les cls :
int clef(type_element e) /* renvoie la valeur de la cl */ { return (e.cle); Jean Fruitet - IUT de Marne La Valle - 99

Introduction la programmation } int compare(type_element e1, type_element e2) { if (clef(e1) < clef(e2) ) return (-1); else if (clef(e1) == clef(e2) ) return (0); else return (1); } arbre inserer_bin_recherche(type_element elt, arbre racine) { if (vide(racine)) racine=nouveau_binaire(elt, racine); else if (compare(elt, racine->elt) <= 0) racine_fils_gauche = inserer_bin_recherche(elt, racine>fils_gauche); else racine->fils_droit = inserer_bin_recherche(elt, racine->fils_droit); return(racine); }

La complexit de cet algorithme est proportionnelle la hauteur de larbre et donc en O(log2n) pour un arbre binaire de recherche quilibr. Suppression La suppression dun lment doit conserver larbre binaire de recherche. Il faut donc remplacer ltiquette supprime par ltiquette la plus droite du sous-arbre gauche. E
FG FD FG

Max FG FD

Max FG La suppression de l'tiquette E ncessite de remplacer celle-ci par la plus grande tiquette du sous-arbre gauche...

La programmation de cette opration assez dlicate sera laisse la sagacit du lecteur ! Parcours darbre Un parcours en profondeur consiste descendre dans larbre depuis la racine en commenant par le premier fils (le fils gauche pour un arbre binaire), de faon rcursive, puis traiter les autres fils. Selon lordre daffichage de ltiquette des noeuds avant, entre ou aprs les fils laffichage sera prfixe, infixe ou suffixe.

Jean Fruitet - IUT de Marne La Valle - 100

Introduction la programmation

Parcours en profondeur d'un arbre binaire de recherche

12 9 23 10 9

-2 -77

22

78

Parcour s prfixe : 12, 9, -2, -77, 9, 10, 23, 22, 78 Parcours infixe : Parcours suffixe : -77, -2, 9, 9, 10, 12, 22, 23, 78 -77,9, -2, 10, 9, 22, 78, 23, 12

Le parcours infixe affiche les lments dans lordre croissant. void infixe(arbre racine) { if (! vide(racine)) { infixe(racine->fils_gauche); printf(%d\t,racine->elt); infixe(racine->fils_droit); }

Exercices
A est un arbre binaire de recherche dont les donnes sont des entiers. 1) Donner en langage C la dfinition de A. 2) Dessiner A aprs insertion des nombres 100, 20, 30, 150, 110, 10, 25, 45, 150, 200. 3) Quelle est la hauteur de l'arbre A ? 4) Que devient l'arbre A si - on supprime 30 ? - on supprime 100 ? - on rajoute 5 et 120 ? 5) Ecrire une fonction affichant les lments dun arbre binaire de recherche dans lodre dcroisssant. 6) Le parcours en largeur consiste afficher la valeur de chaque noeud au fur et mesure de la descente dans l'arbre, puis traiter chaque fils dans l'ordre gauche puis droite. Pour l'arbre de la question 2 un parcours en largeur produit la liste : 100, 20, 10, 30, 25, 45, 150, 110, 200 Ecrire en C la fonction void parcours_largeur(type_arbre *racine); 7) Ecrire une fonction taille retournant le nombre de noeuds dun arbre. 8) Ecrire une fonction hauteur retournant la hauteur dun arbre.

Jean Fruitet - IUT de Marne La Valle - 101

/* JF */ /* Arbre #include #include #include

binaire de recherche */ <stdio.h> <stdlib.h> <errno.h>

Introduction la programmation racine->fg = NULL; racine->fd = NULL; } else perror("Erreur allocation memoire\n"); } else if (strcmp(element, racine>elt)<=0) racine->fg=insere(element, racine->fg); else racine->fd=insere(element, racine->fd); return (racine); } arbre recherche (char *element, arbre racine) { int test; if (racine!=NULL) { test = strcmp(racine->elt, element); if (test==0) return (racine); else if (test<0) return( recherche(element, racine->fd)); else return( recherche(element, racine->fg)); } else return (NULL); } arbre min_arbre(char *element, arbre racine) /* supprime la valeur minimum de l'arbre et la place dans element */ { arbre aux; if (racine!=NULL) { if (racine->fg==NULL) { aux=racine; strcpy(element, racine->elt); racine=racine->fd; free(aux); } else { racine->fg=min_arbre(element, racine->fg); } } return(racine); } arbre supprime(char *element, arbre racine) /* supprime element de l'arbre */ { int test; arbre aux; Jean Fruitet - IUT de Marne La Valle - 102

#define MAXCAR 20 #define MAXHACHE 1000; typedef struct cellule { char elt[MAXCAR]; struct cellule * fg; struct cellule * fd; } *arbre; #define MAXHAUTEUR 100 struct liste {char n[MAXCAR]; struct liste * suiv;} *ta[MAXHAUTEUR]; /* tableau de listes */ FILE *f; /* PROTOTYPES */ arbre insere(char *element, arbre racine); /* insere un element dans l'arbre binaire */ arbre recherche (char *element, arbre racine); /* recherche un element */ arbre min_arbre(char *element, arbre racine); /* supprime le min de l'arbre */ arbre supprime(char *element, arbre racine); /* supprime element de l'arbre */ void affiche_p(arbre racine); /* affiche en profondeur infixe */ struct liste * insere_queue_liste(struct liste * l, char n[]); /* ajoute eun element n queue de liste */ void cree_l(int h, arbre racine); /* transforme un arbre en tableau de listes */ void affiche_liste(struct liste *l); /* affiche le tableau de listes niveau par niveau */ void affiche_l(arbre racine); /* affiche un arbre en largeur */ /* FONCTIONS */ arbre insere(char *element, arbre racine) /* insere un element dans un arbre */ { if (racine==NULL) /* creer l'arbre */ { racine = (struct cellule *) calloc(1, sizeof(struct cellule)); if (racine != NULL) { strcpy(racine->elt, element);

Introduction la programmation aux = racine; if (racine!=NULL) { test = strcmp(racine->elt, element); if (test==0) { /* remplacer cet element */ if (racine->fd==NULL) /* faire monter le sous-arbre gauche */ { aux=racine; racine=racine->fg; free(aux); } else if (racine->fg==NULL) /* faire monter le sous-arbre droit */ { aux=racine; racine=racine->fd; free(aux); } else /* remplacer par min_fd */ { racine->fd = min_arbre(racine->elt, racine->fd); } } else /* rechercher sur les fils */ if (test<0) racine->fd=supprime(element, racine->fd); else racine->fg=supprime(element, racine->fg); } return (racine); } void affiche_p(arbre racine) { if (racine!=NULL) { affiche_p(racine->fg); printf("%s\t",racine->elt); affiche_p(racine->fd); } } /* affichage en largeur */ struct liste * insere_queue_liste(struct liste * l, char n[]) { struct liste *aux; if (l==NULL) /* creer la liste */ { l=(struct liste *) calloc(1, sizeof(struct liste)); if (l==NULL) perror("Erreur allocation memoire \n"); else { strcpy(l->n, n); l->suiv=NULL; printf("Insertion %s\t",n); */ }

/*

} else { aux=l; while (aux->suiv != NULL) aux=aux->suiv; aux->suiv=(struct liste *) calloc(1, sizeof(struct liste)); if (aux->suiv==NULL) perror("Erreur allocation memoire \n"); else { strcpy(aux->suiv->n, n); aux->suiv->suiv=NULL; /* printf("Adjonction %s\t",n); */ } } return (l); } void cree_l(int h, arbre racine) { if (racine!=NULL) { ta[h]=insere_queue_liste(ta[h],raci ne->elt); cree_l(h+1,racine->fg); cree_l(h+1,racine->fd); } } void affiche_liste(struct liste *l) { while (l != NULL) { printf("%s\t", l->n); l= l->suiv; } } void libere_liste(struct liste *l) { struct liste *aux; while (l != NULL) { aux=l->suiv; free(l); l = aux; } } void libere_l(void) { int i ; for (i=0; i<MAXHAUTEUR; i++) { libere_liste(ta[i]); ta[i]=NULL; Jean Fruitet - IUT de Marne La Valle - 103

} } void affiche_l(arbre racine) { int i ; libere_l(); cree_l(0,racine); printf("\n"); for (i=0; i<MAXHAUTEUR; i++) if (ta[i]!=NULL) { printf("%d\t",i); affiche_liste(ta[i]); printf("\n"); } } /* MAIN */ void main (int argc, char *argv[]) { int i, c; char str[20]; struct cellule *racine; i=0; if (argc>1) { if ((f=fopen(argv[1], "r"))!=NULL) { printf("Ouverture en lecture de %s\n",argv[1]); while ((c=getc(f))!=EOF) { if ((c==' ') || (c=='\n') || (c=='\t')) { str[i]=0; i=0; printf("%s\n",str); racine=insere(str, racine); } else str[i++]=c; } fclose(f); } } do { printf("MENU : i:inserer s:supprimer a:arbre l:liste q:quitte\n"); do { c=getchar(); } while ((c=='\n') || (c=='\t') || (c==' ')); /* boucler sans rien faire */ switch (c) { case 'i': case 'I' : rewind(stdin); str[0]=0;

Introduction la programmation printf("Etiquette a inserer ?\n"); if (scanf("%s",str)!=0) { printf("Insertion de %s\n ",str); racine= insere(str, racine); } break; case 's': case 'S' : rewind(stdin); str[0]=0; printf("Etiquette a supprimer ?\n"); if (scanf("%s",str)!=0) { printf("Suppression de %s\n ",str); racine= supprime(str, racine); } break; case 'a' : case 'A' : printf("Affichage en profondeur \n"); affiche_p(racine); printf("\n"); fflush(stdout); break; case 'l' : case 'L' : printf("Affichage en largeur \n"); printf("Niveau\tValeurs \n"); affiche_l(racine); fflush(stdout); break; default : break; } } while ((c!='q') && (c!='Q') ); }

Jean Fruitet - IUT de Marne La Valle - 104

Introduction la programmation

Graphes Les graphes interviennent chaque fois qu'on veut reprsenter et tudier un ensemble de liaisons (orientes ou non) entre les lments d'un ensemble fini d'objets. Par exemple reprsenter un rseau routier, lectrique, un circuit lectronique, un rseau informatique, l'ordonnancement de tches, une application hyper-mdia, etc. Aprs des dfinitions et notions fondamentales sur les graphes, nous prsenterons quelques algorithmes lmentaires. Dfinition Un graphe G est un couple (S,A) o : - S est un ensemble fini de sommets ; - A est un sous-ensemble de SxS, ensemble des arcs de G. On prendra gnralement pour S un segment [1,n]. Exemple Reprsentation du graphe orient G1 = (S1,A1) = ({1,2,3,4,5}, {(1,2), (1,3), (2,2), (2,4), (3,1), (4,2), (4,4), (5,4)})

2 1 3

5 Un arc (x,y) reprsente une liaison oriente entre l'origine x et l'extrmit y. Si (x,y) est un arc, x est le prdcesseur de y et y est le successeur de x ; si x=y l'arc est une boucle. Graphe non orient On dit qu'un graphe G = (S,A) est non orient si et seulement si, pour tout si et sj de l'ensemble des sommets S, si (si, sj) est un arc de A, alors (sj, si) aussi. Les arcs s'appellent alors des artes et sont reprsentes par des paires {si, sj}, non orientes bien sr. Exemple Le graphe non orient G2 = (S2, A2), reprsent graphiquement par : S2 = {1,2,3,4,5}; A2 = {(1,5), (2,3), (2,4), (3,2), (3,5), (4,2), (4,5), (5,1), (5,3), (5,4)}

3 1 5 4 2

Proprits Deux sommets x et y d'un graphe orient (respectivement non orient) sont adjacents s'ils sont les extrmits d'un arc (respectivement d'une arte).
Jean Fruitet - IUT de Marne La Valle - 105

Introduction la programmation

Soit un graphe G=(S,A) et T un sous-ensemble de S. L'ensemble des arcs de A dont une extrmit est dans T et l'autre est dans S-T est appel le cocycle associ T. L'ensemble des sommets de S-T adjacents au moins un sommet de T est la bordure de T. Le graphe G=(S,A) est dit biparti s'il existe un sous-ensemble de sommets T tel que A= cocycle(T). Un sous-graphe du graphe G = (S,A) est un couple G' = (S',A') pour lequel S' est inclus dans S, et A' inclus dans A. Le sous-graphe G' est un graphe partiel de G si S'=S. Si A' est l'ensemble des arcs de A dont les deux extrmits sont dans S', le sous-graphe G' est dit induit par S'. Exemple : G3 = (S3, A3) = ({1,2,3,4,5}, {(1,4), (1,5), (2,4), (3,5), (4,3), (5,2)})
(a)
1 2 5 3

(b)

(c)
2

(d)

(a) Graphe orient G (b) Un sous-graphe de G (c) Le graphe partiel induit par les sommets {1, 2, 3, 4} (d) Le sous-graphe induit par les arcs {(1,4) , (4,3)} Le graphe G est biparti parce que tout arc est incident T = {1, 2, 3} (i.e. a l'une de ses extrmits dans T)
Implmentation d'un graphe Trois reprsentations reviennent principalement : la matrice d'adjacence, la matrice d'incidence et la liste des successeurs. Matrice d'adjacence On associe un graphe G = ([1,n], A) une matrice carre d'ordre n valeurs dans {0,1}, appele matrice d'adjacence, telle que quels que soient les sommets i, j de l'ensemble des sommets [1,n], la valeur de l'lment mi,j de la matrice est gal 1 si et seulement si (i,j) est un arc de G, et 0 sinon. Exemple : G1 = ({1,2,3,4,5}, {(1,2), (1,3), (2,2), (2,4), (3,1), (4,2), (4,4), (5,4)}) 2 3 4 5 M1 1 1 0 1 1 0 0 2 0 1 0 1 0 3 1 0 0 0 0 4 0 1 0 1 1 5 0 0 0 1 0 Matrice d'adjacence M1 du graphe orient G1.

Jean Fruitet - IUT de Marne La Valle - 106

Introduction la programmation

G2 = ({1,2,3,4,5}, {(1,5), (2,3), (2,4), (3,2), (3,5), (4,2), (4,5), (5,1), (5,3), (5,4)}) 2 3 4 5 M2 1 1 0 0 0 0 1 2 0 0 1 1 0 3 0 1 0 0 1 4 0 1 0 0 1 5 1 0 1 1 0 Matrice d'adjacence M2 du graphe non orient G2 (la matrice M2 est symtrique). Matrice d'incidence Si G est un graphe sans boucle, sa matrice d'incidence "sommets-arcs" (G) est une matrice |S|x|A| valeurs dans {-1,0,1}, telle que l'lment dx,a de la matrice est gal 1 si x est l'origine de l'arc a, -1 si x est l'extrmit de l'arc a et 0 sinon... Exemple : matrices d'adjacence et d'incidence de G3. G3 = (S3, A3) avec S3= {1,2,3,4,5} liste des sommets et A3= {1,2,3,4,5,6 } liste des arcs numrots 1=(1,4); 2=(4,3) ; 3=(3,5) ; 4=(1,5) ; 5=(2,4) ; 6=(5,2) M3 1 2 3 4 5
1
4 6

1 0 0 0 0 0
1

2 0 0 0 0 1

3 0 0 0 1 0
4
5

4 1 1 0 0 0

5 1 0 1 0 0

3 1 2 3 4 5

1 1 0 0 -1 0

2 0 0 -1 1 0

3 0 0 1 0 -1

4 1 0 0 0 -1

5 0 1 0 -1 0

6 0 -1 0 0 1

2 5
3

Jean Fruitet - IUT de Marne La Valle - 107

Introduction la programmation

Liste des successeurs ou liste d'adjacence On peut aussi dcrire un graphe par un tableau (q1, q2, ... qn) o l'lment qi est un pointeur sur la liste des successeurs du sommet i. Exemple :
1 2 5 3 4

Liste des successeurs pour le graphe G3


Chemins, chanes, circuits, cycles Soit G un graphe orient. Un chemin d'origine x et d'extrmit y est une suite finie non vide de sommets c = (s0, s1, s2 .,.., sp ) telle que s0,=x et sp=y et pour k= 0, 1, .., p-1, (sk , sk+1) est un arc du graphe. La longueur du chemin est p ; c'est le nombre d'arcs (non ncessairement distincts) emprunts par ce chemin. Un chemin est simple si les arcs sont deux deux distincts et il est lmentaire si ce sont les sommets qui sont deux deux distincts... Si p est 1 et que s0= sp le chemin est un circuit (il revient au dpart). Dans le cas de graphes non orients, l'quivalent d'un chemin est une chane et celui d'un circuit est un cycle. Un graphe non orient est connexe si pour tout couple de sommets il existe une chane ayant ces deux sommets pour extrmits. Autrement dit on peut aller de tout sommet du graphe tout autre... Par extension un graphe orient est connexe si sa version non oriente (obtenue en supprimant les orientations et les boucles) est connexe. La connexit est une relation d'quivalence entre les sommets du graphe et ses classes d'quivalences sont appeles composantes connexes du graphe. Fermeture transitive d'un graphe La fermeture transitive d'un graphe G est le graphe G' o deux sommets si et sj sont relis par un arc si et seulement si il existe un chemin dans G allant de si sj . Algorithme de fermeture transitive Les mthodes de test d'existence d'un chemin entre deux sommets sont fondes sur le lemme de Knig qui assure que s'il existe un chemin entre deux sommets d'un graphe, il en existe alors un de longueur infrieure ou gale N, nombre de sommets du graphe. Autrement dit il existe un chemin lmentaire...

Jean Fruitet - IUT de Marne La Valle - 108

Introduction la programmation

2 1

5 3

Graphe G'1, fermeture transitive du graphe orient G1

Arcs initiaux Arc crs par transitivit

Pour calculer la fermeture transitive d'un graphe, nous allons dfinir d'abord deux oprations sur les matrices d'adjacence valeurs boolennes : Soient deux matrices carres M=(mi,j) et N=(ni,j) d'ordre N valeurs boolennes {0,1} ; on dfinit leur somme S et leur produit P par les formules : si,j = MIN (1, mi,j+ ni,j) pi,j = MIN (1, (m i,k x nk,j)1kn ) Pour calculer la fermeture transitive d'un graphe G de N sommets associ une matrice M, on dfinit une suite de matrices d'ordre N, valeurs dans {0,1} dfinie par : M1 = M Mp = M x Mp-1 On montre qu'il existe un chemin de longueur k entre deux sommets i et j de G si et seulement si on a Mk(i,j)=1. Cette remarque combine avec le lemme de Knig fournit un algorithme : la somme boolenne des n matrices M1, M2 ... Mn n'est autre que la matrice associe la fermeture transitive de G. Exercice 1 Ecrire un programme qui possde les fonctionnalits suivantes : - Saisie de la matrice d'adjacence associe un graphe G. - Affichage de la matrice de la fermeture transitive de G. - Rponse la question : Existe-t'il un chemin de longueur k entre les sommets i et j ?.

Exercice 2 1) Saisie d'un graphe 2) Affichage d'un graphe 3) Coloriage 1) Saisie. Un graphe orient G est un ensemble de sommets S et un ensemble d'arcs A. Les sommets sont donns sous forme d'une liste de l'intervalle [1..n], n nombre de sommets. Les arcs sous forme d'une liste de couples (a,b), avec a sommet origine et b sommet extrmit de l'arte. Exemple G = (S,A) avec S=[1..6] A={(1,2), (2,5), (3,2), (3,6), (4,3), (5,6)} Les principales oprations sur les graphes orients sont la lecture des tiquettes associees aux sommets ou aux arcs, l'insertion ou la suppression de sommets et d'arcs,

et le parcours du graphe le long de leurs arcs en suivant l'orientation de ceux-ci. Question 1 Reprsenter graphiquement le graphe G1 = (S1,A1) S1=[1..8] A1={(1,2), (2,1), (2,4), (3,3), (3,5), (4,4), (5,3), (5,5), (6,1), (6,2), (6,4), (6,7)} Plusieurs mthodes permettent de reprsenter un graphe : a) Liste (ou table) de sommets et d'arcs (comme cidessus) b) Matrice d'adjacence c) Liste d'adjacence Question 2 Jean Fruitet - IUT de Marne La Valle - 109

Introduction la programmation Reprsentez les graphes G et G1 par une matrice d'ajacence et par une liste d'adjacence. Question 3 Dfinir le type type_sommet du sommet d'un graphe orient. Dfinir le type type_indice de la position d'un sommet dans la liste des sommets adjacents a un sommet du graphe. Question 4 Ecrire les fonctions C de saisie d'un graphe d'au plus MAXSOMMET et MAXARETE reprsent par a) Tableau d'arcs type_sommet sommets_graphe[MAXSOMMET]; type_sommet aretes_graphe[MAXARETE][2] b) Matrice d'ajacence type_sommet mat_adj[MAXSOMMET][MAXSOMMET]; c) [FACULATIF] liste d'adjacence typedef struct arete{type_sommet a; type_sommet b; struct arete *suivant;}arete; arete *liste_adj[MAXSOMMET]; On prendra soin de dfinir les fonctions de base de manipulation des graphes pour chacune des implantations : type_indice premier(type_sommet s); retourne l'indice du premier sommet rencontre dans la liste des sommets adjacents s (son indice est 0 dans cette liste si on utilise une liste d'ajacence). type_indice suivant(type_sommet s, type_indice i); retourne l'indice du sommet adjacent s qui suit le sommet d'indice i dans la liste des sommets adjacents s. type_sommet sommet(type_sommet s, type_indice i); retourne le sommet d'indice i dans la liste des sommets adjacents s. 2) Affichage. L'affichage du graphe est destin vrifier la qualit de la saisie. Le programme devra aussi afficher les sommets isols... Question 5 Ecrire les fonctions C d'affichage de la liste des arcs d'un graphe d'au plus MAXSOMMET et MAXARETE represent par a) Tableau d'arcs b) Matrice d'ajacence c) Liste d'adjacence 3) Coloriage. Colorier un graphe non orient consiste attribuer une couleur chaque sommet de telle sorte que deux sommets adjacents n'aient pas la mme couleur... Un coloriage optimal est celui qui ncessite le moins de couleurs distinctes... Exemple : le graphe G ncessite 2 couleurs. Question 6 Combien de couleurs ncessite le coloriage de G1 ? Question 7 Ecrire les fonctions C de coloriage d'un graphe d'au plus MAXSOMMET et MAXARETE represent par a) Tableau d'artes b) Matrice d'ajacence c) Liste d'adjacence Ces fonctions devront fournir pour chaque sommet le numro de couleur attribu et le nombre de couleurs utilises. Question 8 Proposer une heuristique pour rechercher un coloriage optimal... Donnes Le graphe des carrefours propos en cours fera l'affaire... Exercice 3 1) Saisie d'un graphe 2) Parcours en profondeur 3) Parcours en largeur Un graphe orient G est un ensemble de sommets S et un ensemble d'arcs A. Les sommets sont donns sous forme d'une liste de l'intervalle [1..n], n nombre de sommets. Les arcs sous forme d'une liste de couples (a,b), avec a sommet origine et b sommet extrmit de l'arte. Reprsentez graphiquement le graphe G2 G2 = (S2,A2) S2=[1..7] A2={(1,2), (2,1), (2,4), (3,3), (3,5), (4,3), (4,6), (5,3), (5,5), (6,1), (6,2), (6,7)} 1) Implantation d'un graphe Question 1 Dfinir le type type_sommet du sommet d'un graphe orient. Dfinir le type type_indice de la position d'un sommet dans la listedes sommets adjacents un sommet du graphe. Dfinir les fonctions de base de manipulation des graphes pour la matrice d'adjacence et la liste d'adjacence... type_indice premier(type_sommet s); retourne l'indice du premier sommet rencontr dans la liste des sommets adjacents s (son indice est 0 dans cette liste si on utilise une liste d'ajacence). type_indice suivant(type_sommet s, type_indice i); retourne l'indice du sommet adjacent s qui suit le sommet d'indice i dans la liste des sommets adjacents s.

Jean Fruitet - IUT de Marne La Valle - 110

type_sommet sommet(type_sommet s, type_indice i); retourne le sommet d'indice i dans la liste des sommets adjacents s. 2) Parcours en profondeur Question 2 Donner la liste des sommets visits dans un parcours en profondeur d'abord en visitant les sommets de 1 7. Question 3 Ecrire la fonction de parcours en profondeur en utilisant les fonctions dfinies au 1 pour une

Introduction la programmation reprsentation par matrice d'adjacence et pour une reprsentation par liste d'adjacence. Cette fonction affichera les sommets visits dans l'ordre prfixe et les arcs. Question 4 Ecrire la fonction de parcours en largeur d'abord pour les deux modes de reprsentation. Question 5 Ecrire une fonction dtectant les circuits dans un graphe.

Jean Fruitet - IUT de Marne La Valle - 111

Introduction la programmation

Tris La recherche dun lment dans un ensemble est bien amliore si les lments sont ordonns. Cest en particulier le cas des recherches de mots dans un dictionnaire. Ordonner les lment consiste effectuer une permutation entre les lments de sorte quaprs celle-ci les lments soient classs tris en croissant (respectivement dcroissant)... Donnes : N, nombre fini des lments. Les lments sont tous du mme type et occupent un espace mmoire fini. Les donnes sont par exemple reprsentes dans un tableau. a[0], a[1], ..., a[N-1] est la liste initiale b[0], b[1], ..., b[N-1] est la liste finale telle que b[0]< b[1] <... < b[N-1]. P est une permutation qui ordonne les lments : b[i] = a[P(i)] avec P une permutation de [0, N[. Pour effectuer le rarrangement, il faut disposer dune relation dordre total sur les lments. Relation dordre Une relation dordre note R sur les lments dun ensemble E est une relation binaire ayant les proprits : Rflexivit : aRa Transitivit : si aRb et si bRc alors aRc Antisymtrie : si aRb et si bRa alors a=b. En gnral une relation dordre est note <. Elle est dordre total si tous les lments de lensemble sont comparables deux deux. Pour les donnes complexes, la relation dordre sera dfinie sur une cl, cest--dire sur une liste dattributs qui identifient de faon unique chaque lment de lensemble. Exemples de relations dordre Droite relle D. On peut dfinir un ordre sur la droite euclidienne en choisissant un point O appel origine et un vecteur unitaire u li lorigine. Cela dfinit sans ambigit un sens de parcours. A chaque point M on associe son abscisse relle x, cest--dire la mesure algbrique du vecteur OM dans le repre (O,u). La relation dordre sur IR induit une relation dordre entre les points de la droite. M1 avant ou confondu avec M2 ssi x1x2.

La droite euclidienne M2 O M1 x1 u x2

D IR

Jean Fruitet - IUT de Marne La Valle - 112

Introduction la programmation

Plan euclidien On peut dfinir une relation dordre entre les points du plan deux dimension P de plusieurs faons. Par exemple en utilisant des coordonnes polaires. Avec un systme de coordonnes cartsiennes, M[x, y], par rapport un repre (O, u, v) avec u et v unitaires non colinaires, il nest pas vident quon puisse dterminer une relation dordre unique. La figure montre que la relation dordre des projections sur une seule droite par exemple OX (droite oriente par u) ne suffit pas ordonner sans ambiguit les points M1, M2 et M3. Par contre en combinant la relation dordre sur les projections sur OX avec une relation dordre sur les projections sur OY, on peut induire un ordre total sur P.
Selon OX : M1 < M3 < M2

Le plan euclidien M2
y3

X IR O u v
y1 x2

M3
x1=x3

y2

M1

IR

Selon OY : M3 < M2 < M1 Pour ordonner le Plan euclidien il faut dfinir un ordre total : par exemple ordre selon OX, et si les abscisses sont gales, ordre selon OY. En ce cas M3 < M1 < M2

Fiche de recensement Un recensement porte sur une population. Chaque lment est reprsent par une fiche : (Numro, Nom, Prnom, Date de naissance, Adresse, Sexe). Plusieurs ordres sont possibles, selon le numro, selon le nom et le prnom, etc. Il importe de dfinir prcisment quelle sera la cl puis on induira lordre sur les objets partir de lordre sur les cls. Oprations lmentaires pour le tri. Toute opration de tri implique de disposer dune fonction de comparaison entre deux lments (ordre des cls), et dune fonction dchange (permutation) entre lments. Algorithmes de tri Les algorithmes de tri ont fait lobjet de nombreuses recherches. Ils diffrent principalement par : - la simplicit de mise en oeuvre, - lefficacit. En gnral ce sont deux contraintes contradictoires. Plus un algorithme est efficace, plus il est sophistiqu et dlicat implanter. Nous commencerons par prsenter des algorithmes dits nafs car trs immdiats. Tri par slection Soit une liste L quelconque, et une liste vide T. L= {-5, 3, 2, 4, 1} ; T= {}.
Jean Fruitet - IUT de Marne La Valle - 113

Introduction la programmation

Principe : Pour trier L, retirer llment minimum de L, L = L - {MIN(L)}; et le placer la fin de la liste trie T. T= T U {MIN(L)}; Recommencer lopration jusqu ce que L soit vide. La liste rsultante T est trie... Exemple L= {-5, 3, 2, 4, 1}; T= {}; L= { 3, 2, 4, 1}; T= {-5}; L= {3, 2, 4 }; T= {-5, 1}; L= {3, 4 }; T= {-5, 1, 2}; L= {4}; T= {-5, 1, 2, 3}; L = {}; T= {-5, 3, 2, 4, 1}; Programme C : void tri_selection(typelement a[], int N) { int i,j; int mini; /* indice du minimum de la liste */ for (i=0; i<N-1; i++) { mini=i; for (j=i+1; j<N; j++) if (a[j]<mini) mini=j; echange(&a[i],&a[mini]); } Complexit de lalgorithme. La recherche du minimum dune liste non trie de N lments ncessite de parcourir toute la liste et N-1 comparaisons. La longueur de la liste diminue chaque itration. Donc le nombre de comparaisons est donn par : (N-1) + (N-2) + .... + 1, soit N (N-1) / 2 comparaisons. Lalgorithme naf est en O(N2) dans tous les cas. Sil y a 1000 lments, cela fait un million de comparaisons ! Cette complexit peut tre amliore si la structure de donnes utilise permet une recherche acclre de llment minimum. Cest le cas du tri maximier ou tri par tas. Tri maximier ou tri par tas [Heap sort] Le tri par tas est aussi un tri par slection, sur place, dont lefficacit est due la structure de donnes astucieuse, un arbre maximier. Sa complexit est O(n log n). Principe : On opre en deux tapes : 1. On fabrique un tas [heap], cest--dire un arbre binaire partiellement ordonn dit arbre maximier qui peut tre reprsent par un tableau tel que a[i] a[2i] et a[i] a[2i+1] pour 1iN. Si on reprsente les lments 2i et 2i+1 comme les fils du noeud i, alors a est un arbre binaire quilibr pour lequel la cl dun noeud nest jamais dpasse par les cls de ses descendants. Pour cela on tamise successivement a[N/2], ..., a[1].
Jean Fruitet - IUT de Marne La Valle - 114

Introduction la programmation

2. Puis on extrait successivement le maximum de larbre, qui par construction se trouve en a[1] en lchangeant avec a[M] pour M = N, N-1, ..., 1. Et comme cette opration a supprim la proprit de tas, on la rtablit en tamisant le nouveau a[1].
Arbre maximier
1 99

a[i] a[2i] et a[i] a[2i+1]


1

99 60
2

2 60 4

3 59 5 50 6

3 7 39

59 40
4

40

29

50 29
6

10 9 20 10 20 11 30

12 19 13 9 14 39 15 19 7

39 10
8

20 20
10

11

30

Le tamisage Le tamisage de a[k] consiste changer itrativement a[k] avec le maximum de a[2k] et de a[2k+1] jusqu ce que la condition de tas soit satisfaite. La procdure tamiser(k, M) insre a[k] parmi a[k] ... a[M] : Exemple : Tamisage 1 24 24 2 5 45 3 81 81 4 2 2 5 45 5 Programme C :
void tamiser(int k; int M) { int j, v; v = a[k]; while (k<= M/2) { j = 2*k; if ((j<M) && (a[j+1] > a[j])) j++; if (v>=a[j]) break; a[k] = a[j]; k = j; } a[k] = v; } void heapsort(int N) { int k; for (k= (N/2)-1; k>=0; k- -) tamiser(k, N); for (k=N-1; k>0; k- -) { echange(&a[0], &a[k]); tamiser(0,k); } } Complexit : O(n log n). /* Tri du TAS ou tri maximier [Heap sort] */ /* JF */ #include <stdio.h> #include <stdlib.h> #define MAXELEMENT 10 int T[MAXELEMENT + 1]; Jean Fruitet - IUT de Marne La Valle - 115

81 45 24 2 5

Heap sort 81 5 45 45 24 24 2 2 5 81

45 5 24 2 81

45 5 24 2 81

2 5 24 45 81

24 5 2 45 81

2 5 24 45 81

5 2 24 45 81

Liste trie 2 2 5 5 24 24 45 45 81 81

Introduction la programmation } void echanger(int *a, int *b) { int temp; temp=*a; *a=*b; *b=temp; } void range_tas(int premier, int dernier) /* Suppose que T[premier], ..., T[dernier] possedent la propriete des maximiers, sauf peut-etre pour les fils de T[premier] */ /* La procedure fait descendre T[premier] jusqu'a restauration de l'ordre partiel sur tout l'arbre */ { int r; r=premier; while (r <= dernier / 2) { if (dernier == 2*r) { if (T[r]>T[2*r]) echanger(&T[r], &T[2*r]); r = dernier; } else if ((T[r]>T[2*r]) && (T[2*r]<=T[2*r+1])) { echanger(&T[r], &T[2*r]); r = 2*r; } else if ((T[r]>T[2*r+1]) && (T[2*r+1]<T[2*r])) { echanger(&T[r], &T[2*r+1]); r = 2*r+1; } else r = dernier; /* sortie du while */ } void TriTas(int n) /* tri par tas de n elements ranges dans le tableau T */ { int i; for (i=n /2; i>=1; i--) range_tas(i,n); for (i=n ; i>=2; i--) { echanger(&T[1], &T[i]); range_tas(1, i-1); } } /* ------------------------- MAIN ----------------- */ void main (void) { int i; srand (1); for (i=1; i<=MAXELEMENT; i++) { T[i]=rand(); } printf("\nLISTE A TRIER ------\n"); for (i = 1; i<=MAXELEMENT; i++) printf("%d ",T[i]); printf("\n--------------------\n"); TriTas(MAXELEMENT); printf("\nLISTE TRIEE ------\n"); for (i = MAXELEMENT; i>=1; i--) printf("%d ",T[i]); printf("\n--------------------\n"); }

Tri bulle Le tri bulle (buble sort) consiste comparer les lments conscutifs et les changer si l'ordre recherch est viol (les bulles lgres remontent vers le haut). Le tri peut se faire sur place, et la fin du tri survient quand plus aucun change na eu lieu au cours dune traverse de la liste. Principe : Faire venir en a[i] llment minimum de a[i], a[i+1], ..., a[N-1] par change dlments adjacents. Exemple : 0 2 2 2 2 5 1 1 1 1 1 1 2 5 2 2 2 1 3 3 3 1 5 3 3 3 3 4 4 3 5 4 4 4 4 4 5 5 4 5 Programme C :
Jean Fruitet - IUT de Marne La Valle - 116

Introduction la programmation

for (i=0; i<N-1; i++) for(j=N-1; j>i; j--) { if (a[j]<a[j-1]) echange(&a[j-1],&a[j]); } Exercice - Ecrire un algorithme de tri bulle amlior en dtectant la fin du tri (aucun change n'a eu lieu lors de la dernire passe) et en ne repassant pas sur les valeurs qui sont dj ordonnes. - Quelle est sa complexit dans le meilleur des cas, dans le pire des cas, et en moyenne ? Tri par insertion Principe : A la i-me tape, insrer a[i] parmi a[1], a[2], ..., a[i-1] dj tris. Exemple : Indice 1 0 5 1 2 2 1 3 3 4 4

2 2 5 1 3 4

3 1 2 5 3 4

4 1 2 3 5 4

1 2 3 4 5

Programme C: void tri-insertion(typelement a[], int N) { typelement v; /* une variable auxiliaire */ int i,j; for (i=1; i<N; i++) { v=a[i]; j=i; while ((j>0) && (a[j-1]>v)) { a[j]=a[j-1]; j--; } t[j]=v; } } Complexit : O(N2) au pire des cas et en moyenne. Tris sur les Listes Une liste est une structure de donnes constitue de cellules chanes les unes aux autres par pointeurs. Une cellule est un enregistrement : typedef struct cellule { int val; struct cellule *suiv ; } *liste;
Jean Fruitet - IUT de Marne La Valle - 117

Introduction la programmation

La tte de liste est dsigne par un pointeur tte de type liste ; cest une cellule qui est chane aux cellules suivantes par l'intermdiaire du pointeur suiv. La dernire cellule n'a pas de successeur. Elle pointe sur NULL.

tte

val
cellule cellule

val
... NULL

val

On dira qu'une liste de valeurs <n1, n2, ..., nk > est trie si n1<=n2 <= ...<= nk . Tri par insertion - Ecrire une fonction liste insere( liste l, int x ) qui, si on l'appelle avec les paramtres x et l pointant sur la liste <n1, n2, ..., nk > trie, rend un pointeur sur une liste de la forme <n1, n2, ...,ni, x, ni+1, ..., nk > elle aussi trie, et laissant intacte la liste l. On crira cette fonction de faon rcursive. Exercice 2 : Tri par insertion et modification - Ecrire une fonction void insere_modifie( liste l, int x ) qui, si on l'appelle avec les paramtres x et l pointant sur la liste <n1, n2, ..., nk > trie, rend la liste l modifie et trie de la forme <n1, n2, ...,ni ,x, ni+1, ..., nk >. On crira cette fonction de faon itrative. Justifier lutilisation dun pointeur sur l.. Exercice 3 : Fonction de tri rcursive - Ecrire une fonction de tri : liste tri_ins ( liste l ) qui fonctionne de la faon suivante : si son argument est vide, elle rend la liste vide. Sinon elle insre (au moyen de la fonction insere) la tte de son argument (premier entier dans la liste) dans la liste obtenue en triant (en utilisant tri_ins) la queue de son argument (suite de la liste passe en argument). Exercice 4 : Fonction de tri itrative Ecrire une fonction de tri :liste tri_ins_iterative (liste l ) de faon itrative qui utilise une liste auxiliaire, initialement vide, laquelle elle ajoute successivement au moyen de la fonction insere_modifie tous les lments de son argument, qu'elle parcourt jusqu'au bout. Puis elle retourne cette liste auxiliaire. Exercice 5 : Complexit - Que pensez-vous de ces deux fonctions de tri, du point de vue de la clart des algorithmes (comment prouver leur correction) ? - Du point de vue de la consommation d'espace mmoire ? - Du point de vue du nombre de comparaisons ?

Jean Fruitet - IUT de Marne La Valle - 118

Introduction la programmation

Shellsort Le shell sort est un tri par insertion, mais au lieu de placer chaque lment sa place dans la sousliste trie de tous les lments qui le prcdent, on le place dans une sous-liste d'lments qui le prcdent distants d'un certain incrment incr, que l'on diminue au cours de passages successifs sur la liste. Cela a pour effet de dplacer trs rapidement les lments trs loigns de leur position finale. Au premier passage on cre des sous-listes d'lments distants de n/2 qu'on trie sparment ; au 2me passage des sous-listes d'lments distants de n/4, qu'on trie leur tour sparment, etc. A chaque passage, l'incrment est divis par deux et toutes les sous-listes tries par insertion squentielle. Le tri s'arrte lorsque l'incrment est nul. - Montrer que si deux lments t[i ] et t[i+n/2k ] ont t changs au kime passage, alors ils restent tris par la suite. - Programmer un shell-sort sur un tableau tir alatoirement de 1000 valeurs. Comparer avec le tri bulle sur le mme ensemble de donnes (nombre de comparaisons et dchanges).

Tri par fusion Ce tri procde suivant le principe "diviser pour rsoudre". On doit disposer de deux fonctions rcursives : 1) Dcoupage rcursif Une fonction rcursive dont la dclaration est : void decoupe(liste l, liste p, liste i ) telle qu'aprs l'appel sur des arguments l = <n1, n2, ..., nk > , p, i, la variable p contienne la liste <n2 ,n4, ...> des lments de rang pair de l, et i contienne la liste <n1, n3, ....> des lments de rang impair de l.. 2) Fusion Une fonction dont la dclaration est : liste fusion ( liste n , liste m) telle que le rsultat de l'appel de fusion sur deux listes tries (hypothse essentielle) n = <n1, n2, ..., nk > et m = <m1, m2, ..., mp > soit une liste trie de longueur k+p contenant tous les lments de n et de m (autrement dit une permutation trie de la liste <n1, n2, ..., nk , m1, m2, ..., mp >). Mais attention, on veut que le nombre de permutations ralises pour effectuer cette opration soit born par k+p. Cette fonction pourra, au choix, tre crite de faon rcursive ou itrative. 3) Tri par fusion A l'aide des deux fonctions prcdentes crire la fonction rcursive de tri par fusion : liste tri_fusion (liste l ) dont le principe est le suivant : si l'argument est vide ou n'a qu'un seul lment, on retourne l'argument comme rsultat. Sinon on dcoupe l'argument en deux sous-listes au moyen de decoupe, on rappelle tri_fusion sur chaque partie, et on obtient ainsi deux listes tries l et l' (expliquer pourquoi ?) On applique la fonction fusion ces deux listes et le rsultat obtenu est, si fusion est correctement crite, une liste trie.

Jean Fruitet - IUT de Marne La Valle - 119

Introduction la programmation

Tri rapide [quick-sort ] Ce tri procde aussi comme le prcdent selon le principe "diviser pour rsoudre". Il diffre essentiellement par la phase "diviser"; 1) Dcoupage ordonn - Ecrire une fonction de dcoupage : void decoupe_ordre ( liste l, int x , liste i, liste s) telle que, aprs appel sur les arguments l = <n1, n2, ..., nk > , x , i, s , la variable i contienne la liste des lments qui sont infrieurs ou gaux x, et la variable s contienne la liste des lments de l qui sont strictement suprieurs x. L'entier x est appel pivot . Cette fonction opre donc une partition de l. 2) Quick-sort. - Ecrire une fonction rcursive de tri : liste tri_quick (liste l ) dont le principe est le suivant : si l'argument est vide, ou n'a qu'un seul lment, on rend l'argument comme rsultat. Sinon, l'argument est de la forme <n, n1, n2, ..., nk > avec (k>=1 ). On utilise la fonction decoupe_ordre pour partitionner la liste <n1, n2, ..., nk > en utilisant n comme pivot. On obtient alors deux listes. Appelons les l1 et l2 . Tous les lments de l1 sont infrieurs ou gaux n, et tous ceux de l2 sont suprieurs n. On trie ces deux listes au moyen de tri_quick et on obtient deux listes tries l'1 et l'2 . On renvoie alors la concatnation de l'1 et n .l'2 qui est une liste trie. Complexit Les algorithmes de tri bulle sont en O(n*n). Lalgorithme quick-sort en O(n log2(n)).

Jean Fruitet - IUT de Marne La Valle - 120

Introduction la programmation

Bibliographie Informatique et calcul numrique Breton Ph., Dufourd G, Heilman E., "Pour comprendre l'informatique",Hachette, 1992 Cohen J.H., Joutel F., Cordier Y., Jech B. "Turbo Pascal, initiation et applications scientifiques", Ellipses, 1989 Leygnac C., Thomas R. "Applications de l'informatique, tudes de thmes en mathmatiques, physique et chimie", Bral, 1990 Piskounov N., Calcul diffrentiel et intgral, Editions Mir, 2 tomes. Algorithmique Aho A., Hopcroft J., Ulman J., Structures de donnes et algorithmes - InterEditions 1987 Beauquier D., Berstel J., Chretienne Ph., Elments dalgorithmique - Masson 1992. Carrez C. Des structures aux bases de donnes - Dunod 1990. Crochemore M. Mthodologie de la programmation et algorithmique - UMLV 1990. Perrin D. "Cours d'Informatique DEUG SSM Module M2" - UMLV 1997 Programmation PATTIS R. E. Karel the Robot, a gentle intrduction to the art of programming - John Wilez & Sons, 1995. Kerninghan B. , Ritchie D. "Le langage C" - Masson 1984 BORLAND, "Turbo C 2.0 "Manuel de l'utilisateur" BORLAND, "Turbo C 2.0 "Manuel de rfrence" Leblanc G., "Turbo C" - Eyrolles 1988 Charbonnel J., "Langage C - Les finesses d'un langage remarquable" - Armand Colin 1992

Jean Fruitet - IUT de Marne La Valle - 121

Introduction la programmation

Table des matires Introduction la programmation informatique Avertissement Caractrisation dun problme informatique Dmarche Introduction linformatique Langage Traitement de l'information Ordinateur Un peu d'histoire Ce qui caractrise un ordinateur Matriel et logiciel Le codage binaire Reprsentation des informations en binaire Passer du dcimal au binaire Passer du binaire au dcimal Oprations usuelles en binaire Oprations logiques Les nombres entiers et les nombres rels dcimaux Oprations sur les entiers Implmentation des entiers non signs Implmentation des entiers signs Algorithme de conversion d'un nombre en binaire complment 2 sur un octet : Les nombres rels. Oprations sur les rels : La notation scientifique normalise Reprsentation des nombres rels en binaire Dcomposition d'un nombre rel dcimal en binaire Rels en double prcision Les nombres rationnels Codage des informations non numriques Textes Les images Les relations Notion dalgorithme 1 3 3 4 5 5 5 6 6 6 7 7 7 7 8 8 8 9 9 10 10 10 11 11 11 11 12 12 12 13 13 13 13 14
Jean Fruitet - IUT de Marne La Valle - 122

Introduction la programmation

Traduction de lalgorithme dans un langage de programmation Types de donnes et structures de contrle Un langage de programmation graphique Modle d'ordinateur abstrait et langage de programmation Variables et types Types simples et types combins Oprations de bases Les structures de contrle du langage Fonction factorisation dun polynme rel de degr 2 Conclusion Le langage C. Caractristiques succintes du langage C Evolutions Structures en blocs Variables locales et variables globales Constantes et variables Mots rservs Types de donnes Instruction d'affectation Transtypage (cast) Oprateurs Oprateurs arithmtiques Oprateurs de comparaison Incrmentation et dcrmentation Structures conditionnelles if / else Conditions imbriques Regroupement d'instructions Affectation conditionnelle Slection (switch) Boucles et sauts Exit Tableaux Tableaux une dimension Affectation Chanes de caractres Tableaux plusieurs dimensions Pointeurs Dclaration de pointeur Oprateur adresse (&) Oprateur valeur (*) Pointeurs et tableaux Tableaux de pointeurs Allocation dynamique de mmoire

14 15 15 16 16 17 17 17 18 18 19 20 21 21 21 23 23 23 24 24 24 24 24 25 25 25 26 26 26 26 27 27 28 28 28 28 28 29 29 29 29 29 30 30

Jean Fruitet - IUT de Marne La Valle - 123

Introduction la programmation

Programme principal et fonctions Dclaration de fonction avec prototypage Dfinition Arguments et valeur retourne. Pointeurs et arguments de fonctions Fonctions rcursives Arguments sur la ligne de commande Structure Dclaration Affectation Union Directives de compilation Typedef #define #include Directives de compilation Les entres/ sorties et les fichiers Fonctions d'entres / sorties Fichiers de donnes Compilation 1) Prcompilation 2) Compilation (compile) 3) Liaison (link) Interdpendance de fichiers Processus itratifs. 1. Rappels mathmatiques 2. Types de donnes et algorithmes Fonctions et sous-programmes Notion de complexit. Amlioration dun algorithme. Des donnes aux structures de donnes Tableaux. Dclaration dun tableau. Tableau de tableaux Assignation un tableau Calcul matriciel () Oprations sur les matrices Rsolution d'un systme d'quations (mthode de Cramer) Calcul du dterminant Inversion de matrice Calcul numrique et programmation de fonctions mathmatiques Calcul des termes dune suite et problmes de dbordement

31 31 31 31 33 34 34 35 35 35 35 36 36 36 36 36 37 37 38 41 41 41 41 41 43 43 43 44 48 50 50 51 51 52 53 53 55 58 58 61 64

Jean Fruitet - IUT de Marne La Valle - 124

Introduction la programmation

Conjecture polonaise Fonctions rcursives Factorielle Exercices de programmation numrique Surface et volume dune sphre Polynme Racine carre dun nombre rel positif Surface dun triangle Limite dune suite Valeur approche de 2/6 Valeur approche de log(n) Termes dune suite Puissance n-ime dun nombre Nombre dor Dcomposition dun cube en somme de nombres impairs Rsolution de f(x)=0 () Mthode dichotomique Mthode du balayage Mthode des parties proportionnelles Mthode de Newton Intgration numrique

64 64 64 65 65 65 65 65 65 66 66 66 67 67 67 68 68 69 70 70 72

f (t)dt =

x k =0

n1

x k+1
k

f (t)dt
72 72 72 73 76 76 76 79 79 79 79 95 95 96 97 98 98 105 105 105 105 106 106
Jean Fruitet - IUT de Marne La Valle - 125

Mthode des rectangles Mthode des trapzes Interpolation () Structures de donnes Structures Exercices Ensembles Dfinition Oprations sur les ensembles Reprsentation des ensembles : tableaux, listes, piles, files Arbres et ensembles ordonns Exemples darbres Reprsentation symbolique des arbres Dfinition axiomatiques des arbres Reprsentation informatique Implantation en Langage C Graphes Dfinition Graphe non orient Proprits Implmentation d'un graphe Matrice d'adjacence

Introduction la programmation

Matrice d'incidence Liste des successeurs ou liste d'adjacence Chemins, chanes, circuits, cycles Fermeture transitive d'un graphe Tris Relation dordre Exemples de relations dordre Droite relle D. Plan euclidien Fiche de recensement Oprations lmentaires pour le tri. Algorithmes de tri Tri par slection Tri maximier ou tri par tas [Heap sort] Tri bulle Tris sur les Listes Tri par insertion Shellsort Tri par fusion Tri rapide [quick-sort ] Complexit Bibliographie Informatique et calcul numrique Algorithmique Programmation Table des matires

107 108 108 108 112 112 112 112 113 113 113 113 113 114 116 117 118 119 119 120 120 121 121 121 121 122

Jean Fruitet - IUT de Marne La Valle - 126

You might also like