ABDELKADER BENHARI
L’ALGORITHMIQUE
The algorithm is the set of rules and techniques that are involved in the definition and design of algorithms, that is to say, systematic process of problem solving to describe the steps to the result. In other words, an algorithm is a finite and unambiguous instructions to give the answer to a problem. If the instructions of an algorithm executed one after the other, the algorithm is called sequential if they run at the same time, it is parallel. If the algorithm operates tasks running on a processor network is called distributed algorithm, or distributed. The word "algorithm" comes from the name of the mathematician Al Khawarizmi (Latinized Algoritmi in the Middle Ages), which, in the ninth century wrote the first systematic work on the solution of linear and quadratic equations.
Table des matières INTRODUCTION A L’ALGORITHMIQUE ........................................................................................................ 4 -
Analyse Algorithme Squelette d’un algorithme Elément de base Schémas algorithmique
APPLICATION ............................................................................................................................................... 13 DEFINITION DES VARIABLES ....................................................................................................................... 14 -
Variable destinée au calcul Variable non destinée au calcul
ENTREE DE DONNEES DANS LA MACHINE ................................................................................................ 15 AFFICHAGE DE RESULTATS ......................................................................................................................... 15 CALCULS........................................................................................................................................................ 15 CONDITIONS................................................................................................................................................. 15 LES STRUCTURES REPETITIVES ................................................................................................................... 16 LES PROCEDURES ET LES FONCTIONS (SOUS-PROGRAMME).................................................................. 19 -
Procédure Fonction
LES CHAINES DE CARACTERES .................................................................................................................... 22 -
Définition Concaténation Conversions Longueur d’une chaîne Sous chaîne d’une chaîne
NOTION DE TABLEAU (OU TABLE OU VECTEUR OU MATRICE -
ARRAY) ............................................. 24
Définition Déclaration du tableau Mise à l’état initial Recherche de donnée dans un tableau
LES METHODES DE TRI USUELLES .............................................................................................................. 28 -
Tri par insertion Tri par sélection Le tri bulle Le tri de shell Tri de shell-Metzner Tri par vecteur d’indice Tri par monotonie
LA RECURSIVITE ........................................................................................................................................... 35 -
Définition Principe
LES FICHIERS ................................................................................................................................................. 37 -
Définition
A.BENHARI
2
-
du fichier Notion d’enregistrement Déclaration des fichiers en algorithme Instruction de manipulation des fichiers Application sur les fichiers séquentiels Les fichiers à accès direct Les fichiers texte
ALGORITHMES ET STRUCTURE DE DONNEES ........................................................................................... 44 -
Les structures arborescentes Graphes Problème de la recherche Problème du tri Quicksort Heapsort
ALGORITHMES NUMERIQUES .................................................................................................................... 58 -
Généralités Systèmes linéaires Ax=b : méthodes directes Factorisation A=LU Factorisation PA=LU Factorisation A=BBt : Cholesky Factorisation A=LDLt : Crout
SYSTEMES LINEAIRES AX=B : METHODES ITERATIVES ............................................................................. 73 -
Principe Méthode Jacobi Méthode Gauss-Seidel Méthode de relaxation Méthodes du gradient
PROBLEMES AU MOINDRES CARRES (LINEAIRE) ...................................................................................... 79 -
Régression linéaire Méthode des équations normales
RESOLUTION DES EQUATIONS NON LINEAIRES ....................................................................................... 81 -
Méthode de dichotomie Généralités Valeurs propres et vecteurs propres
APPROXIMATION POLYNOMIALE & INTEGRATION NUMERIQUE .......................................................... 85 -
Approximations polynomiales
ÉQUATIONS DIFFERENTIELLES.................................................................................................................... 89 -
Généralités Méthode de résolution numérique Méthode de Euler Méthode du développement de Taylor Méthode de Runge - Kutta
EXERCICES CORRIGES .................................................................................................................................. 92 BIBLIOGRAPHIE ......................................................................................................................................... 120
A.BENHARI
3
L’ALGORITHMIQUE
I. INTRODUCTION A L’ALGORITHMIQUE Qu’est ce qu’un algorithme ? "Une suite finie de règles à appliquer dans un ordre déterminé à un nombre fini de données pour arriver, en un nombre fini d'étapes, à un certain résultat, et cela indépendamment des données". Encyclopaedia universalis
I.1. Analyse Définition La décomposition d’un problème en sous problèmes, ensuite des sous problèmes en sous problèmes, on arrive ainsi à des problèmes non décomposables, ou à des tâches élémentaires. Ces tâches élémentaires ordonnées forment la succession des étapes qui permettent à partir d’une situation initiale d’aboutir à une situation finale qui représente la solution du problème de départ. Une première solution peut être rédigée dans un langage non formel (en français par exemple), ensuite traduite dans un langage formel (algorithme), à partir duquel il est possible d’écrire un programme dans un langage de programmation et de l’exécuter sur une machine.
Démarche de décomposition Nous allons détailler un exemple qui montre la démarche de décomposition et comment arriver à résoudre un problème sans faire autre chose que de l’exprimer par des problèmes plus petits. Le problème initial : un individu se trouve devant une voiture et doit la faire démarrer. Entrer dans la voiture Démarrer la voiture Ouvrir la portière Monter Fermer la portière Faire fonctionner la voiture Démarrer la voiture Mettre la clé dans le contact Faire un quart de tour, les voyants doivent s’activer Continuer à tourner la clé jusqu’à ce que la voiture émette un bruit indiquant l’état de marche normal A.BENHARI
4
Appuyer sur la pédale d’embrayage Enclencher la première vitesse Désactiver le frein à main Actionner doucement le démarreur et relâcher progressivement l’embrayage. La solution finale est exprimée par les tâches se trouvant en bas du schéma. Cette succession de tâches s’appelle un algorithme mais il est ici exprimé dans un langage non formel. La situation initiale : individu, et voiture ouverte (non verrouillée). La situation finale : individu dans la voiture et voiture en état de marche. L’algorithme a besoin de certains renseignements externes pour pouvoir fonctionner correctement (voyants, bruit que fait la voiture…etc.) La solution est donnée dans le cas où il n’y a aucun problème, supposons maintenant que la voiture ne veut pas démarrer où qu’une fois démarrée, le conducteur cale ! Que faire ? Il est clair que notre algorithme ne répond plus à la question, et qu’il faut l’améliorer pour qu’il marche dans toutes les situations possibles. Nous allons réécrire notre algorithme. Entrer dans la voiture Démarrer la voiture Ouvrir la portière Monter Fermer la portière Faire fonctionner la voiture Démarrer la voiture Si le conducteur a la clé alors Tant que la voiture n’est pas en état de fonctionnement normal il faut Début Mettre la clé dans le contact Faire un quart de tour, les voyants doivent s’activer Continuer à tourner la clé jusqu’à ce que la voiture émette un bruit indiquant l’état de marche normal Si la voiture ne démarre pas alors Retourner la clé dans le sens contraire Reprendre à : Mettre clé dans contact Fin Appuyer sur la pédale d’embrayage Enclencher la première vitesse Désactiver le frein à main Actionner doucement le démarreur et relâcher progressivement l’embrayage. Si la voiture cale alors Retourner la clé dans le sens contraire Reprendre à : Mettre clé dans contact Fin si Sinon Retourner chercher la clé. A.BENHARI
5
Reprendre à : Mettre clé dans contact Fin si. Ce nouvel algorithme permet de refaire certaines actions si elles ne fonctionnent pas correctement.
I.2. Algorithme Définition Un algorithme est rédigé dans un pseudo-langage et destiné à une machine abstraite (virtuelle). Il permet de décrire formellement toutes les étapes nécessaires qui à partir d’une situation initiale, permettent d’aboutir à une situation finale. Cette dernière constitue la solution qui résout un problème donné. Le langage algorithmique est précis, et suit des règles qui seront décrites tout au long de ce document.
Démarche : Problème, analyse, algorithme Pour illustrer la démarche qui permet d’écrire un algorithme nous allons traiter des exemples concrets 1er exemple : Somme de deux entiers Soit le problème formulé dans les termes suivants : écrire un algorithme qui calcule la somme de deux entiers, et affiche le résultat à l’écran. Le problème ici est simple, il s’agit de calculer la somme de 2 entiers. Le problème ne précise pas où trouver les deux entiers, il est alors possible de supposer que les deux entiers seront donnés par l’utilisateur, ce dernier dialogue avec la machine par l’intermédiaire du clavier. On dit alors que les deux entiers seront saisis au clavier. L’énoncé ne précise pas non plus que faire du résultat, on suppose alors que ce dernier sera affiché sur l’écran. Voici le schéma qui résume notre problème.
Donnée 1 Calcul de Somme
Donnée
Résultat
2
Figure Erreur ! Il n'y a pas de texte répondant à ce style dans ce document.-1
Deux données seront à l’entrée d’une boîte qui réalise le calcul et fournit en sortie la somme de ces deux données. En algorithmique, il est fréquent de parler d’entrée et de sortie. o Les données d’un algorithme sont appelées entrées : elles sont à la base du traitement des algorithmes. o Les résultats d’un algorithme sont appelés sorties : elles sont le fruit des traitements faits par les algorithmes et fournissent une réponse au problème posé.
A.BENHARI
6
La boîte de la figure Figure Erreur ! Il n'y a pas de texte répondant à ce style dans ce document.-1 représente ce que nous allons appeler par la suite un processus de calcul. Ce processus réalise un traitement simple, qui est le calcul de Donnée 1 + Donnée 2. Une fois le résultat obtenu il sera affiché sur l’écran. La totalité du schéma est le processus général et c’est ce qu’il faut concrétiser par un algorithme. Pour écrire cet algorithme nous avons besoin de : 1. Accepter Donnée 1 et la stocker, 2. Accepter Donnée 2 et la stocker, 3. Calculer Donnée 1 + Donnée 2, 4. Stocker le résultat, 5. Afficher le résultat sur l’écran. Nous avons ainsi décomposé le problème comme expliqué dans la section 0, les tâches numérotées de 1 à 5 sont en fait l’algorithme écrit en langage non formel. Il est possible de noter ici, que chaque problème possède la solution dans sa décomposition. Nous allons le traduire dans un langage algorithmique formel, et nous expliquerons les différents mots-clés utilisés au fur et à mesure. Algorithme Somme Variables Donnée1, Donnée2, Résultat : entier Début Ecrire (Donner la donnée numéro 1 ) Lire Donnée1 Ecrire (Donner la donnée numéro 2 ) Lire Donnée2 Résultat = Donnée1+Donnée2 Ecrire (La somme est : Résultat) Fin
I.3. Squelette d’un algorithme Algorithme NomDeLAlgorithme VAR //Déclaration de variables manipulés par l’algorithme Donnée1, Donnée2, Résultat : entier Début //Corps de l’algorithme constitué par les expressions Fin
Un algorithme est défini par un entête donnant le nom de l’algorithme, généralement explicite. L’entête est suivie par une partie déclarative permettant de définir toutes les données qui seront utilisées par l’algorithme. Par la suite entre deux mots-clé Début et Fin, nous retrouvons le corps de l’algorithme qui sera constitué par les différentes expressions permettant de résoudre le problème.
I.4. Eléments de base Types Les types permettent de donner un domaine de définition aux objets manipulés par un algorithme, par exemple des données nécessaires pour un calcul seront définies dans le domaine des réels ou des entiers, un message affiché sera défini dans le domaine des caractères alphanumériques…etc.
A.BENHARI
7
Il existe 5 types de base en langage algorithmique de programmation : Les entiers : définis dans le domaine des entiers naturels et les entiers relatifs. Les réels Les caractères : définit tout ce qui est caractère alphanumérique, « a ».. « z », « 1 ».. « 9 » ainsi que les caractères spéciaux, caractères de ponctuation, etc… Les chaînes de caractères : un assemblage de caractères forme une chaîne. Les booléens : un booléen permet de définir une donnée qui ne peut prendre qu’un avaleur entre deux : vrai ou faux, ou bien 0 ou 1.
Variables Les variables servent à déclarer des objets nécessaires au bon fonctionnement d’un algorithme. Les variables doivent être définies avant leur utilisation, en général en dessous de l’entête de l’algorithme dans une partie qui peut être distinguée par le mot clé VAR. Elles sont définies grâce à l’un des cinq types de base et peuvent accepter une valeur de début appelée valeur initiale. Exemple : Algorithme Exemple VAR Donnée1 : entier Donnée2 : entier Car : caractère Message : Chaîne de caractères VraiOuFaux : booléen Début // Initialisation des différentes variables Car ‘A’ VraiOuFaux Faux Donnée1 10 Donnée2 20 . . . Fin
L’initialisation des variables permet de donner à ces dernières une première valeur. Il n’est pas interdit de changer cette valeur par la suite que ce soit par l’intermédiaire : o d’une autre affectation, o d’une expression de calcul, o d’une lecture au clavier.
Constantes Les constantes sont des données initialisées qui ne changent jamais de valeur pendant toute la durée de l’algorithme. Elles peuvent seulement être lues, utilisées pour un traitement, affichées mais jamais modifiées Algorithme Circonférence Constantes PI = 3,14 VAR Circonférence : réel Rayon : réel
A.BENHARI
8
Début Ecrire (Donner le rayon du cercle) Lire Rayon Circonférence PI * (Rayon)² Ecrire (La circonférence de votre cercle est : Circonférence) Fin.
Dans cet algorithme PI ne peut qu’être utilisée telle quelle, elle ne peut pas être modifiée d’une façon quelconque.
Déclaration La déclaration sert à introduire la donnée (variable ou constante)qui sera utilisée par l’algorithme. Lors de la déclaration d’une donnée il est nécessaire de lui donner un type, et il est parfois possible de lui affecter une valeur de départ. Pour les constantes, la valeur de départ est obligatoire. Il existe deux manières de déclarer une variable en pseudo-langage. NomDeLaVariable [: type de la variable]
Ou bien [Type de la variable] NomDeLaVariable <
Valeur de départ>
Remarque : Il est conseillé de garder le même type de déclaration dans le même algorithme. Exemples : V1 : entier //Déclaration de V1 de type entier Entier V2 0 //Déclaration de V2 de type entier avec une valeur initiale égale à 0 Entier V3 //Déclaration de V3 de type entier sans valeur initiale Il est aussi possible de faire des déclarations « groupées ». Entier V1, V2, V3 // Déclaration de trois variables de type entier par le biais d’une même instruction.
Initialisation L’initialisation d’une variable revient à une affectation d’une première valeur avant toute autre utilisation de cette variable. Les instructions d’initialisation peuvent figurer n’importe où dans l’algorithme, et pas nécessairement au début.
Opérateurs Les opérateurs permettent de modifier des valeurs de données à l’intérieur des expressions. Nous allons distinguer entre trois types d’opérateurs en algorithmique. Le type d’une donnée détermine le type des opérateurs qui peuvent lui être appliqués. Remarque : certains langages de programmation possèdent des opérateurs spéciaux. Opérateurs arithmétiques Les opérateurs arithmétiques sont tous utilisés en algorithmique pour écrire des expressions arithmétiques pouvant être affectées à des variables numériques. Par exemple pour modifier certaines valeurs il est nécessaire d’utiliser des opérateurs. Remarque : Il est aussi possible d’utiliser l’opérateur + pour modifier des chaînes de caractères. + : permet les additions - : permet les soustractions. * : permet la multiplication / : permet la division % ou modulo : le reste de la division entière
A.BENHARI
9
Opérateurs logiques Les opérateurs logiques sont utilisés pour affecter ou modifier les valeurs des données de type booléen. Il en existe trois : o NON : appelé Non logique, c’est un opérateur unaire, o OU : opérateur binaire appelé Ou logique, o ET : opérateur binaire appelé Et logique. Les trois tableaux ci-dessous résument les tables de vérité des opérateurs logiques : Et Vrai Faux
Vrai Vrai Faux
Faux Faux Faux
Ou Vrai Faux
Vrai Vrai Vrai
Faux Vrai Faux
Non
Vrai Faux
Faux Vrai
Opérateurs relationnels Les opérateurs relationnels permettent de comparer des expressions entre elles, le résultat sera une expression logique : vraie ou fausse. Ces opérateurs peuvent comparer entre les types numériques, les types caractères et les types chaînes de caractères. < <= = > >= <> Opérateur Type numérique Type alphanumérique Type chaîne <= 2 <= 3 vrai ‘a’ <= ‘b’ vrai « abc » <= « acc » vrai <= 32.5<=1 faux ‘9’ <= ‘a’ vrai « zze » <= « azerty » faux >= 3 > 2 vrai ‘9’ >= ‘a’ faux « aaaaa » >= « bbbbbbb » faux = 0 = 0 vrai ‘a’ = ‘b’ faux « aaaa » = « fffe » faux <> < >
Expressions Les expressions constituent la base de toute instruction algorithmique. Ils existent des expressions simples et des expressions complexes. Toutes seront étudiées dans les sections suivantes sous la dénomination de schémas algorithmiques. Définition Une variable ou une constante est une expression. Les expressions peuvent être combinées grâce aux opérateurs et donnent ainsi une nouvelle expression.
A.BENHARI
10
Les expressions comme nous le verrons plus loin peuvent aussi contenir des appels de fonctions, ou constituer des appels de procédure. Les expressions constituent les instructions algorithmiques.
I.5. Schémas algorithmiques Schéma algorithmique simple Affectation L’affectation est l’expression de base en algorithmique, elle permet d’associer une valeur quelconque à une variable de l’algorithme. Il est clair que la valeur doit être du même type que la variable. L’affectation comprend 2 parties séparées par le symbole d’affectation « » : o une partie gauche appelée aussi valeur de gauche et constituée par une variable, c'està-dire un objet qui peut prendre une valeur, o une partie droite ou valeur droite constituée par une « expression » pouvant être évaluée. … VAR V1 : entier V2 : réel … Début V1 V1 V2 V2 V2 Fin
10.5 10 32.5 10 25/2
// Affectation erronée // Affectation correcte, on dit que V1 reçoit la valeur 10 // Affectation correcte, V2 reçoit 32.5 // Affectation correcte, les réels englobent les entiers naturels // Affectation correcte, V2 recevra le résultat du calcul de 25 divisé par 2
Lecture de données Une autre manière d’accorder des valeurs à des variables est de faire ce qu’on appelle une lecture de données. La lecture se fait à partir d’un dispositif d’entrée, en l’occurrence un clavier. On l’appelle aussi saisie ou entrée de données. Ce procédé est utilisé à chaque fois qu’une valeur est requise par l’algorithme et que cette valeur ne peut être donnée que par l’utilisateur, c'est-à-dire la personne qui utilise le programme. Bien sûr dans un algorithme il n’y aura pas de véritable saisie à partir du clavier mais seulement une simulation de la saisie. L’algorithme simule une demande de donnée à l’utilisateur et l’accepte pour la stocker dans une variable. Plus tard, l’algorithme sera traduit par un programme, le programme sera compilé et les instructions qui seront exécutables par une machine demanderont une saisie réelle de la part de l’utilisateur. Ce dernier devra taper une donnée du type requis au clavier et valider sa réponse par un retour chariot. La syntaxe permettant de lire une donnée est la suivante : Lire NomDeLaVariable
Ecriture de données L’écriture de données permet un autre type d’interaction avec l’utilisateur : la sortie de messages ou de résultats à l’attention de ce dernier. L’écriture se fait sur un dispositif de sortie tel que l’écran ou l’imprimante par exemple. A.BENHARI
11
La syntaxe communément adoptée est la suivante : Ecrire « Message » Ecrire Valeur
Incrémentation L’incrémentation est une expression particulière qui permet d’augmenter la valeur d’une variable d’une certaine quantité à la fois. V1 V2
V1 + 1 V2 + 2
Décrémentation La décrémentation permet de réduire la valeur d’une variable. V1 V2
V1 - 1 V2 - 2
Schéma algorithmique conditionnel Un schéma algorithmique conditionnel donne à l’algorithme la possibilité d’aller dans un sens plutôt que dans un autre. Une condition est évaluée, et à partir du résultat de cette évaluation un choix est fait.
A.BENHARI
12
II. Application Ennoncé de EXAM1 : on fait passer un examen à des étudiant et l’on veut déterminer ceux qui sont admis . Il y a 3 matières : math (coef 3), français (coef 2) et informatique (coef 5). Les notes peuvent aller de 0 à 20. Il y a admission à la condition d’obtenir la moyenne c'est-à-dire 10 sur 20. Réalisation des spécifications : 3 matières : maths 3 français 2 informatique 5 notes 0 à 20 admis = moyenne de 10/20 minimum c'est-à-dire ajourné pour un total de point <100 mais admis pour un total >= 100 Réalisation d’un organigramme de programmation ou ordinogramme
Début Entrée des notes
Calculé le total Non
Oui Si total >= 100
Admis
Ajourné
FIN
Réalisation de l’algorithme algo exam1 () A.BENHARI
13
/* déterminer admis ajourné*/ /* 0<= notes <= 20 */ const entier coefmath 3 entier coeffran 2 entier coefinfo 5 var locales réel fran, math, info, total début afficher (« Entrez la note de math = » ) saisir (math) afficher (« Entrez la note de français = » ) saisir (fran) afficher (« Entrez la note d’informatique = » ) saisir (info) total math*3 + fran*2 + info*5 ou total math*coefmath + fran*coeffran + info*coefinfo si total >= 100 alors afficher (« ADMIS ») sinon afficher (« AJOURNER ») finsi fin
III. Définition des variables 2 types de variables
a. Variable destiné au calcul Entier : peut contenir un nombre entier entre -32 768 et 32 767. Représentation binaire pure en machine Réel : tous les nombres dont les entiers. Représentation virgule flotante. 0,3458.104 (mentis et caractéristique) Logique ou booléen : 2 valeurs : vrai et faux var locales logique homme début si homme ou si homme = vrai alors afficher (« c’est un homme. »)
b.Variable non destiné au calcul car : un symbole chaîne (longueur) : chaîne de charactère A.BENHARI
14
ex : chaîne (15) phrase …. Phrase « il y a des nuages »
IV. Entrée de données dans la machine saisir (nom_variable)
V.
Affichage de résultats
afficher (« libellé1 », var1, « libellé2 », var2, …)
VI. Calculs Symbole d’affectation total math*3 … Règle hiérarchique des opérateurs : - puissance : ** - multiplication et division : * et / - addition et soustraction : + et – Les parenthèse peuvent changer la hiérarchie des opérations. Réalisation des opérations dans la parenthèse la plus interne.
VII. Conditions Exécution séquentielle des instructions des programmes
Attention au parenthèse si (a=8 et b=3 ou (c=5) ou non d
A.BENHARI
15
VIII. Les structures répétitives
Pour que le programme ne boucle pas indéfiniment, il faut continuellement inclure à l’intérieur de la boucle une instruction capable de modifier la valeur de l’expression testé.
Différentes façon de programmer une boucle : Lors d’un dialogue clavier/écran = question posé à l’opérateur Autres traitement ? (oui/non) Réponse de l’opérateur variable = réponse Analyse du problème : faire n addition de 2 nombre c a+b Début Saisie de a et b Calculer 1 addition prog
Addition (c fois) Affichage du résultat question
fin
tant que réponse = « oui » faire calculer 1 addition autre calcul ? (oui/non) saisir la réponse fin tant que
A.BENHARI
si non
16
Entrez impérativement dans la boucle : réponse « oui » Entrez conditionnelle dans la boucle suivant opérateur : Afficher (calcul ? (oui/non)) algo rep1() var locales entier a, b, c chaîne (3) reponse début afficher (« Voulez-vous faire un calcul ? (oui/non) ») saisir (réponse) c a+b tant que réponse = « oui » faire afficher (« entrez a et b ») saisir (a, b) c a+b afficher (« résultat= », c) afficher (« autre addition ? (oui/non) ») saisir (réponse) fin tant que fin A l’aide d’une marque de fin de travail algo rep2() var locales entier a, b, c début afficher (« Entrez une valeur pour a ou -1 pour terminer.») saisir (a) tant que a <> -1 faire afficher (« entrez b ») saisir (b) c a+b afficher (« résultat= », c) afficher (« Entrez a ou -1 pour terminer.») saisir (a) fin tant que fin
A.BENHARI
17
a. A l’aide d’un compteur Par incrémentation ou décrémentation
i. Par décrémentation algo rep3() var locales entier a, b, c, i début afficher (« Entrez le nombre d’addition à faire.») saisir (i) tant que i > 0 faire afficher (« entrez a et b ») saisir (a, b) c a+b afficher (« résultat= », c) i i-1 fin tant que fin
ii. Par incrémentation algo rep4() var locales entier a, b, c, I, cpt début afficher (« Nombre d’addition.») saisir (i) cpt 0 tant que i > 0 faire afficher (« entrez a et b ») saisir (a, b) c a+b afficher (« résultat= », c) cpt cpt+1 fin tant que fin
A.BENHARI
18
IX. Les procédures et les fonctions (sousprogramme)
Raison des sous programmes : - réutilisabilité - lisibilité du programme - facilité de maintenance - facilité de mise au point
P1 : entrée P2 : entrée-sortie P3 : sortie
A.BENHARI
19
Une fonction ne retourne qu’une valeur, ses paramètres doivent être exclusivement d’entrée (passage par valeur uniquement) Entrée = passage de paramètre par valeur Entrée-sortie et sortie : passage par référence Passage par une valeur : on donne au programme une valeur donné
A.BENHARI
20
a. Procédure Est un sous ensemble indépendant où faisant partie d’un programme principale. Elle communique avec des paramètres entrée-sortie, sorties. Exemple : soit calcul de la somme de 2 nombres : c a + b
procédure somme (a, b, c) val entier a val entier b ref entier c début c a+b fin programme principal algo pp () var locales entier x, y, z début afficher (« Entrez une valeur pour x ») saisir (x) afficher (« Entrez une valeur pour y ») saisir (y) somme (x, y, z) afficher (« Le résultat est », z) fin
b.Fonction Une fonction est une sous partie d’un programme qui retourne 1 valeur donc une fonction possède un type. Elle ne doit posséder que des entrés. Doit contenir la commande retourne (constante, variable, expression arithmétique)
fonction entier fsomme (a,b) A.BENHARI
21
val entier a val entier b var locales entier c début c a+b retourne (c) fin
début retourne (a+b) fin
programme principal algo fpp() var locales entier a, b début afficher (« entrez a et b ») saisir (a,b) afficher (« Résultat », fsomme (a,b)) fin
X.
Les chaînes de caractères a. Définition
C’est un ensemble de caractères affichable. On utilise un code ISO (ASCII) codant 0 – 127 caractère texte et 128 – 255 caractères graphiques - 0 – 31 caractère de contrôle du terminal - 48 – 57 chiffre - 65 … A, B - 97 … a, b caractère alphabétique numérique spéciaux Une chaîne de caractère = caractère concaténé
b.Concaténation Mise bout à bout de caractère pour former une chaîne Mise bout à bout de plusieurs chaînes Opérateur de concaténation = + y = « il fait chaud » // pas de sémantique z = « xyaZb2 » a = « il » b = « fait » c = « froid » d = « chaud » e = « humide » y=a+b+d
A.BENHARI
22
c. Conversions i. Conversions d’une chaîne en entier Fonction chaînant c z
« 2003 » chainant (c)
d « 128 » y c+d y = « 2003128 » r chainant (d) r = 128 w=z+v w = 2131 a chainant (y) a = 2003128 Si erreur chainant = « Za34 » retourne 0 chainant = « 34Za » retourne 34
ii. Conversion d’un entier en chaîne Ent chaine (entier) retourne une chaîne
d.Longueur d’une chaîne Définition de la chaîne var locales chaine (12) a Longueur effective de la chaîne = Longueur de l’espace utilisé longueur (chaine) retourne un entier ex : l
longueur (a)
e. Sous chaîne d’une chaîne z = « Il fait chaud » temperature milieu (z, 9, 5) température = « froid » milieu (chaine, num départ, nombre à partir de départ)
A.BENHARI
23
XI. Notion de tableau (ou table ou vecteur ou matrice array) a. Définition Un tableau est un ensemble de valeurs de même type Types : - prédéfinis = entier, réel, logique, caractère, chaîne - construits = structuré, énuméré Ex d’un tableau d’entier 1, 3, 5, 2, 8, 7 en variable 1 3 A B
5 C
2 D
Tableau t1 1 3 5 2
8
7
1
5
6
2
3
4
8 E
7 F
Valeur Rang dans tableau
t1[3] = 5 5 est la valeur de l’élément de rang 3 du tableau t1 1
2
1 1 3 2 5 2 3 8 7 t1[2ligne,1colone] = 5 rang = 2,1
b.Déclaration du tableau var locales type nom_tableau [taille] taille = 1er valeur … valeur max Ex : soit un tableau de 50 entiers appelé t1 entier t1 [1 … 50] Soit un tableau de 50 chaînes de caractères de 22 caractères chaine (22) t2 [1 … 50]
i. Tableau à 1 dimension On peut le considérer comme linéaire On le remplie avec 1 et 1 seul indice (vecteur) Chaque élément est identique
ii. Tableau à 2 dimensions, 3, n A.BENHARI
24
On peut considérer qu’il s’agit d’une nature contenant l lignes et c colones var locales type nom_tableau [ [1…l], [1 … c] ] exemple à 3 dimensions entier t1 [ [1 … m], [1…l], [1 … c] ] ensemble de matrice Du plus haut niveau au plus bas niveau
c. Mise à l’état initial Mettre les données dans un tableau correspond au chargement des données dans le tableau. RAZ, RAB, VRAI / FAUX - Transfert de variables - Transfert d’autre tableau - Saisie - Donnés de fichiers Exemple de saisie algo saisie () var locales entier t1 [[1..5], [1..3]], l, c début /* -1 pour fin*/ afficher (« entrez un numéro de ligne ») saisir (l) tant que l <> -1 faire afficher (« entrez un numéro de colone ») saisir (c) afficher (« entrez une valeur pour », l, c) saisir (t1[l,c]) afficher (« Entrez un numéro de ligne ou -1 pour quitter » fin tant que fin Exemple de fonction avec passage de tableau fonction entier TOTO (t1[], n) ref entier t1 [1..n] val entier n
d.Recherche de donnée dans un tableau i. Recherche par le rang Ex : afficher (t1 [3])
ii. Recherche séquentielle 1. Sans erreur possible A.BENHARI
25
C'est-à-dire élément cherché se trouve toujours dans le tableau
algo
Début Tableau à trouver
Début traitement
Trouver 1 élément du tableau (t fois)
Trouvé (0,1)
∈t1 (0,1) ∉t1 (0,1)
Trouvé (0,1)
Inter i I n+2 Trouve vrai i i+1
fin
2. Avec erreur possible En italique dans sch précédent. ∈t1 (0,1) ∉t1 (0,1) procédure rechseq (t1 [], n atrouve) ref entier t1[1..n] val entier n val entier atrouver var locales entier i logique trouve début trouve faux i 1 tant que (i<=n) et trouve = faux (non trouve) faire si t1[i]=atrouve alors trouve vrai sinon i i+1 finsi fin tant que si trouve = vrai alors afficher (« l’élément », atrouve, « se trouve en », i, « positions ») sinon afficher (« erreur ») fin si fin
iii. Recherche dichotomique Attention : Cas particulier pour tableau triées A.BENHARI
26
Principe Soit un tableau d’une suite de 8 nombres. 3 5 8 12 15 27 43 75 1 2 3 4 5 6 7 8 Chercher 15 indice mini = 1 indice maxi = 8 indice mil = (mini + maxi) /2 =4 trouve = 12 indice mini mil +1 indice mil 6 trouve = 27 indice maxi mil - 1 indice mil (5+5) / 2 = 5
Tant que (mini<= maxi) et cherche <> trouve procédure
Début
Cherche < t1 [mil] (0,1)
Traiter 1 élément de partage n fois
Si cherche < t1 [mil] <> (0,1)
∈t1 (0,1) ∉t1 (0,1)
Si cherche t1 [mil]
fin
procédure dichotomie (t1[], n, cherche, trouve, rang) ref entier t1[1..n] val entier n val entier cherche ref logique trouve ref entier rang var locales entier mini, maxi, mil
début mini 1 maxi n mil (mini + maxi) / 2 tant que mini <= maxi et t1[mil] <> cherche faire si cherche < t1[mil] alors maxi mil -1 A.BENHARI
27
sinon mini
mil + 1
finsi mil (mini + maxi) / 2 fin tant que si t1[mil] = cherche alors trouve vrai rang mil sinon trouve faux finsi fin
XII. Les méthodes de tri usuelles a. Tri par insertion i. Principe 18 1
5 2
12 3
17 4
14 5
31 6
8 7
Comparer un élément au suivant de la liste si cet élément à une valeur inférieur, il reste en place sinon il est échangé avec celui qui est de valeur inférieur, il s’agit donc pour chaque élément du tableau de lui ménager une petite place parmi ceux qui sont déjà trié en décalant vers le haut ceux qui sont plus grand que trié.
ii. Algorithme procédure tri insère (tab [], n) réf TIND tab [1..n] TIND correspond à un type indéterminé valeur entier n var locales entier i,j TIND temp logique fin
début i 2 tant que i <= n faire temp tab [i] j i-1 fin faux A.BENHARI
28
tant que (j > 0) et (fin = faux) faire si temp < tab [j] alors tab [j+1] tab [j] j j–1 sinon fin vrai fin fin tant que tab [j+1] temp i i+1 fin tant que fin
b.Tri par sélection i. Principe A chaque itération, on choisi le plue petit élément parmi ceux qu’il reste à trier et on le met à sa place.
ii. Algorithme procédure trisélection (tab [], n) ref TIND tab [1..n] val entier n var locales TIND petit entier i, ipetit, j début i 1 tant que i < n faire ipetit i petit tab [ipetit] j i+1 tant que j <= n faire si tab [j] < petit alors ipetit j petit tab [ipetit] finsi j j+1 fintantque tab [ipetit] tab [i] tab [i] petit i i+1 fintantque fin A.BENHARI
29
iii. Remarque Cette méthode conduit à peu de décalage. Elle est pourtant moins rapide que la précédente.
c. Le tribulle i. Principe On parcoure le tableau autant de fois qu’il le faut en comparant les éléments qui se suivent et en les échangeant s’ils ne sont pas dans le bonne ordre. A chaque passage, on peut enlever 1 à n puisque l’on trouve le dernier du tableau à trier.
ii. Algorithme procédure triballe (tab [], n) ref TIND tab [1..n] val entier n var locales logique fin entier i TIND petit
début fin faux tant que fin = faux faire fin vrai i 1 tant que i < n faire si tab [i] > tab [i+1] alors petit tab [i+1] tab [i+1] tab [i] tab [i] petit fin faux finsi i i+1 fin tant que n n –1 fin tant que fin
iii. Commentaire L’un des plus mauvais trie si les données sont très dispersées par contre, il peut très bien convenir pour remettre en ordre des données peu triés.
d.Le tri de shell i. Principe A.BENHARI
30
Pour limiter les déplacements , on choisi de comparer des éléments du tableau dans des parties de tableau. On choisi au départ des parties d’un pas égale à la moitié de la taille du tableau, chaque éléments de la première moitié est comparé à un élément de la seconde. S’il ne sont pas dans le bonne ordre, ils sont échangé puis on diminue le pas en continuant à comparer des éléments dont la distance est égale au pas. De cette façon, les éléments traités sont d’abord des sauts important puis de plus en plus petit jusqu’à ce que le pas soit égale à 1.
ii. Algorithme h n/2 tant que h >=1 faire fin vrai i 1 tant que i <= n-h faire si tab [i] > tab [i+h] alors petit tab [i+h] tab [i+h] tab [i] tab [i] petit fin faux finsi i i+1 fin tant que si fin = vrai alors h h/2 fin si fintantque
iii. Remarque Méthode plus efficace que la précédente dans les cas d’une grande dispersion.
e. Tri de shell-Metzner i. Principe Même principe que pour le shell, au lieu d’ « utiliser », le triballe, on choisi le tri par insertion ( i+1 changé par i +h).
ii. Algorithme h n/2 tant que h>=1 faire i h+1 tant que i<=n faire petit a[i] j i-h tant que petit < a[j] et j >= 1 A.BENHARI
31
faire a[j+h] a[j] j j-h fin tant i i+1 fin tant h h/2 fin tant
iii. Remarque Tri réputé plus rapide que tous les précédant
f. Tri par vecteur d’indice i. Principe Méthode ne manipulant pas directement les éléments du tableau mais utilisation d’un vecteur d’indice qui joue le rôle de pointeur Ex : Avant tri Tab 50 2 1 2 Indice 1 2 1 2
25 -30 45 3 4 5
1 6
3 3
5 5
6 6
Après tri Tab 50 2 25 -30 45 1 2 3 4 5
1 6
Indice 4 6 1 2
1 6
2 3
4 4
3 4
5 5
Résultat : -30, 1, 2, 25, 45, 50
ii. Algorithme (Avec tri par sélection) ideb 1 tant que ieb
32
aux indice [min] indice [imin] indice [ideb] indice [ideb] aux finsi k k+1 fin tant ideb ideb +1 fin tant
iii. Remarque Cette méthode est très intéressante pour manipuler des fichiers de grande taille, on peut donc les trier sans déplacer l’ordonnée.
g. Tri par monotonie i. Principe On part du constat que dans toute suite de nombre entier trié au hasard, on a toujours un certain nombre d’entre eux trié naturellement. On appelle monotonie, une suite de nombre naturellement trié ? Exemple :
ii. Algorithme procedure separation (tab1[], tab2[], tab3[], i1,i2, i3) ref TIND tab1 [1..i1], tab2 [1..i2], tab3 [1..i3] ref entier i2, i3 val entier i1 var locales entier ecrit, i début ecrit 2 i 1 i2 1 A.BENHARI
33
i3 0 tab2[i2]
tab1[1]
tant que i
34
si k <= i3 alors tab1[i] k k+1 finsi
tab3[k]
finsi i i+1 fintant fin algo trimonotonie () var locales entier i1, i2, i3 TIND t1[1..i1], t2[1..i2], t3[1..i3] début i3 1 tant que i3 <> 0 faire séparation (t1[], t2[], t3[], i1, i2, i3) si i3 <> 0 alors fusion (t1[], t2[], t3[], i1, i2, i3) finsi fintant fin
XIII. La récursivité a. Définition On appelle fonction récursive une procédure ou une fonction qui s’appelle elle même. Fonction entier fn(a) Si condition d’arrêt retourne (fn(a)) fin Cette approche permet de simplifier l’écriture de certain programme comme les listes chaînés et les arbres. Elle n’est pas souhaitable pour tout les programmes Elle n’est jamais la meilleur solution du point de vue temps de traitement et de la place occupé en mémoire. Dès la construction de l’algorithme, il faut prévoir une action de fin d’appel (pour ne pas voir le programme bouclé indéfiniment).
b.Principe Ex1 : soit calculer la factoriel d’un nombre. 5x4x3x2x1 = 1200 A.BENHARI
35
à 1 instant t n ! = (n-1) ! * n 0 !=1
fonction entier facto (n) val entier n début si n=0 alors retoune (1) sinon retourne (facto(n-1)*n) finsi fin algo factorielle () var locales entier n début afficher (« Quelle factorielle ? ») saisir (n) afficher (« La valeur est »,facto(n)) fin En C++ int facto (int n) { if (n==0) return (1) else return (facto (n-1)*n) endif } Ex 2: soit la somme des n premiers nombres entiers fonction entier somme (n) val entier n début si n = 0 alors retoune0 sinon retourne (somme (n-1) +n) finsi fin
A.BENHARI
36
Ex 3 : écrire une procédure récursive qui affiche tous les éléments d’un tableau d’entier dans l’ordre croissant de leur indice.
procedure ecrivect (V[], n, i) val entier V[i..n] val entier i,n début si i <= n alors affiche (V[i]) ecrivect (V[], n, i+1) finsi fin
XIV. Les fichiers a. Définition du fichier On appelle fichier un ensemble de donné stocker sur un support externe (exp : diskette, CD, DVD, c’est à dire autre que la RAM). Fichier binaire et texte intéresse l’algo (surtout binaire).
b.Notion d’enregistrement Média = disque dur, trieur On appelle enregistrement un ensemble de donnée sur un sujet déterminé. Un enregistrement est décrit en informatique par une structure Ex : RE étudiant = {numetu, nom, moyenne} types struct entier numetu chaine (30) nom reel moyenne fstruct ETU On met en majuscule les structures pour les différencier des autres telque les variables. A chaque fois que l’on veut identifier un fichier on doit définir la structure de ce fichier Cette structure est généralement déclaré en début de programme et les caractéristiques des fichiers dans les variables globales.
A.BENHARI
37
Transfert logique
En mémoire centrale, 3 zones de travail ou BUFFERS qui réalise les entrée, sortie et travail.
c. Déclaration des fichiers en algorithme Pour éviter les problèmes de recopie, nous déclarons les types de fichiers au niveau global EX : Soit à déclarer un fichier client qui contient un numclient 1 nom, 1 adresse, 1 solde de compte. types types struct entier numroclient chaine (30) nom chaine (80) adresse reel solde fstruct CLIENT Après déclaration des bibliothèque (#iostream.h) var globale CLIENT ennrcli /*déclaration d’un buffer*/ FICHIER (client) ficli /*déclaration d’un fichier construit sur la structure CLIENT*/ ficli est un nom logique
A.BENHARI
38
d.Instruction de manipulation des fichiers -
Ouverture Lecture/ écriture/ suppression
i. Ouverture, fermeture 1. Ouverture OUVRE (nom_fichier_logique, « nom-fichier_physique », mode_d’ouverture) nom_fichier_logique : nom pour le programme. nom-fichier_physique : nom connu pour le système d’exploitation. mode_d’ouverture : - lecture - écriture - Mise à Jour (MAJ) {lecture/écriture} - Extension {après fin de fichier} Fonction : - En ouverture : vérifier que le fichier existe, réserver ensuite un buffer. - Ouverture en écriture : créé le fichier ou l’écraser s’il existe déjà - En MAJ : modifier directement chaque enregistrement - En extension : on efface la fin de fichier actuelle pour enregistrer des données à la suite de celle qui existe déjà. En algo, on peut utiliser une primitive (fonction) système qui est fdef (fin de fichier ; fdef(nom de fichier))
2. Fermeture fermer (nom de fichier logique) Libère le buffer créé à l’ouverture en écriture, enregistrer sur le disque le dernier contenu du tampon.
ii. Lecture, écriture, suppression Lecture Ecriture
lire (nom fichier logique, nom du buffer) ecrire (nom fichier logique, nom du buffer)
Remarque : Encli.nom donnée du buffer toujours nommé par le présence du nom du buffer avant le nom de la donnée séparé d’un point.
A.BENHARI
39
e. Application sur les fichiers séquentiels i. Soit imprimer le contenu d’un fichier sur imprimante Fichier physique : Fiphy Fichier logique : fientr types type struct chaine (25) nom entier nucli fstruct CLIENT var globales CLIENT enrcli FICHIER (CLIENT) fientr chaine (25) snom entier snucli algo lecseq () début ouvre (fientr, « Fiphy », lecture) lire (fientr, enrcli) tant que non fdef (fientr) faire snom enrcli.nom snucli enrcli.nucli imprimer (« » , snom , « », snucli) fintant ferme (fientr) fin
ii. Remarque Le fichier d’entré ne doit pas être créé à partir de l’éditeur de texte mais à l’aide d’un programme de création.
A.BENHARI
40
iii. Création d’un fichier séquentiel types type struct chaine (25) nom entier nucli fstruct CLIENT var globales CLIENT enrcli FICHIER (CLIENT) fisor chaine (25) tnom entier tnucli algo ecriseq () début ouvre (fisor, « Fiphy », ecriture) afficher (« entrez un nom ou fin ») saisir (tnom) tant que tnom <> « fin » faire enrcli.nom tnom afficher (« entrez un numéro ») saisir (tnucli) enrcli.nucli tnucli écrire (fisor, enrcli) afficher (« entrez un nom ou fin ») saisir (tnom) fintant ferme (fisor) fin
f. Les fichiers à accès direct Sachant que les supports externes tel que les disques magnétiques sont adressable, on va les utiliser pour retrouver directement des données Remarque : random (ang) = aléatoire ou au hasard Dans tous les cas il faut créer une correspondance entre une des informations de l’enregistrement et le rang de stockage de l’enregistrement sur le support externe. Algorithme de génération automatique d’adresse ou correspondance direct. Ex : Correspondance direct, rang identifiant externe A.BENHARI
41
Exemple = numéro étudiant = rang de stockage sur le disque
i. Lecture à accès directe types type struct chaine (25) nom entier nucli fstruct CLIENT var globales CLIENT enrcli FICHIER (CLIENT) filogcli chaine (25) snom entier snucli, rang algo lecdir () début ouvre (filogcli, « Fiphy », lecture) afficher (« entrez un numéro de client ou 0 pour fin ») saisir (rang) tant que rang <> 0 faire positionner (filogcli, rang) lire (filogcli, eurcli) snom enrcli.nom stnucli enrcli.nucli afficher (« Nom du client : », snom) afficher (« Numéro du client : » snucli) afficher (« entrez un numéro de client ou 0 pour fin ») saisir (rang) fintant ferme (filogcli) fin
ii. Création a accès direct types type struct chaine (25) nom entier nucli fstruct CLIENT var globales CLIENT enrcli FICHIER (CLIENT) filogcli chaine (25) tnom entier tnucli, rang A.BENHARI
42
algo ecridir () début ouvre (filogcli, « Fiphy », ecriture) afficher (« entrez un numéro de client ou 0 pour fin ») saisir (rang) tant que rang <> 0 faire afficher (« Entrez nom du client ») saisir (tnom) enrcli.nom tnom enrcli.nucli rang positionner (filogcli, rang) ecrire (filogcli, enrcli afficher (« entrez un numéro de client ou 0 pour fin ») saisir (rang) fintant ferme (filogcli) fin
g. Les fichiers texte i. Définition Fichier dont les composantes sont des caractères TEXTE fitext On la particularité d’être divisé en ligne dont la fin est indiquer par un caractère spéciale en général ce caractère et le caractère CR (caracter return). Un fichier texte fait les conversions de formats de données. Les transferts se fond par les noms de variables et non pas par structure complète. Les entrées sorties standards sont généralement de ce type (saisir, afficher, imprimer). Remarque : un fichier texte peut être créé à partir de l’éditeur de texte
ii. Déclaration d’un fichier texte var TEXTE nom_du_fichier_texte (logique)
iii. Action sur un fichier texte 1. Ouverture de fichier ouvre_text (nom_logique, « nom_physique », mode d’ouverture) 2. Transfert de données a. Lecture lire_text (nom_logique, arg1, arg2 …) b. Ecriture A.BENHARI
43
ecrire_text (nom_logique, arg1, arg2 …) 3. Fermeture ferme_text (nom_logique)
XV. Algorithmes et structure de données a. Les structures arborescentes Un arbre est un ensemble d’éléments appelés nœuds ou sommets organisés de manière hiérarchique à partir d’un nœud distingué appelé racine. On repère les nœuds de l’arbre en leur donnant des noms différents.
i. Arbres binaires Un arbre binaire est soit vide, noté Ø, soit de la forme < r, B1, B2 > où r est la racine et où B1 et B2 sont des arbres binaires.
r
B1
B2
On définit intuitivement les notions de sous-arbre, de sous-arbre gauche, de fils gauche, de lien gauche et réciproquement à droite. On définit encore les notions de père, de frère, d’ascendant et de descendant. Les nœuds d’un arbre binaire ont au plus deux fils. Un nœud interne ou double a 2 fils. Un point simple à gauche a seulement un fils à gauche, et réciproquement à droite. Un nœud externe ou feuille n’a pas de fils. De façon généralisée, on qualifie de nœud interne, tout nœud qui n’est pas externe. On appelle les branches de l’arbre tout chemin (suite consécutive de nœuds) allant de la racine à une feuille. Il y a autant de branches que de feuilles. Le bord gauche est le chemin issu de la racine en suivant les liens gauches, et réciproquement à droite. Les caractéristiques d’un arbre sont : - la taille de l’arbre est le nombre total de nœuds. - la hauteur ou niveau d’un nœud x est le nombre de lien sur l’unique chemin allant de la racine à x, notée h(x). - la hauteur ou profondeur de l’arbre A, h( A) = max{h( x )} . x
-
la longueur de cheminement de l’arbre A,
LC ( A) = ∑ h( x ) = LCE ( A) + LCI ( A) avec LCE x
la longueur de cheminement extérieure
∑ h(x ) et LCI la longueur de cheminement intérieure x feuille
∑ h( x ) . x noeud interne
-
la profondeur moyenne externe de A est
On donne la signature du type abstrait arbre binaire : sorte arbre utilise nœud opérations
A.BENHARI
44
PE ( A) =
LCE ( A) . nombre de feuilles
Ø : arbre < – , – , – > : nœud x arbre x arbre racine : arbre nœud gauche : arbre arbre droit : arbre arbre.
arbre
Proposition : Soit un arbre binaire de taille n, de profondeur p et possédant f feuilles. Si on examine les cas extrêmes, on obtient que
p log 2 (n ) ≤ p ≤ n − 1 ; par ailleurs f ≤ 2
d’où
p ≥ log 2 ( f ) .
Représentation des arbres en machines : On utilise la structure récursive des arbres. 1) Dans cette première représentation, le chaînage est symbolisé par des pointeurs. type arbre = adresse de nœud ; type nœud = structure val : élément ; g, d : arbre ; fin ; 1. 2. L’arbre est déterminé par l’adresse de la racine. On gère la mémoire dynamiquement pour les opérations de suppression / insertion. 2) Dans la représentation contiguë, on simule les chaînages par des indices dans un tableau. type arbre = tableau de 1 à N de structure val : élément ; g, d : entier ; fin ; 3. 4. On utilise l’indice 0 pour indiquer qu’il n’y a pas de fils. L’arbre est déterminé par une variable entière contenant l’indice de la racine. On va gérer les cases libres pour des insertions / suppressions. On chaîne les cases libres comme une pile, en utilisant le chaînage g et on utilise une variable entière libre pour indiquer l’indice du « sommet de pile ».
ii. Arbres binaires complets Un arbre binaire est complet si tous les nœuds qui ne sont pas des feuilles ont 2 fils. Propositions : Un arbre binaire complet ayant n nœuds internes possède en tout n+1 feuilles. La démonstration se fait simplement par récurrence. Par ailleurs, on montre qu’il existe une bijection entre l’ensemble des arbres binaires de tailles n, Bn, et l’ensemble des arbres binaires complets de taille 2n+1, BC2n+1. Principe : on ajoute des feuilles de sorte que tout nœud de l’arbre ait deux fils. De plus on établit que
Bn = BC 2 n +1 =
1 C 2nn . n +1
iii. Arbres binaires parfaits, ordre hiérarchique On dit qu’un arbre binaire est parfait si toutes ses feuilles sont situées sur les deux derniers niveau, l’avant dernier étant complet, et les feuilles du dernier sont le plus à gauche possible. Attention ! un arbre binaire parfait n’est pas forcément complet, mais il a toujours au plus un nœud simple (le père de la feuille la plus à droite). On peut représenter un arbre binaire parfait de taille n de manière compacte par un tableau à n cases. Ceci se fait en numérotant les nœuds de 1 à n en partant de la racine, niveau par niveau de gauche à droite (ordre hièrarchique). On a les relation générales suivantes : - le père du nœud d’indice i est à l’indice i / 2 (division entière) ; - le fils gauche d’un nœud i est, s’il existe, à l’indice 2i ; - le fils droit d’un nœud i est, s’il existe, à l’indice 2i+1 ; - les feuilles sont aux indices > n / 2.
A.BENHARI
45
iv. Parcours en profondeur d’un arbre binaire On considère l’opération de parcours qui consiste à examiner systématiquement dans un certain ordre tous les nœuds de l’arbres pour effectuer un traitement de données. Le parcours en profondeur à gauche consiste à partir de la racine et à tourner autour de l’arbre en allant toujours le plus à gauche possible. Procédure Parcours(A : arbre) ; début Si A = Ø Alors T0 Sinon début T1 ; Parcours(g(A)) ; T2 ; Parcours(d(A)) ; T3 ; fin ; fin ; Chaque nœud est visité trois fois. A chaque visite correspond un traitement Ti et un ordre de parcours. T1 s’effectue avant la descente gauche et décrit l’ordre préfixe ou pré-ordre. T2 s’effectue après la remontée gauche et avant la remontée droite, l’ordre associé est l’ordre infixe ou symétrique. Le traitement T3 est réalisé après la remontée droite ; les nœuds sont parcourus dans l’ordre suffixe ou post-fixe. On ajoute un traitement particulier T0 pour les nœuds vides.
v. Arbres généraux Un arbre général, ou simplement arbre, est une structure arborescente où le nombre de fils n’est plus limité à 2. Un arbre A = < r, A1, A2, …, An > est la donnée d’une racine r et d’une suite éventuellement vide de sous-arbres disjoints. Cette suite est une forêt. Un arbre est obtenu en rajoutant un nœud racine à la forêt. On donne la signature des arbres généraux : sorte arbre, forêt utilise nœud opérations cons : nœud x forêt arbre racine : arbre nœud sous-arbre : arbre forêt Ø : forêt ième : forêt x entier arbre longueur : forêt entier insérer : forêt x entier x arbre
forêt
Il n’y a plus de notion de fils gauche ou de fils droit. On parle du ième fils d’un nœud. Dans un parcours à gauche, chaque nœud est rencontré une fois de plus que son nombre de fils. Procédure Parcours(A : arbre) ; début Si sous-arbre(A) = Ø Alors T0 Sinon début i 1; Répéter Ti ; Parcours(ième(sous-arbre(A), i)) ; i++ ; Jusqu’à ce que i > longueur(sous-arbre(A)) ;
A.BENHARI
46
Ti ; fin ; fin ; L’ordre préfixe sur les nœuds est obtenu en ne faisant qu’intervenir que T1. L’ordre suffixe est obtenu en ne faisant intervenir que Ti à l’extérieur de la boucle. Il n’y a pas d’ordre infixe. Représentation des arbres : On représente un arbre général par des listes chaînées dynamiques. type arbre = adresse de nœud ; type nœud = structure val : élément ; premier_fils, frère : arbre ; fin ; Propositions : Le nombre d’arbres généraux de taille n+1 est
1 C 2nn . Par ailleurs, il existe des bijections n +1
entre les forêts de taille n, les arbres généraux de taille n+1, et les arbres binaires de taille n, avec des propriétés intéressantes sur les parcours.
b. Graphes i. Définition Un graphe est un ensemble d’objets modélisés par des sommets, et mis en relation (binaire). Ces relations sont modélisés par des arcs ou des arêtes. Un graphe orienté [non orienté] est un couple
G = S , A où S est un
ensemble fini de sommets, et A un ensemble de paire ordonnées [couple] de sommets appelés arcs [arêtes].
ii. Terminologie Un graphe simple est sans boucle1, et sans liens multiples. Dans un graphe orienté, on dit que y est le successeur de x s’il existe un arc qui mène de x vers y ; on dit en outre que y est adjacent à x. Pour un graphe orienté, on dit simplement que x et y sont adjacents. Un graphe est dit complet si pour tout couple de sommet il existe un arc (ou une arête) les joignant. Dans un graphe orienté, le demi-degré extérieur [intérieur] d’un sommet x, que l’on
d + ( x ) [ d − ( x ) ], est le nombre d’arcs ayant x comme extrémité initiale (finale). Le degré de x est d ( x ) = d + ( x ) + d − (x ) . Pour un graphe non orienté, on définit uniquement le degré d’un sommet x d ( x ) . Dans un graphe orienté, on appelle chemin de longueur L une suite de L+1 sommets (s 0 , s1 L s L ) telles que
note
(si , si +1 ) forme un arc. Pour un graphe non orienté, on parle de chaîne. Dans un graphe orienté [non orienté],
un chemin [une chaîne] dont tous les arcs [arêtes] sont distincts et tels que les sommets aux extrémités coïncident est un circuit [un cycle]. Un graphe orienté est fortement connexe si pour toute paire de sommets distincts s et s’, il existe un chemin de s vers s’ et un chemin de s’ vers s. Un graphe non orienté est connexe, si pour toute paire de sommets distincts, il existe une chaîne les joignant. Une composante fortement connexe [connexe] est un sous-graphe fortement connexe [connexe] maximal.
iii. Graphe et Arbre En théorie des graphes, un arbre est un graphe non orienté, connexe et sans cycle. Soit G un graphe orienté, on appelle racine de G un sommet r tel que, pour tous sommets x distincts de r, il existe un chemin de r vers x. Une arborescence est un graphe orienté G admettant une racine et tel que le graphe obtenu à partir de G en enlevant l’orientation soit un arbre.
iv. Signature graphe orienté sorte sommet utilise booléen, entier 1
lien d’un sommet sur lui-même
A.BENHARI
47
opérations s : entier sommet n° : sommet entier – arc – : sommet x sommet booléen d+ : sommet entier ième_succ : sommet x entier sommet prem_succ : sommet sommet succ_suivant : sommet x sommet sommet Pour les graphes non orientés, on dispose de la même signature en remplaçant – arc – par – arête – et d+ par d.
v. Représentation des graphes On aura deux possibilités classiques de gestion de la mémoire : contiguë et chaînée. Représentation contiguë : Soit n le nombre de sommet d’un graphe ; on définit la matrice d’incidence de dimension n x n noté G et tel que G i, j = vrai ssi il existe un arc de i vers j. Si le graphe est non orienté la matrice d’incidence est symétrique.
[ ]
type graphe = tableau[1 à n, 1 à n] de booléen. La complexité en espace est en O(n²), parcourir les successeurs d’un sommet se fait en O(n), savoir si y est le successeur de x se fait en O(1). Représentation chaînée : Pour chaque sommet si, on forme la liste d’adjacence, qui est la liste chaînée de tous le successeur de si. type graphe = tableau[1 à n] d’adresse de cellule; cellule = structure numéro : entier de 1 à n; suivant : adresse de cellule; fin; Soit
A = ∑ d + ( x ) . La complexité en espace est en n + 2p. Le parcours des successeurs d’un sommet x
s’effectue en
(
)
O d + ( x ) . La consultation complète est en O( A ) . Savoir si y est le successeur de x se fait en
( (x )) , dans le pire des cas.
Od
+
Remarque. Le chaînage peut être simulé dans un tableau. Pour un graphe non orienté, il y a redondance2 d’information.
vi. Parcours en profondeur d’un graphe orienté Le parcours en profondeur un parcours récursif, simulable par une pile. Principe : On utilise une marque (vecteur de n booléens) pour marquer les sommets au fur et à mesure qu’on les rencontre. A partir d’un x de départ, non marqué, on avance dans le graphe en allant toujours vers un nouveau successeur non marqué ; les sommets retenus à chaque fois sont marqués. Quand on ne peut plus avancer, on revient au choix précédent, et on itère la méthode. Procédure Profondeur(x : sommet) ; début i n°(x) ; marque[i] vrai ; pour j de 1 à d+(x) faire début y ième_succ(x, j) ; k n°(y) ; 2
y est le successeur de x et réciproquement
A.BENHARI
48
si non marque[k] alors Profondeur(y) ; fin ; fin_Profondeur ; Programme principal début pour i de 1 à n faire marque[i] faux ; pour i de 1 à n faire si non marque[i] alors profondeur(s(i)) ; fin. 5.
Pour les graphes non orientés, on dispose du même algorithme en remplaçant d+(x) par d.
Les sommets ne sont marqués qu’une seule fois et l’algorithme parcourt un fois et une seule les listes d’adjacence : complexité en
∑ d (x ) , ce qui donne O( A ) pour les listes d’adjacence et O(n² ) pour les +
x
matrices d’adjacence. On considère les arcs x y tels que Profondeur(x) appelle Profondeur(y). Ces arcs couvrants constituent une forêt couvrante constituée d’arborescences disjointes et dont les racines sont les sommets de départ. Les graphes obtenu sans orientation sont des arbres (graphe non orienté, connexe et sans cycle). La forêt couvrante a autant d’arbres recouvrants qu’il y a de composantes connexes dans le graphe. Ainsi le parcours en profondeur résout le test de connexité en temps linéaire.
vii. Parcours en largeur Le parcours par largeur ou par niveau est un parcours itératif qui fonctionne avec une file. Principe : On part d’un sommet x et on visite tous les successeurs y de x ; on réitère l’algorithme sur les sommets y dans l’ordre où on les a rencontrés à partir de x. On utilise toujours une marque de sommets. On utilise une file pour gérer ce parcours par niveaux. Procédure Largeur(x :sommet) début file_vide(file) ; i n°(x) ; marque[i] vraie ; ajouter(file, x) ; tant que non est_vide(file) faire début y premier(file) ; retirer(file) ; pour i de 1 à d+(y) faire début z ième_succ(y,i) ; j n°(z); si non marque[j] alors début marque[j] vraie; ajouter(file,z); fin; fin ; fin ; fin ; Programme principal début pour i de 1 à n faire marque[i] faux ; pour i de 1 à n faire si non marque[i] alors Largeur(s(i)) ;
A.BENHARI
49
fin. On a la même complexité que pour le parcours en profondeur. L’algorithme pour un graphe non orienté s’obtient simplement en remplaçant d+ par d. On a la même propriété sur la forêt couvrante et les composantes connexes que pour le parcours en profondeur.
c. Problème de la recherche i. Introduction Considérons un ensemble de grande taille ayant des caractéristiques communes. On veut faire de manière optimisée des opérations de recherche, d’adjonction et de suppression. A chaque élément, on associe une clé simple (critère unique) : recherche associative. Les bases de données traitent des critères plus généraux et des clés multiples.
Signature sorte ensemble utilise élément, clef opérations clé : élément clef vide : ensemble ajouter : élément x ensemble ensemble supprimer : clef x ensemble ensemble _ ∈ _ : clef x ensemble booléen Remarques : - Si plusieurs éléments ont la même clé, la recherche fournit une solution quelconque parmi les possibilités ; s’il n’y a pas de solutions (échec), on fournit une valeur spéciale. - La suppression commence par une recherche, en cas d’échec de la recherche, la suppression laisse l’ensemble inchangé. - En général, et s’il n’y a pas ambiguïté, on confond l’élément et sa clé. La complexité fondamentale est celle de la comparaison entre deux clés. Si l’ensemble des clés est muni d’une relation d’ordre, on peut les trier avec des algorithmes efficaces. On distingue les méthodes de recherche séquentielle, les méthodes de recherche dichotomique, de hachage, et les méthodes arborescentes.
ii. Arbres binaires de recherche On représente un ensemble ordonné à n éléments par un arbre binaire à n nœuds (les nœuds sont les éléments), et c’est la comparaison avec la valeur d’un nœud qui va orienter la suite de la recherche. Un arbre binaire de recherche est un arbre binaire tel que pour tout nœud x , les nœuds de son sous arbre-gauche s’ils en existent ont des valeurs inférieures ou égales à celle de x, et les nœuds de son sous arbre-droit des valeurs strictement supérieures ;
6.
x
≤x
>x
ce que l’on traduit par g(A) ≤ racine(A) < d(A). On obtient toujours l’ensemble ordonné par un parcours récursif gauche symétrique. Il n’y a pas unicité de la représentation.
A.BENHARI
50
iii. Recherche d’un élément rechercher : valeur × arbre
booléen
On compare l’élément à la valeur de la racine : -
égalité
succès
x = r ➩ rechercher (x , < r , g , d > ) = vraie 7. si le sous-arbre sélectionné est vide, l’élément est absent
échec
rechercher ( x , ∅ ) = faux -
si la valeur est plus petite, on recommence récurcivement dans le sous-arbre gauche ; et réciproquement si la valeur est plus grande dans le sous-arbre droit
x < r ➩ rechercher (x , < r , g , d > ) = rechercher (x , g ) x > r ➩ rechercher (x , < r , g , d > ) = rechercher (x , d ) Complexité : La complexité au pire est en O ( hauteur de l’arbre ).
iv. Adjonction d’un élément aux feuilles ajout_feuille : arbre × valeur
arbre
L’adjonction aux feuilles d’un élément se réalise en deux étapes : - étape de recherche pour savoir où insérer le nouvel élément ; - adjonction elle-même. On compare la valeur de l’élément à ajouter à celle de la racine pour déterminer si on l’ajoute sur le sous-arbre gauche ou droit. x ≤ r ➩ ajout_feuille ( < r , g , d > , x ) = < r , ajout_feuille ( g , x ) , d > x > r ➩ ajout_feuille ( < r , g , d > , x ) = < r , g , ajout_feuille ( d , x ) > Le dernier appel récursif se fait sur un arbre vide ; on crée un nouveau nœud à cette place pour le nouvel élément qui devient donc une feuille. ajout_feuille ( ∅ , x ) = < x , ∅ , ∅ > 8. On peut construire un arbre binaire de recherche par adjonctions successives aux feuilles. 9. On donne l’algorithme d’adjonction aux feuilles (récursif) en LDA : Fonction adjonction_feuille (A : arbre , e : entier ) : arbre début si est_vide(A) alors retourner < e , ∅ , ∅ > sinon si ( e ≤ racine(A) ) retourner < racine(A) , ajout_feuille( g(A) , e ) , d(A) > sinon retourner < racine(A) ,g(A) , ajout_feuille( d(A) , e ) > fin 10. 11. On donne également une version itérative de l’algorithme ( 12. 13. La complexité d’un adjonction est O ( hauteur de l’arbre ).
A.BENHARI
51
voire td…).
v. Adjonction d’un élément à la racine Soit A un arbre binaire de recherche, on veut ajouter x à la racine. On procède en deux étapes : - on coupe A en deux arbres binaires de recherche G et D contenant respectivement tous les éléments ≤ x et tous ceux > x. - construire l’arbre < x , G , D > voire cours…
vi. Suppression d’un élément supprimer : arbre × valeur -
arbre
recherche de l’élément à supprimer suppression qui dépend de la place de l’élément, selon que le nœud est sans fils, avec un seul fils, ou avec deux fils. La suppression d’un nœud sans fils est immédiate. Pour la suppression un nœud avec un seul fils, on remplace ce nœud par son fils. Pour un nœud, avec deux fils, on dispose de deux solutions : soit on remplace le nœud à supprimer par le plus grand élément de son sous-arbre gauche, soit on le remplace par le plus petit élément de son sous-arbre droit.
On donne l’algorithme de suppression en LDA : 14. Fonction suppression ( A : arbre , e : entier ) : arbre début % recherche de l’élément à supprimer % si est_vide(A) alors retourner erreur si ( e < racine(A) ) alors retourner < racine(A), suppression( g(A) , e ) , d(A) ) sinon si ( e > racine(A) ) retourner < racine(A), g(A) , suppression( d(A) , e ) ) % suppression % sinon si est_feuille(A) alors retourner ∅ sinon si est_vide(g(A)) retourner d(A) sinon si est_vide(d(A)) retourner g(A) sinon % on ajoute l’élément le plus à droite du sous-arbre gauche % retourner < max_noeud(g(A)) , retire_max(g(A)), d(A) > fin Fonction max_noeud ( A : arbre ) : entier % retourne le plus grand élément de l’arbre A, le plus à droite % début si est_vide(d(A)) alors retourner racine(A) sinon retourner max(d(A)) fin Fonction retire_max ( A : arbre ) : arbre % retourne l’arbre privé de son plus grand élément %
A.BENHARI
52
début si est_vide(d(A)) alors retourner g(A) sinon retourner < racine(A) , g(A) , retire_ max(d(A)) > fin La complexité est O ( hauteur de l’arbre ).
Conclusion, Tri par arbre binaire de recherche Toutes les opérations ont une complexité dépendant de la hauteur de l’arbre binaire de recherche. Elle varie entre O (log n ) pour des arbres équilibrés et O ( n ) pour des arbres dégénérés. Par conséquent, le tri par arbre binaire de recherche, obtenu par un parcours symétrique de l’arbre, a une complexité en comparaison dans le pire des cas variant entre O ( n log n ) et O ( n² ).
d. Problème du tri i. Introduction Le problème du tri est quasiment le plus important en informatique. Spécification du tri : La donnée est une liste à n éléments ; à chaque élément est associée une clé dont la valeur appartient à un ensemble totalement ordonné ; le résultat est une liste dont les éléments sont une permutation de la liste d’origine, et telle que les valeurs des clés soient croissantes quand on parcourt la liste séquentiellement. Un tri est stable, s’il conserve l’ordre de départ des éléments dont les clés sont égales. En fonction de la capacité mémoire, on distingue le tri interne (tout en mémoire centrale) et le tri externe (mémoire centrale + disque). Pour le tri interne, on a des algorithmes qui travaillent sur place, c’est-à-dire sur la liste de départ et des algorithmes qui manipulent physiquement une copie. On a des algorithmes différents et plus compliqués quand ils se font sur place. On compte le nombre de variables auxiliaires pour évaluer la complexité en mémoire. Le tri interne, sur place, avec un nombre constant de variables auxiliaires possède une bonne complexité en espace. On compte le nombre de comparaisons entre clés et de transferts d’éléments pour évaluer la complexité en temps. On distingue les méthodes simples et les méthodes plus complexes.
ii. Tri par arbre binaire de recherche C’est une méthode plus complexe, qui consiste à créer l’arbre binaire de recherche, puis à faire un parcours symétrique, pour obtenir la liste trieé. voire partie sur les arbres binaires de recherche…
e. Quicksort i. Principe On choisit une des clés de la liste (par exemple, celle du premier élément), et on l’utilise comme pivot. On construit sur place une sous-liste dont les clés sont inférieures ou égales au pivot et une sous-liste dont les clés sont strictement supérieurs au pivot.
≤ pivot
A.BENHARI
p
53
> pivot
Le pivot p a alors sa place définitive. Et on recommence récursivement sur chacune des deux sous-listes. A la fin, la liste est triée par ordre croissant. Remarquons que le choix du pivot est délicat ; de lui dépend l’équilibrage des deux sous listes. On suppose donnée une procédure Placer (e/s t : tableau de 1 à n entiers , e/ i : entier , e/ j : entier , /s k : entier) qui effectue le traitement de t entre les indices i et j en fonction du pivot t[i], et qui rend comme résultat l’indice k où le pivot a été placé et le tableau t réagencé. La procédure générique du quicksort s’écrit : Procédure Quicksort (e/s t : tableau de 1 à n entiers , e/ i : entier , e/ j : entier) utilise localement k : entier début si i < j alors début Placer (t , i , j , k) Quicksort (t , i , k - 1) Quicksort (t , k + 1 , j) fin fin Le tri de la liste complète est obtenu par Quicksort (t , 1 , n). La procédure Placer : La partition et le placement du pivot ne nécessite qu’un parcours.
a i
≤
≤
≤
>
≤
l
k
>
>
>
x
j
j+ 1
On utilise deux compteurs l et k qui partent des extrémités du sous-tableau, et qui vont l’un vers l’autre : - l part de i+1 et avance tant que l’on rencontre un élément ≤ à a. - k part de j et recule tant que l’on rencontre un élément > à a. On échange les deux éléments et on recommence la progression jusqu’à ce que les deux compteurs se croisent : la place définitive du pivot est en k, et on y place le pivot a par échange avec un élément ≤ à a. Si on utilise la procédure Placer sur un sous-tableau qui n’est pas à la fin de ( x = t[j+1] existe ), alors l’élément x est un pivot placé antérieurement. Donc, on a ∀s ∈ i, j , x ≥ t [ s ] . Par conséquent, cet élément x va arrêter la progression du compteur l. Pour utiliser cette propriété (effet de bord) lors de tous les appels, on rajoute un terme en t[n+1] qui contiendra un élément plus grand que tous les autres.
[ ]
15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28.
Procédure Placer (e/s t : tableau de 1 à n entiers , e/ i : entier , e/ j : entier , /s k : entier) utilise localement l : entier début l i +1 k j % boucle : tant que les compteurs ne se croisent pas % tant que l ≤ k faire début tant que t[k] > t[i] faire k-tant que t[l] ≤ t[i] faire l++ % on a t[k] ≤ t[i] et t[l] > t[i] % si l < k alors début échanger t[l] et t[k] l++
A.BENHARI
54
29. 30. 31. 32. 33. 34. 35.
k-fin fin % on met le pivot à sa place définitive % échanger t[i] et t[k] fin
ii. Complexité 36. Complexité de Placer : Considérons un sous-vecteur à p éléments, on la pivot aux p - 1 autres éléments. On effectue en tout p + 1 comparaisons. 37. 38. Complexité du Quicksort, au pire: Le graphe des appels du Quicksort est un arbre binaire. La complexité au pire en nombre de comparaisons est obtenu pour t déjà trié est en prenant à chaque fois le 1er élément comme pivot. Le graphe des appels sera dégénéré (peigne) et va induire une complexité au pire en O ( n² ). 39. 40. Complexité du Quicksort, en moyenne : On suppose que les n nombres sont distincts, et que le pivot va occuper la pième place de la liste à trier. On suppose que toutes les places sont équiprobables ; on a la probabilité 1/n d’avoir le pivot à la place p et donc d’avoir deux sous-listes de taille p - 1 et n - p. On démontre ( voire cours + td ) que la complexité en moyenne est en O (2n log n).
iii. Taille de la pile de récursivité 41. Dans la procédure Quicksort, le 2ème appel est terminal, ce qui veut dire qu’on peut le supprimer, et donc éviter des empilements. Comme un seul appel va être conservé, on l’effectuera systématiquement sur la plus petite des deux sous-listes. La taille de récursion sera en O (log2 n), car on divisera par 2 la taille de la liste d’appel. 42. Procédure Quicksort (e/s t : tableau de 1 à n+1 entiers , e/ i : entier , e/ j : entier) utilise localement k : entier début tant que i < j alors début Placer (t , i , j , k) % on choisit le plus petit % si (j - k) > (k - i) alors début Quicksort (t , i , k - 1) i k+1 fin sinon début Quicksort (t , k + 1 , j) j k-1 fin 43. fin fin
f. Heapsort3 C’est un tri par sélection des minimums successifs basé sur une structure de tas. On va obtenir un tri O (n log n) comparaisons au pire, sans mémoire auxiliaire.
3
Tri par tas
A.BENHARI
55
i. Arbres partiellement ordonnés Un tri par sélection nécessite de savoir localiser et récupérer efficacement ( en O (1), si possible ) le minimum parmi les éléments non encore placés. On considère le cas particulier du type abstrait ensemble où les seules opérations sont : - l’accès à un élément minimum - la suppression du minimum - l’adjonction d’un nouvel élément On représente cette ensemble par un arbre binaire parfait partiellement ordonné. 44. Un arbre partiellement ordonné est un arbre étiqueté par les valeurs d’un ensemble muni d’un ordre total, tel que la valeur associée à tout nœud soit ≤ aux valeurs associées aux fils. La racine contient toujours un élément minimum, accès en O (1). 45. 1) Adjonction d’un élément x On ajoute d’abord x comme une feuille en conservant la structure d’arbre binaire parfait. Puis, on reconstruit l’ordre partiel : y x tant que ( y ≠ racine ) et ( y < père(y) ) faire échanger y et père(y) 46. 2) Suppression du min Une fois la racine enlevée, on place la dernière feuille à la racine, pour conserver la structure d’arbre binaire parfait. Puis, on reconstruit l’ordre partiel : y racine tant que ( y n’est pas une feuille ) et ( y n’est pas ≤ aux deux fils ) faire échanger y et son fils de valeur minimum 47. 48. La complexité en nombre de comparaisons de l’adjonction et de la suppression du minimum est au pire en O (hauteur de l’arbre). Par ailleurs, la hauteur d’un arbre binaire parfait ayant n nœuds est de log 2 n . On utilise la représentation en tableau (ordre hiérarchique) des arbres binaires parfaits. ( structures arborescentes) Le tableau forme le tas.
voire partie sur les
On donne les algorithmes écrits en LDA des procédure d’adjonction et de suppression du minimum : Procédure ajouter ( e/s t : tableau de 1 à N entiers , e/s n : entier , e/ x : entier ) % ajoute l’élément x à t ayant n éléments au moment de l’appel % utilise localement i : entier début si n < N alors début n++ t[n] x i n tant que ( i > 1 ) et ( t[i] < t[i div 2] ) faire début échanger t[i] et t[i div 2] i i div 2 fin fin sinon écrire débordement du tas fin Procédure suppress_min ( e/s t : tableau de 1 à N entiers , e/s n : entier , /s min : entier ) % fournit dans min le minimum pour t ayant n > 0 éléments % utilise localement i, j : entiers
A.BENHARI
56
début min t[1] t[n]
t[1] n-i 1 % tant que l’on est pas sur une feuille % tant que ( i ≤ n div 2) faire début si ( n = 2i ) ou ( t[2i] < t[2i+1]) alors j 2i sinon j 2i +1 si ( t[i] > t[j]) alors début échanger t[i] et t[j] i j fin sinon exit fin fin
ii. Tri par tas Principe : -
Construire un tas contenant les n éléments par adjonction successives ; en O (n log n). Tant que le tas n’est pas vide, faire supprimer le minimum du tas avec réorganisation, mettre ce minimum à sa place définitive ; en O (n log n).
La complexité en comparaison est au pire en O(n log n). On utilise un seul tableau pour le tas et les valeurs des minimums successifs. Le minimum à récupérer est toujours dans t[1]. On mettra les minimums successifs à la droite du tableau, de la droite vers la gauche. A la fin, on obtient l’ensemble dans l’ordre décroissant.
min
49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. t[p+1] 63.
tas à traiter
t[n]
minimums bien plaçés
Procédure heapsort (e/s t : tableau de 1 à n entiers) utilise localement p, min : entiers début % construction du tas % p 0 tant que p < n faire ajouter( t , p , t[p+1] ) % tri % tant que p > 1 faire suppress_min ( t , p , min ) min fin
64. 65. Remarque : l’incrémentation et la décrémentation de p est généré par les procédures en e/s.
A.BENHARI
57
XVI. Algorithmes numériques
a. Généralités i. Normes et rayon spectral Définition norme vectorielle :
x a x , R n → R+ vérifiant : -
x ≥ 0 et x = 0 ⇔ x = 0
-
α .x = α . x
-
x+ y ≤ x + y
Exemple de norme vectorielle : -
Norme 1 :
X
= ∑ xi
1
i
-
Norme 2 :
X
=
2
∑x
2 i
=
X, X
i
-
Norme ∞ :
X
∞
= Sup xi i
Proposition : En dimension finie, toutes ces normes sont équivalentes ; en pratique, on choisit celle qui nous arrange. Définition norme matricielle :
A× B ≤ A . B .
C'est une norme dans l'espace vectorielle Mn(R), avec en plus
ii. Norme matricielle induite : A partir d'une norme vectorielle, on construit une norme matricielle induite :
AX = Sup A = Sup X =1 ou X X X ≠0 Notons de plus que I = 1 .
( AX ) .
≤1
I
En particulier pour la norme 2, on a la relation :
2
(
)
= ρ A t A avec ρ le rayon spectral.
Propriétés : -
AX ≤ A . X et AB ≤ A . B A
Cas de A symétrique : Dans le cas général,
A
2
2
= ρ ( A) = max λi i
= µ max , maximum des valeurs singulières µ i = λi avec λi les valeurs
propres (positives) de la matrice symétrique A -
t
A . (?)
Soit A une matrice carré quelconque n x n. Pour toutes normes de matrice induite, on a
A.BENHARI
58
ρ ( A) ≤ A
.
iii. Conditionnement d’une matrice inversible : Considérons un système linéaire AX=b. L'expérience de Wilson met un évidence une instabilité des calculs dans certains cas. Si l'on modifie sensiblement les paramètres de la matrice A, ou du second membre b, on peut trouver des résultats complètement différends ! -
Cond ( A) = A . A −1
-
Cond (αA) = Cond ( A) Cond ( A) ≥ 1 avec Cond (Id ) = 1
-
Soit une matrice Q orthogonale :
-
Les bons conditionnements sont les petits conditionnements (au mieux 1 pour les matrices orthogonales).
-
Pour A symétrique :
-
QX
Cond 2 ( A) =
2
λ max λ min
= X
2
Cond (Q ) = 1
et
; dans la cas général :
Cond 2 ( A) =
µ max µ min
Théorèmes sur le conditionnement :
Théorème :
AX = B et A( X + ∆X ) = b + ∆b . On a
Théorème :
AX = B et ( A + ∆A)( X + ∆X ) = b . On a
∆X ∆b ≤ Cond ( A) . X b
∆A ∆X . ≤ Cond ( A) X + ∆X A
Remarque : Le conditionnement traduit l'amplification des grandeurs relatives.
iv. Inverse numérique d’une matrice : Soit A une matrice inversible et A-1 son inverse théorique. M est un inverse de A du point de vue numérique si :
M − A−1
-
-
A
−1
M −1 − A
est petit, ce qui correspond à M=A-1
est petit, ce qui correspond à A=M-1
A AM − Id et MA − Id sont petits, ce qui correspond à AM − Id = 0 et MA - Id = 0
On s'adapte au calcul que l'on veut faire. Notons que l'on résout rarement un système linéaire en calculant l'inverse
X = A−1b
A.BENHARI
59
b. Systèmes linéaires Ax=b : méthodes directes i. Formules de Crammer Cette méthode nécessite le calcul d'un déterminant, dont la complexité est en n!. La compléxité de la formule de Cramer est en n 2 n!. Par conséquent, cette méthode n'est pas utilisable en informatique.
ii. Méthode du pivot de Gauss ai ,k i > k , Ligne i − a k ,k n3 L'algorithme à une complexité en . 3 À la kème étape : pour
a Ligne k . On pose l i ,k = i , k . a k ,k
Le problème des coefficients diagonaux nuls : il faut permuter les lignes lorsque apparaît un zéro sur la diagonale. Stratégie du pivot maximum partiel : On permute la kème ligne et la ième ligne avec i tel que
ai , k = Sup al ,k . Pour des raisons de stabilité l ≥k
numérique, on divise par le terme de la colonne k, qui a la plus grande valeur absolue. Stratégie du pivot avec seuil : On effectue une permutation uniquement des
a k ,k < ε . Cependant cette méthode peut être mise en défaut. Il
vaut mieux utiliser la méthode du pivot maximum partiel, qui n'est pas vraiment plus coûteuse en calcul.
iii. Calcul de l’inverse Une idée pour résoudre le sytème Ax=b serait de calculer l’inverse de A. En effet, on a
x = A −1 b .
Méthode de Shermann – Morison Soit A une matrice n x n, réelle inversible, dont on connaît l’inverse A-1 ; soit B une perturbation, on cherche à calculer
( A + B ) −1 .
On démontre que si
c=
−1 . 1 + Y t A −1 X
(
)
B = XY t , alors ( A + B ) = I + c. A −1 B A −1 = A −1 + c. A −1 BA −1 , avec −1
On suppose maintenant que la perturbation ne modifie qu’un seul en
(i, j ) : B = ε .Ei , j = ε . ei × e j . { { t
X
Notons
[
A −1 = (α k , j )1≤ k ,l ≤ n . Alors on trouve (A + ε .E i , j )
−1
]
k ,l
= α k ,l − ε
α k ,i α j ,l 1 + ε .α j ,i
Y
.
iv. Elimination de Gauss On applique la stratégie du pivot partiel maximum, au calcul de l’inverse. On considère une matrice A inversible, de dimension n On résout
Ax = el pour 1 ≤ l ≤ n , ce qui revient à écrire A. A −1 = I . On procède par élimination de Gauss,
ce qui donne une matrice triangulaire supérieure (complexité en n3). Ensuite, on réalise n remontées, une par vecteur el (complexité en n 2).
A.BENHARI
60
En résumé, on a
Ax = el et U .x = M .el avec U = MA une matrice triangulaire supérieure.
On veut traiter tous les seconds membres en une seule passe ; pour cela on considère la matrice n x 2n suivante :
qui après calculs donne
On donne ici un exemple d’écriture en langage de description algorithmique : -
Procédure pivot ( k , l : entiers ; OK : booléens ) Début
A(k , k ) ;
-
Max :=
-
l := k ; Pour i := k+1 à n faire
-
Si max <
-
Alors Début
-
Max :=
A(i, k ) ;
l := i ; Fin ; OK := Max > ε ; Fin ; Procédure permuter ( k , l : entiers ) Début Si k ≠ l Alors Pour j := k à 2n faire Début c := A(k , j ) ;
A(k , j ) : = A(l , j ) ; A(l , j ) := c ;
-
A(i, k )
Fin ; Fin ;
On donne maintenant le programme principal, réalisant le calcul de l’inverse. -
A.BENHARI
Début Initialiser A et lire ε ; /* triangularisation */ Pour k := 1 à n faire Début Pivot (k , l , OK ) ; Si non(OK) Alors Début Ecrire « matrice non inversible » ; Exit echec ; Fin ; Permuter ( k , l ) ; Pour j := k+1 à 2n faire A(k , j ):= A(k , j ) / A(k , k ) ;
61
.
-
Pour i := k+1 à n faire Pour j := k+1 à 2n faire
A(i, j ):= A(i, k ) − A(i, k ) * A(k , j ) ;
Fin ; -
/* n remontées */ Pour k := 1 à n faire Pour i := n-1 à 1 par pas de -1 faire Début s := 0 ; Pour j := i+1 à n faire
s := s + A(i, j ) * A( j , n + k ) ; A(i, n + k ):= A(i, n + k ) − s ;
Fin ; Fin ;
Remarques : - Choix du pivot : pour des raisons de stabilité numérique, on divise toujours par le terme de la colonne k qui a la plus grande valeur absolue (Cf. Pivot partiel maximum). - Recherche du pivot : si la plus grande valeur absolue est inférieure à la précision machine ε, alors on arrête en disant que la matrice n’est pas inversible à ε près (test d’inversibilité informatique). Cependant, elle peut très bien être inversible du point de vue mathématique !
c. Factorisation A=LU Soit A une matrice régulière, de dimension n. Lien avec la méthode de Gauss On applique la méthode de Gauss sans pivoter. U est une matrice triangulaire supérieure réelle, telle que
∏J
k
A =U .
k =1, n
1 1 avec α = − a l , k pour l > k . α k +1,k 1 On donne la définition des matrices J k = l ,k a k ,k M O α n ,k 1 −1 On démontre que l’inverse des Jk existe et que L = ∏ J k est une matrice triangulaire inférieure, avec des 1 k =1, n
sur la diagonale. En fait, on a J k
−1
1 1 − α k +1,k = M − α n ,k
. 1 O 1
Calcul algorithmique des coefficients de L et de U On procède par identification en utilisant les propriétés de L (triangulaire inférieure avec une diagonale de 1) et de U (triangulaire supérieure). On cherche un algorithme par ligne donnant les li , j pour 1 ≤ j ≤ i − 1 et les ui , j pour 1 ≤ j ≤ n . - Pour i := 1 à n faire - Début
A.BENHARI
62
-
Pour j := 1 à i-1 faire j −1 l i , j := ai , j − ∑ l i ,k .u k , j a j , j ; k =1 /* avec l i ,i = 1 */
Pour j := i à n faire i −1
-
u i , j := a i , j − ∑ li ,k .u k , j ; k =1
-
Fin ;
Remarque : L et U écrasent la matrice A. Cas particulier des matrices à « structure bande »
O O O O O O O O O O O O O O O O O -
La largeur de la bande est W = P+Q+1 On ne stocke dans une structure de donnée appropriée que la bande, soit un O(W.N), ce qui est intéressant si W << N.
Propriété fondamentale : La bande se conserve par factorisation LU. On parle de structure de données statique. En revanche, si on utilise des techniques de pivotage au cours d’une factorisation LU sur une matrice bande, alors la structure bande n’est pas conservée. On utilise la méthode uniquement dans le cas, où à priori on ne pivote pas. La condition suffisante la plus connue est « A matrice à diagonale strictement dominante », c’est à dire
∀i ∈ 1, n ai ,i >
Cas des matrices symétriques définies positives (SDP) Cf. factorisation Cholesky et Crout.
d. Factorisation PA=LU P est la matrice des permutations. L est une matrice triangulaire inférieure dont la diagonale se compose de 1. U est une matrice triangulaire supérieure.
A.BENHARI
63
∑a
j =1, n j ≠i
i, j
.
Matrice de permutation élémentaire i ↔ j :
1 Pi , j =
O 1 0
1 1 O 1
1
0 1
→ ligne i → ligne j O 1
Le produit PA permute les lignes i et j de la matrice A. Le produit AP permute les colonnes i et j de la matrice A. (à compléter avec le cours : obtention de la factorisation et utilisation de la factorisation )
A.BENHARI
64
e. Factorisation A=BBt : Cholesky Cette factorisation s'applique pour des matrices A symétriques et positives. Théorème : Soit A une matrice SDP de dimension n. Il existe une et une seule matrice B triangulaire inférieure, telle que A=BBt.
f. Factorisation A=LDLt : Crout Théorème : Soit A une matrice SDP de dimension n. Il existe une et une seule matrice L triangulaire inférieure et D diagonale positive, telles que A=LDLt. Remarque : Crout a le même comportement numérique que Cholesky. Cependant, il est plus utilisé car généralisable au cas complexe. Soit A une matrice symétrique définie positive (quelconque ?). L est une matrice triangulaire inférieure de dimension n dont la diagonale se compose de 1. D est une matrice diagonale de dimension n. L est en fait la matrice B pour laquelle les termes d'une colonne sont divisés par les coefficients bii. D est la matrice dont les coefficients diagonaux sont les bii².
i. Algorithme par ligne pour l’obtention de la factorisation 1 On écrit L = l i, j
0 d1 O O 0 et D = . 1 d n 0
j −1
Il s'agit de calculer les li,j et les di. On a
ai , j = ∑ l ik d k l jk + lij d j . k =0
On établit un algorithme par ligne : Pour la 1
ère
ligne, on écrit
d 1 = a1,1 . Supposons maintenant le calcul j −1
effectué jusqu'à la ligne i-1 ; le calcul de la ligne i est donné par j −1
par
(
)
li, j = ai, j −
∑ (l k =1
ik
d k l jk )
dj
pour
j ≤ i − 1 et
d i = ai ,i − ∑ l ik d k . Ainsi une CNS pour cette factorisation est que les di ne soient pas nuls. k =1
2
On donne l’algorithme correspondant : - Pour i de 1 à n faire - Début - Pour j de 1 à i-1 faire j −1
-
l i , j := ai , j − ∑ (l ik d k l jk ) / d j ; k =1
-
/*
l i ,i := 1 */ j −1
-
k =1
-
(
)
d i := ai ,i − ∑ l ik d k ; 2
Fin ;
A.BENHARI
65
Remarque : L et D écrase la partie triangulaire inférieure de A. On veut maintenant apporter une amélioration à cet algorithme en diminuant les nombres de calcul ; on économise les produits l i ,k .d k , que l’on stocke pour un i fixé dans le vecteur C[k]. On donne l’algorithme modifié : - Pour i de 1 à n faire - Début - Pour j de 1 à i-1 faire Début j −1
-
C[ j] :=
ai , j − ∑ l jk .C[k ] ; k =1
C[ j ] := ; dj
-
li, j
-
Fin ; j −1
-
d i := ai ,i − ∑ lik .C[k ] ;
-
Fin ;
k =1
ii. Algorithme par colonne pour l’obtention de la factorisation Principe : On construit L et D, en procédant par décomposition successives. On réalise le découpage suivant :
d1 A = A1 = v1 d1
d1 , avec v1 un vecteur colonne de dimension n-1, et B1 une matrice carré de dim B1
v1
t
n-1.
O O 1 d1 t v1 .v1 On pose L1 = . , avec B1′ = B1 − , A2 = d1 v 1 B1′ I n −1 O d1 t t Ainsi, on a : A = A1 = L1 A2 L1 . Puis, en réitérant n-1 fois, il vient : A = A1 = (L1 L Ln −1 ) An (L1 L Ln −1 ) . 14243 { 14243 L
A.BENHARI
66
D
Lt
1 O 1 Le produit des matrices Lk = vk dk 1 1 L= O . v2 v1 L 1 d2 d1
donnent la matrice finale O 1
Ce qui correspond en effet à une factorisation de Crout, car la matrice
D = (d i ) est bien diagonale et la matrice
L est bien triangulaire inférieure, par construction. On donne l’algorithme de calcul de L et de D par colonne, qui procède en écrasant la partie triangulaire inférieure de A, (les 1 de la diagonale de L ne sont pas stockés, car on préfère y stocker D) : - Début - Pour k de 1 à n-1 faire - Pour j de k+1 à n faire Début d := a j ,k a k ,k ; -
Pour i de j à n faire
-
a j ,k := d ;
a i , j := ai , j − ai ,k .d ;
- Fin ; - Fin ; La structure donnée d’implémentation serait un vecteur à une dimension stockant consécutivement les colonnes de la partie triangulaire inférieure de A. Remarque fondamentale :
a i , j est modifié par a i ,k et a j ,k .
iii. Etude du remplissage lors de la factorisation de matrices SDP creuses Considérons une matrice A symétrique creuse. On utilise une structure de donnée type profil, il est important de savoir où se trouvent les termes à priori non nuls de L. Une matrice est dite creuse si elle contient « un grand nombre » de termes nuls. Plus précisément, on considère que la matrice est creuse à partir du moment, où son pourcentage de termes nuls permet un gain informatique par rapport à un traitement classique qui la considérerait pleine. Définitions : - Un terme de remplissage apparaît en (i,j) au cours de la factorisation si et seulement si
a i , j = 0 et
l i , j ≠ 0 . On reformule le problème comme la conservation du creux initial de la matrice. -
li,j est logiquement non nul si itération
a i , j ≠ 0 ou ∃k ,1 ≤ k ≤ j − 1 tel que l i , k l j ,k ≠ 0 . C’est à dire, à la kéme
(1 ≤ k ≤ n − 1) un terme ai, j de la matrice A qui est nul, devient non nul ssi
A.BENHARI
67
a j ,k ≠ 0 et a i ,k ≠ 0 avec k ≤ j − 1 . Preuve (algorithme par colonne): a i , j := ai , j − { { ≠0
-
=0
≠0 6 47 4 8 a i ,k .a j ,k
a k ,k
.
Les li,j logiquement non nuls se trouvent à l'intérieur du profil de A.
x x x Exemple de remplissage total : E1 = x 0 x x 0 0 x x 0 0 0
x x → E = x 2 x x x
x x
x
x x
x x
x x
x
Le coefficient (3,2) dépend uniquement des coefficients (3,1) et (2,1) qui sont non nuls, par conséquent le coefficient (3,2) devient logiquement non nul : effet de remplissage. Ensuite, le coefficient (4,2) qui dépend des coefficients (4,1) et (2,1) devient logiquement non nul. (…) Le coefficient (5,3) dépend des coefficients (5,k) et (3,k) pour k variant de 1 à 3-1=2, etc. Remarque : Ainsi, on voit que le phénomène dépend de l’ordre selon lequel on exécute les itérations, c’est à dire de la numérotation des inconnues du système ! Si l’on permute les indices 5 et 1 dans l’exemple précédent, on
x 0 x obtient la matrice suivante : E 3 = 0 0 x 0 0 0 x x x
x x
qui ne produit pas de remplissage ! x
La question qui se pose maintenant est de savoir si l’on peut trouver une matrice de permutation P, telle que la factorisation de la matrice PAPt crée le moins de remplissage possible ? Il n’existe pas de méthode exacte en temps raisonnable et on va utiliser des méthodes approchées (heuristiques).
A.BENHARI
68
iv. Caractérisation du remplissage par les graphes On utilise un graphe afin de déterminer quels sont les termes logiquement non nuls qui vont apparaître au cours du calcul. Le graphe associé à une matrice A symétrique d'ordre n possède n sommets que sont les indices de 1 à n des coefficients de la matrice. Un coefficient non nul est repéré dans le graphe par un arc entre les indices de ligne et de colonne de ce coefficient. Exemple : Graphe associé à la matrice E1 et à la permutation identité :
Considérons une permutation donnée telle que -
Madj ( x k ) = {x j , j > k et tel que (x j , x k ) soit une arête possible}
-
x k avec un numéro plus
rajouter une arête de remplissage pour tout couple de tels sommets non liés entre eux. On fait cela dans l’ordre des k croissants de 1 à n-1. A la fin, on obtient le graphe dit d’élimination.
Exemple : Madj ( x1 ) = {x 2 , x3 , x 4 , x5 } -
et plaçons nous à la kéme itération :
trouver le monotone adjacent de x k qui est l’ensemble de tous les sommets liés à grand,
-
σ ( xi ) = i
Madj ( x 2 ) = { } Madj ( x3 ) = { } Madj ( x 4 ) = { }
remplissage total
pas de remplissage pas de remplissage pas de remplissage
Profil ligne Considérons une matrice SDP A de dimension n. Définition : Pour chaque ligne, on considère la colonne La contribution de la ligne i au profil est croissant de colonne (soit
ci correspondant au premier terme non nul sur la ligne.
Pi = {a i , j , ci ≤ j ≤ i} qui sera effectivement stockée par ordre
i − ci + 1 coefficients). Le profil ligne est l’union des Pi pour i variant de 1 à n. On a
besoin d’un vecteur de dimension n donnant pour tout i la valeur de
ci .
n
La taille du profil est
m = ∑ i − ci + 1 . i =1
Propriété fondamentale : Le profil ligne se conserve par factorisation (statique). Le remplissage est inclus dans le profil ligne. Par conséquent, on va chercher à trouver des numérotations qui tendent à minimiser la taille du profil ligne.
On adapte l’algorithme de factorisation :
li , j := ai , j −
j −1
∑( (l
ik k = max ci , c j
d k l jk )/ d j , ainsi on diminue le volume de
)
calcul. Optimisation du profil ligne Critère approché : On va chercher une numérotation des sommets du graphe
Gσ minimisant le profil A. Pour
cela, on cherche à diminuer la taille m. On utilise un critère local : à i fixé, on va essayer d’obtenir autant que possible de i, ce qui va induire un tassement vers la diagonale.
A.BENHARI
69
ci proche
Le problème en terme de numérotation sur
Gσ est le suivant : « numéroter ses voisins avec des numéros les plus
proches possibles de i ».
v. Numérotation en couches : On partitionne l’ensemble des sommets du graphe par rapport à leur distance à un sommet de départ x. On numérote continûment selon les couches et le plus grand écart varie comme un O(longueur d’une couche). Le nombre de sommets étant fixé, on cherche le sommet x de départ de telle manière que le nombre de couche
h( x ) générés à partir de x soit maximum ; ceci aura tendance à minimiser la longueur des couches.
Exemple : prenons x = 1, on a h(x) = 1.
Algorithme : - Choisir x quelconque - Construire la structure en couche à partir de x - Choisir un sommet y de la couche terminale ayant le moins de voisins et construire les couches à partir de ce nouveau sommet, nécessairement h( y ) ≤ h( x ) - Si h(x) > h(y) Alors réitérer, Sinon, on est dans le cas où h(x) = h(y), et y est le point de départ.
A partir de l’exemple précédent, on choisit y = 2 et on obtient h(y) = 2. En réitérant de nouveau, on obtiendra pas mieux. Donc on déduit x = 2 . On applique le changement de numérotation : Ancien numéro i 1 2 3 4 5 2 1 3 4 5 Nouveau numéro σ (i )
x x x Ce qui donne la transformation suivante : E1 = x 0 x x 0 0 x x 0 0 0
x x → E = 0 4 0 0 x
x x
x
x 0
x
x 0 0
. x
Limitation du remplissage Théorème : CNS de création d’une arête de remplissage Soit Gσ le graphe numéroté associé à la matrice A. Une arête de remplissage
(x , x ) est créée si et seulement si : i
j
-
l’arête est déjà présente dans
Gσ ;
-
il existe un chemin allant de
xi à x j tel que les numéros intermédiaires soient plus petits que ceux des
extrémités.
A.BENHARI
70
Idée de numérotation : Pour mettre en défaut ce théorème, on utilise des séparateurs topologiques. Cette méthode consiste à séparer deux sous-ensembles A et B par un ensemble C, appelé séparateur ; de sorte que tout chemin allant d’un élément de A vers un élément de B passe au moins par un sommet de C. Si on numérote les sommets de C avec des numéros plus grands que ceux affectés à A et B, alors il n’y aura pas d’arête de remplissage créées entre les éléments de A et ceux de B.
A
B C
On applique ce principe de numérotation récursivement par bloc, jusqu’à tomber sur une grille qui n’est plus séparable. Ce faisant on limite excellemment le remplissage, mais le profil risque d’être mauvais. Remarque : Il faut une autre structure de donnée que celle du profil non adapté. Par ailleurs, il y a aussi une indépendance des calculs exploitable sur une machine à architecture parallèle. Exemple : On reprend l’exemple précédent…
A B x x C x x 0 x On effectue le changement de numérotation : E1 = x 0 x → E5 = 0 0 x x 0 0 x 0 0 0 x 0 0 0 x x x x
x x
et x
l’on peut vérifier que cette dernière matrice ne se remplie pas du tout !
vi. Utilisation de la factorisation pour résoudre Ax=b Il s’agit de résoudre Ax = b en utilisant la factorisation de Cholesky - CROUT : en trois étapes. -
Descente : Posons
ALDLt X = b . On procède
y = DLt x et résolvons Ly = b , dont la complexité est en
n2 (matrice triangulaire). 2
On écrit un algorithme utilisant un accès par ligne dans la matrice L. -
y1 := b1 ; i −1
Pour i de 2 à n faire
yi = bi − ∑ li , j y j ; j =1
-
Résolution du système diagonal : Posons
- Pour i de 1 à n faire z i -
=
z = Lt x et résolvons Dz = y (par n divisions).
yi ; di t
Montée : Résolvons finalement L
x = z , dont la complexité est en
n2 . 2
On écrit un algorithme utilisant un accès par ligne dans Lt, ce qui revient à un accès par colonne dans L.
A.BENHARI
71
-
xn := yn ;
Pour i de n-1 à 1 faire
xi := zi −
n
∑l
j = i +1
i, j
t
xj ;
On veut exploiter la symétrie. On ne stocke que L et D ; et on ne stocke pas les 1 de la diagonale de L, qui sont pris en compte directement dans le calcul. Considérons le fait que l’on stocke les données en mémoire de façon mono-dimensionnelle. On va donc être obligé de choisir une organisation ligne par ligne, ou colonne par colonne des données. Si l’on choisit une organisation ligne par ligne, on s’aperçoit que l’algorithme de descente est bien adapté à la structure de données par ligne, tandis que l’algorithme de montée, qui pratique un accès aux données par colonne ne l’est pas. C’est pourquoi, il faut écrire un algorithme de montée accédant aux données par ligne et non plus par colonne. - Pour i de 1 à n faire xi := zi ; - Pour i de n à 2 par pas de -1 faire Pour j de i-1 à 1 par pas de -1 faire x j := x j − li , j xi ;
A.BENHARI
72
XVII. Systèmes linéaires Ax=b : méthodes itératives a. Principe i. Méthode itératives classiques : On cherche à obtenir une suite de vecteur
( X n )n convergeante vers X telle que AX = b .
En posant A = M − N où M est une matrice inversible, on propose la formule de récurrence
MX n +1 = NX n + b ou encore X n +1 = M −1 NX n + M −1b . Si X est solution du problème, il vient que
(X − X ) = (M n
Ainsi pour que X n
−1
N
) × (X − X ) . n
0
(
)
B = M −1 N est appelée la matrice d'itération.
(
→ X , il est nécessaire que M −1 N
)
n
→ 0.
Remarque : Le cadre normale de convergence des méthodes itératives classiques est : « A matrice symétrique définie positive ».
Théorème :
(B ) n
n
ii.
Vitesse de convergence :
→ 0 ssi ρ (B ) < 1 .
Vitesse de convergence : Considérons la matrice d'itération B symétrique, alors le résultat suivant :
xk − x
≤ ρ (B ) . x0 − x 2 .
B
2
= ρ (B ) et l'on obtient
k
2
En conclusion, le rayon spectral de la matrice d'itération mesure la vitesse de convergence. La convergence est d'autant plus rapide que le rayon spectral est plus petit. On admettra que ce résultat ce généralise aux matrices quelconques.
b. Méthode Jacobi −F Notation : A = D − E On pose A = M − N avec M = D et N = E + F selon le schéma ci-dessus. Ce qui donne la formule de −1 −1 récurrence suivante : X n +1 = D (E + F ) X n + D b . Soit
( )
x k = x ki
i =1, n
le vecteur itéré, on donne l’algorithme donnant
x k +1 en fonction de x k .
- Pour i de 1 à n faire -
x ki +1 =
− 1 i −1 j ∑ a i , j x k + ai ,i j =1
n
∑a
j = i +1
i, j
x kj − bi
Théorème : Soit A une matrice symétrique, à diagonale strictement dominante, c'est à dire alors la méthode est convergente car ρ
(D (E + F )) < 1 . −1
A priori, cette méthode converge pour une matrice A SDP.
A.BENHARI
73
a i ,i > ∑ a i , j i≠ j
c. Méthode Gauss-Seidel Boucle directe On reprend le schéma de matrice précédent et on pose s'écrit :
(D − E )X n+1 = FX n + b .
M = D − E et N = F . La formule de récurrence i −1
i
On calcule x k +1 , l'ième composante du vecteur X k +1 :
ai ,i x ki +1 = −∑ ai , j x kj+1 − j =1
n
∑a
j = i +1
i, j
x kj + bi .
On propose l’algorithme suivant : - Pour i de 1 à n faire -
x ki +1 =
i −1 j − ∑ ai , j x k +1 − j =1
1 a i ,i
n
∑a
j = i +1
i, j
x kj + bi
j On procède par écrasement du vecteur X k : x k +1 , 1 ≤ j ≤ i − 1 1442443 déjà calculés Boucle rétrograde Cette fois, on pose M = D − F et N On propose l’algorithme suivant :
t
x ki +1 { calcul en cours
j xk , i + 1 ≤ j ≤ n .
= E.
- Pour i de n à 1 faire -
x ki +1 =
i −1 j − ∑ a i , j x k − j =1
1 a i ,i
n
∑a
j = i +1
i, j
x kj+1 + bi
Conclusion Théorème : Soit A une matrice symétrique définie positive, alors la méthode est convergente car ρ
((D − E ) F ) < 1 . −1
Comparaison : Si A est SDP les méthodes de Jacobi et de Gauss-Seidel convergent, et Gauss-Seidel converge plus vite que Jacobi car
ρ ( J ) = ρ (L )2 avec J = D −1 (E + F ) et L1 = (D − E )−1 F ou (D − F )−1 E .
d. Méthode de relaxation Pour cette méthode, on pose
M =
D 1− w − E et N = M − A = D + F , avec w ≠ 0 . On donne la w w −1
matrice d’itération :
D 1 − w Lw = − E D + F . Ainsi pour w = 1 , on se ramène à la méthode de w w
Gauss-Seidel. Théorème : Soit A une matrice SDP. Il y a convergence si et seulement si vrai si et seulement si Remarque : -
w ∈ ]0,2[ .
w = 1 : Gauss-Seidel w < 1 : Sous-relaxation w > 1 : Sur-relaxation
A.BENHARI
74
ρ (Lw ) < 1 . On démontre que ceci est
Boucle directe i
On veut calculer x k +1 :
a i ,i w
i −1
x ki +1 = −∑ ai , j x kj+1 − j =1
n
∑a
j =i +1
i, j
1 x kj + − 1a i ,i x ki + bi . Comme dans Gaussw
Seidel, on note que l'algorithme procède par écrasement. - Pour i de 1 à n faire -
x ki +1 = (1 − w)x ki −
w i −1 j ∑ ai , j x k +1 + ai ,i j =1
n
∑a
j =i +1
i, j
w x kj + bi a i ,i
Choix de w :
O Soit A une matrice symétrique définie positive, et tridiagonale par blocs : A = . O −1 On cherche un w optimal, c'est à dire qui rend ρ M N minimum. On établit dans le cas des matrices 2 tridiagonales : woptimal = et ρ Lwoptimal = woptimal − 1 . 2 1 + 1 − ρ (L1 )
(
(
)
)
Note : On utilise aussi cette méthode de façon heuristique pour des matrices qui ne sont pas tridiagonale.
Dichotomie : Si l’on cherche
woptimal par dichotomie, l’expérience montre qu’il faut obligatoirement procédé
par valeurs supérieures (la fonction
w a ρ (Lw ) possède pour w > woptimal une pente de 1).
Évaluation du rayon spectral de L :
x k +1 = L1 .x k + c d’où x k +1 − x k = L1 .( x k − x k −1 ) . On utilise la x k = L1 .x k −1 + c x k +1 − x k méthode de la puissance itérée et on déduit : ρ (L1 ) = lim . En pratique, on fait l’approximation k →∞ x − x k k −1 On écrit les itérés de Gauss-Seidel :
pour des itérés dont l’écart a diminué de manière significative.
Schéma d’implémentation : - Soit x0 donné - On réalise p itérations avec Gauss-Seidel, on obtient la suite des itérées jusqu’à xp à partir de laquelle on évalue de manière approchée ρ (L1 ) et woptimal .
w = woptimal .
-
Puis on applique la méthode de relaxation avec
-
On s’arrête lorsque l’on a atteint la précision désirée.
Remarque : Toute la difficulté réside dans la choix de p. Il faut que le nombre total d’itérations soit être compétitif avec Cholesky. Le choix de p se fait au cas par cas.
A.BENHARI
75
<< n pour
e. Méthodes du gradient4 Principe : méthode de la plus grande descente Soit A une matrice symétrique définie positive. Théorème : Soit J ( X ) =
AX , X − 2 b, X . Alors X est solution de AX = b , si et seulement si X réalise
le minimum de J. En dimension 1, A = a et J ( x ) = ax
2
− bx (équation de parabole) ; d'où le minimum de J est
correspond bien à la solution de l'équation linéaire
ax = b .
b , ce qui a
Formule de récurrence : Prenons un X0 quelconque, et supposons que nous ayons obtenu par itération Xk. Considérons la courbe de niveau k {X tel que J ( X ) = J ( X k )} , pour calculer Xk+1, on se déplace du point Xk, appartenant là a courbe de niveau k, dans la direction de son gradient : ainsi la formule de récurrence : X k +1
=
gk , gk Ag k , g k
1 grad = AX k − b . On donne 2
= X k − θ k g k . Il reste maintenant à choisir la valeur de θ k , de sorte que
J soit le plus petit possible. On montre que prendre θ k
gk =
J ( X k +1 ) = θ k
2
Ag k , g k − 2θ k g k , g k + J ( X k ) , donc il faut
.
On résume le passage de Xk à Xk+1 : -
g k = AX k − b
-
θk =
-
X k +1 = X k − θ k g k
gk , gk Ag k , g k
Algorithme du gradient conjugué Dans cette méthode, on va utiliser un ensemble de directions conjugués.
g k est la meilleure direction locale,
mais pas à long terme, sinon l'algorithme convergerait d'un coup! D'où l'idée, d'apporter une correction pour le choix de la direction. On pose
X k +1 = X k + α k d k avec d k = − g k + β k −1 d k −1 . En résolvant le système obtenu, par annulation des
dérivées partielles pour la fonction J (qui doit être minimum), on calcule les valeurs des coefficients α k On va maintenant résumer la méthode : - Initialisation : X 0 quelconque, -
g 0 = AX 0 − b , et d 0 = − g 0 .
Passage de l'indice k à l'indice k+1 : On suppose que l'on connaît X k , d k , et
αk =
et β k −1 .
g k . On calcule
gk , gk , d'où X k +1 = X k + α k d k . Ad k , d k
4
Cette partie a été rédigée en privilégiant les notes de cours plutôt que celle de TD, où les notations et les méthodes diffèrent sur quelques points.
A.BENHARI
76
-
On prépare la suite en calculant :
g k +1 = g k + α k Ad k ou AX k +1 − b ; β k =
g k +1 , g k +1 gk , gk
et
d k +1 = − g k +1 + β k d k . Remarque : On démontre que la correction apportée dans cette méthode est optimale. Formule par récurrence : On démontre après coup que cette méthode donne la solution de l'équation linéaire au bout de N itérations ! Par conséquent, on pourrait la considérer comme une méthode directe, mais on préfère la prendre comme une méthode itérative, et s'arrêter pour k ≤ N quand la précision est satisfaisante. Préconditionnement : Convergence de la formule :
Cond ( A) − 1 X 0 − X . Notons que plus Cond(A) est petit, plus la On établit que : X k − X ≤ A A Cond ( A) + 1 convergence est rapide. En particulier, si Cond ( A) = 1 , alors on converge d'un coup, c'est à dire X0 est déjà solution ! Rappelons : Cond ( A) ≥ 1 . Ici, on voit que la vitesse de convergence va dépendre de la matrice A, et k
plus particulièrement de son conditionnement. On va alors introduire la notion de préconditionnement. Transformation : On cherche à résoudre un autre système un meilleur conditionnement. On considère
~ ~ ~ AY = b ayant même solution, mais pour lequel la matrice A possède
~ ~ ~ ~ C = E.E t . On pose A = E −1 . A.E −t et b = E −1b . Ainsi AX = b ⇔ A Y = b pour
Y = Et X . Remaque : Les algorithmes passant par l'intermédiaire de Y sont dits non transformés. Lorsque Y n'apparaît plus dans le calcul l'algorithme est dit transformé. Algorithme du gradient préconditionné transformé : Prenons un X0 quelconque, et supposons que nous ayons obtenu par itération Xk. On pose
g k = AX k − b et
−1
hk = C g k , ce qui revient à résoudre Chk = g k . Résolution d'un système linéaire ! Certes. Mais simple, puisqu'on a supposé auparavant, que l'on avait une factorisation de Cholesky de la matrice C, c'est à dire
~ C = E.E t (algorithme de complexité n²). Ensuite, on calcule θ k = faisant
~ X k +1 = X k − θ k hk .
Ainsi, on obtient le résultat fondamental suivant
Xk − X
A
g k , hk Ahk , hk
. Et on passe de Xk à Xk+1 en
() ()
k ~ Cond A − 1 X0 − X ≤ ~ Cond A + 1
. Il faut à présent A
~
= E −1 AE t , ~ −1 par où nous pouvons déduire que Cond A = Cond C A , car ces deux matrices ont les mêmes valeurs travailler pour que le conditionnement de à soit meilleur que celui de A. Or, nous avons posé A
()
(
)
propres. Choix de C (méthode heuristique) : -
Factorisation incomplète de Cholesky : Lorsque l'on pose A =
BB t , il peut sur venir un phénomène de t remplissage ! D'où l'idée de réaliser une factorisation incomplète A = EE + R . On ne calcule dans la matrice E que les l i , j tels que a i , j ≠ 0 , pour lesquels donc on évite le phénomène de remplissage.
Si l'on pose C = BB = A , on obtient un conditionnement de 1 (le meilleur) car peut se produire un phénomène de remplissage peut souhaitable. Et si l'on pose C n'est pas amélioré par rapport à celui de A. t
A.BENHARI
77
C −1 A = Id ; cependant il = Id , le conditionnement
On va alors prendre C = EE (factorisation incomplète de Cholesky), ce qui correspond à un compromis entre le choix d'un bon conditionnement pour à et la disparition du phénomène de remplissage. Factorisation incomplète de Crout: On peut tout aussi bien utiliser Crout (qui est la méthode proposée en t
-
TD). Dans ce cas, A = LDL − R et on prend C = LDL . Voici deux conditions suffisantes chaques à l’existence : A est une matrice SDP à diagonale dominante, ou A est une matrice SDP avec ai , j ≤ 0 pour i ≠ j . t
t
Algorithme du gradient conjugué préconditionné transformé
-
EE t + R ; on pose C = EE t −1 Au départ : On dispose d'un X 0 quelconque, de g 0 = AX 0 − b , de h0 = C g 0 et de d 0 = − h0 .
-
Passage de l'indice k à l'indice k+1 : On suppose que l'on connaît X k , d k , g k
-
Factorisation incomplète de Cholesky : A =
On calcule : -
αk =
et hk .
gk , gk et X k +1 = X k + α k d k . Ad k , d k
On prépare la suite en calculant : g k +1 = g k
+ α k Ad k ou = AX k +1 − b
−1
-
hk +1 = C g k +1 (simple à résoudre car factorisation de Cholesky ou de Crout)
-
d k +1 = − hk +1 + β k d k
Tests d'arrêts pour les méthodes itératives On se donne une précision ε > 0 . On voudrait que l'algorithme se termine une fois la précision atteinte, c'est à dire
X n − X ≤ ε . Cependant, on ne connaît pas X ! On utilise par conséquent le test
suivant
X n+1 − X n ≤ 2ε , dont on considère en pratique qu'il est équivalent au premier, même si cela n'est
qu'à demi vrai en théorie (la réciproque est fausse). Il peut y avoir de rare cas où l'algorithme s'arrête, alors que l'on est loin de la solution !!! Mais faute de mieux… Finalement, on prend comme test d'arrêt :
X n+1 − X n ≤ ε et /ou AX n − X n = g n ≤ ε .
Remarque : La méthode du gradient conjugué préconditionné est plus performant en nombre d’itération que la méthode de relaxation avec woptimal .
A.BENHARI
78
XVIII. Problèmes au moindres carrés (linéaire) a. Régression linéaire Etant donné une série de M points b qui minimise l'erreur
erreur
2
(xi , yi ) , on cherche une relation de la forme 2 = ∑ ei avec ei = yi − (axi + b ) .
yi ≅ axi + b . On cherche a et
M
Cas général On étudie un cas plus général
f (t i ) ≅ ∑ x j .φ j (t i ) , avec N inconnues x j . On a M équations avec M >> N . N
On pose
A = (φ j (t i ))M × N et b = ( f (t i ))M . L'erreur est Ax − b . On cherche les x j qui minimise cette 2
erreur
Ax − b
2 2
= ∑ ∑ aij x j − bi . i =1KM j =1KN
b. Méthode des équations normales Théorème Le vecteur
x réalise le minimum de Ax − b 2 si et seulement si x est solution de (A t A)x = A t b (équation
normale). Il existe toujours au moins une solution. La solution est unique si et seulement si le rang de A est N.
Défauts numériques On appliquera la méthode des équations normales pour un nombre faible d'inconnues 2, 3, 4 ou 5. Un premier défaut est l'imprécision du calcul engendré par le produit matriciel
A t A . Par ailleurs, si la matrice A est creuse,
t
A A peut très bien ne pas l'être… Méthode de la factorisation QR (rectangulaire)
Définition (M > N) R N ×N , avec R une matrice triangulaire AM × N = QM × M R N × N , avec Q une matrice orthogonale et R = O supérieure.
Théorème : minimiser Ax − b
2
pour N supérieur à 3 ou 4
c Q t b = 1 avec c1 de dimension N. Le vecteur x minimise Ax − b 2 si et seulement si x est c2 M solution de Rx = c1 . Soit
A.BENHARI
79
Obtention de la factorisation A = QR par Householder
Définition des matrices de Householder Soit u un vecteur unitaire
(u
2
)
= 1 de dimension m. On définit la matrice de Householder de dimensio m × m
(
H u = Id m − 2u.u . H u est symétrique et orthogonale H u t
en posant
2
)
= 1 . On note également H u = Id m −
v.v t
β
v = 2 β .u .
Propriété fondamentale des matrices de Householder Soit a un vecteur de dimension m, non nul. Il existe H, une matrice de Householder, telle que
α H × a = O m
avec α un réel. Preuve : -
α2 = a
-
On choisit le signe de α : le signe opposé à a1.
-
On pose
-
On choisit
2 2
β = α 2 − α .a1 > 0 . a1 − α v = ai
. m
Principe de l'algorithme de factorisation On veut obtenir la matrice RM × N à partir de la matrice A = A0 . On procède colonne par colonne.
α1 x 0 α2 On rappelle la géométrie de R = M 0
O . O
-
A0 . Il existe une matrice de Householder H 1 de dimension m
Occupons nous de la première colonne de
α 1 0 telle que H 1 × A0 = A1 , où la première colonne de A1 est . M 0
A.BENHARI
80
-
~
On s'intéresse maintenant à la 2ème colonne. Il existe une matrice de Householder H 2 de dimension m-1
1 0 H 2 × A1 = A2 , avec H 2 = ~ . Ainsi la première colonne de A2 reste inchangée par 0 H2 x α 2 rapport à A1 et l'on a fabriqué la deuxième colonne 0 . M 0 Il vient A = A0 = H 1 × A1 = H 1 × H 2 × A2 = K On itère la méthode N fois et il l'on obtient la factorisation A = (H 1 L H n )An avec Q = H 1 L H n et R = An .
telle que
-
Obtention de Q t b = c1 au cours de l'algorithme de factorisation Q t b à l'algorithme précédent. Cela est simple, il suffit de rajouter une N+1 colonne à la matrice initiale, A0 = ( A b ) . Ainsi après N itérations, on obtiendra le résultat En vérité, on peut habilement intégrer le calcul de
Q t b toujours dans la même colonne. Obtention de la factorisation A = QR par Givens (…)
XIX. Résolution des équations non linéaires a. Méthode de dichotomie
[ ]
Considérons une fonction f en dimension 1. On isole une racine unique dans un intervalle a, b . On divise l'intervalle en deux à chaque étape, on identifie le sous - intervalle contenant la racine en comparant le signe du milieu
f (m ) avec f (a ) . Et on réitère. La précision obtenue au bout de k itérations est
b−a . La méthode de 2k
la dichotomie est robuste, mais n'est pas généralisable à la dimension n.
b. Généralités i. Méthode convergente, d'ordre p Une méthode itérative est convergente :
X n → X solution, si ∃C , p / X n − X ≤ C X n −1 − X
que la méthode est dite d'ordre p.
Théorème du point fixe Soit
φ
k-lipschitzienne contractante :
φ ( y 2 ) − φ ( y1 ) ≤ k y 2 − y1
( )
X n +1 = φ ( X n ) . Alors on a X n → X tel que X = φ X .
A.BENHARI
81
avec k < 1 . Soit X 0 et
p
. On dit
-
Pour appliquer ce théorème, il suffit de vérifier qu'il existe une boule
propriété
φ ( y 2 ) − φ ( y1 ) ≤ k y 2 − y1
k = sup φ ′(c ) = sup c
c ,i , j
(
B X, X0 − X
) sur laquelle, on a la
avec 0 < k < 1 . L'inégalité des accroissement finis nous donne
∂φ i (c ) . ∂x j
ii. Méthode d'itérations successives pour résoudre F (X ) = 0
Posons
φ ( X ) = X − F ( X ) . Si X
récurrence suivante :
est point fixe de φ alors
X n +1 = X n − F ( X n ) .
Méthode de Newton - tangente En dimension 1 pour des réels,
x n +1 = x n −
X est solution de F ( X ) = 0 . On définit alors la
f (xn ) . La méthode de la tangente est d'ordre 2. Inconvénient, si f ′( x n )
on part d'une certaine boule , la méthode converge, sinon l'algorithme peut osciller et ne pas converger ! Cette méthode se généralise à la dimension n. Pour des complexes, on peut employer deux fois cette méthode. Méthode de Newton - Raphson
∂F ( X ) X n+1 = X n − ∆ n où J (F ( X n )) × ∆ n = F ( X n ) avec J (F ( X n )) = i n ∂x j (matrice jacobienne). J (F ( X n )) est inversible et permet le calcul de ∆ n à chaque itération. Si on part d'une En dimension n,
certaine boule au voisinage de la solution, la méthode est convergente d'ordre 2. Si on fait un choix au hasard pour X 0 , il faut prévoir un test d'arrêt au bout de 100 itérations par exemple pour éviter le cas d'oscillations ! La complexité globale est en n3.
iii. Variante si m grand La complexité globale passe en n2 après la première utilisation… Factorisation PA=LU… Méthode de Bairstow dans le cas des polynômes On cherche à résoudre
P( x ) = 0 , avec P ( x ) = x n + a n −1 x n −1 + K + a 0 .
Méthode On cherche
(
)
x 2 + βx + α qui divise P. On a P ( x ) = x 2 + βx + α Q ( x ) + (r1 x + r0 ) (division euclidienne).
Pour déterminer les coefficients α et β, on cherche une racine de l'application
F : (α , β ) a (r0 , r1 ) .
On veut appliquer la méthode de Newton - Raphston en dimension 2. Il faut d'abord calculer la matrice jacobienne J : on établit des formules par récurrence assez complexes… Puis, on applique effectivement la méthode de Newton - Raphston, à partir de
(α 0 , β 0 ) , qui donne (α , β ) (sous réserve que l'on se trouve
initialement dans une boule suffisamment proche de la solution pour que la méthode soit effectivement convergente). Finalement, le polynôme
A1 = x 2 + βx + α fournit deux racines de P. On réitère la méthode sur Q1 tel que
P = A1Q1 . Cependant, les itérations successives entraînent une perte progressive de la précision.
A.BENHARI
82
Variante Pour ne pas choisir
(α 0 , β 0 ) complètement au hasard, une méthode consiste à sélectionner une centaine de
couples et à choisir, pour débuter l'algorithme, celui qui rend le polynôme minimum.
Amélioration de la précision La racine obtenue étant assez proche de la racine réelle, on effectue la méthode de la tangente pour améliorer la précision. Tous les 4 ou 5 coups, on améliore la précision avec la précision avec la méthode de la tangente. Cette dernière méthode ne s'applique qu'aux racines réelles (on applique deux fois la méthode pour les racines complexes). Méthode de Bernouilli pour le calcul de la racine dominante si elle est unique ???
c. Valeurs propres et vecteurs propres Conditionnement
Théorème D = P −1 AP avec P la matrice de passage. Pour tout δA , pour toute valeur propre λ de A + δA , il existe une valeur propre λ' de A telle que λ − λ ≤ Cond (P ) δA . Le meilleur cas possible est Si A est diagonalisable en
A symétrique, la matrice de passage est orthogonale et son conditionnement égale à 1. Bissection de Givens - Householder
Méthode 1. 2.
Chercher une matrice tridiagonale semblable à A ayant même valeur propre. Chercher ces valeurs propres.
Tridiagonalisation Cet algorithme utilise des matrices de Householder. On procède bloc par bloc, en dimension décroissante. A1 = A -
1 O ~ −1 H 1 = H 1 = ~ et H 1 la matrice de Householder. On O H1 t ~ a a11 A12 H A 11 1 12 . On sait . Par la suite, A2 = ~ découpe A1 en bloc selon le schéma : ~ ~ H A H A H A21 A22 1 22 1 1 21 α 1 ~ ~ trouver H 1 tel que H 1 A21 = avec α un réel. Voilà ce qui en définitive va rendre la matrice O 1ère étape :
A2 = H 1 × A1 × H 1
−1
avec
(
-
tridiagonale. On applique la même méthode que précédemment avec une dimension en moins…
-
On réitère la méthode n fois en totalité. Finalement, on obtient
A = (H 1 K H n ) × An × (H 1 K H n ) où
An est une matrice tridiagonale semblable à A.
Optimisation des calculs On intègre le calcul de α dans la méthode et on optimise le produit des 3 matrices. -
α 1 = − Signe(a 2,1 ). A21
-
β = α 1 2 − α 1 a 2,1 > 0
A.BENHARI
83
)
−1
α V = A21 − 1 O 1 W = A22V
-
-
β
1 t VW 2β Z = W − λV VZ t = K et ZV t = K ~ ~ H 1 A22 H 1 = A22 − (VZ t + ZV t )
λ=
-
Méthode de recherche des valeurs propres A partir de la matrice tridiagonale M, on va construire le polynôme caractéristique dont les racines sont précisément les valeurs propres. - Soit bi les coefficients diagonaux, et ci les coefficients sous-diagonaux. On a P0 (λ ) = 1 , P1 (λ ) = b1 − λ et pour tout
i ≤ n , Pi (λ ) = (bi − λ )Pi −1 (λ ) − ci −1 Pi −2 (λ ) . Attention au cas particulier où un ci est nul ! Il faut 2
distinguer deux polynômes caractéristiques. 1. Pi est le polynôme caractéristique de Mi où Mi est la sous-matrice de dimension i extraite de M de telle sorte que Mn = M. 3.
(− 1)i λi . Si Pi (λ0 ) = 0 alors Pi +1 (λ0 ) et Pi −1 (λ0 ) sont de signe opposé.
4.
Pi a exactement i racines réelles distinctes qui séparent les i+1 racines de Pi+1.
2.
Le coefficient dominant de Pi est
Bissection de Givens Soit µ un réel. Soit E (i, µ ) = {+, signe(P1 (µ ))K signe(Pi (µ ))} . On définit N (i, µ ) le nombre de changement de signe dans E (i, µ ) . Alors N (i, µ ) représente le nombre de racines de Pi qui sont inférieures et
distinctes de µ.
On ordonne les λi de manière croissante :
µ=
λ1 < L < λn . Considérons un intervalle [a0 , b0 ] contenant λi. Soit
a0 + b0 (bissection). On calcule N (n, µ ) . Si N (n, µ ) > i , alors λi ∈ [a0 , µ ] sinon λi ∈ [µ ,b0 ] . On 2
réitère…
Une variante pour éviter les overflows (…) Méthode de la puissance itérée Soit A une matrice quelconque, éventuellement à coefficient complexe.
Théorème Soit A diagonalisable dont la valeur propre λ1 (de plus grand module) est unique. Soit orthogonal au sous-espace propre à gauche5 associé à λ, tel que
5
vecteur propre à gauche pour λ si
A.BENHARI
A*v = λv 84
q0 un vecteur non
q0 = 1 . On suppose xn +1 = Aqn ,
λ1 qk → u1 le vecteur propre associé à λ1 et xk +1 ( j ) → λ1 pour tout j tel λ qk ( j ) 1 k
x qn +1 = n +1 . Alors, on a : xn +1 que
qk ( j ) ≠ 0 .
En pratique ! -
En pratique l'hypothèse " q0 un vecteur non orthogonal au sous-espace propre à gauche6 associé à λ" n'est
-
pas nécessaire, car le phénomène d'arrondi permet de s'éloigner du cas orthogonal ! Si A n'est pas diagonalisable, la méthode fonctionne encore, mais la convergence est plus lente. En pratique, on choisit la norme infinie, et q0 = (1,K,1) .
Méthode de la déflation On suppose maintenant que l'on connaît λ1 et u1, avec
λ1 > L > λn
et la base de vecteur propre
(u1,L, un ) .
On cherche λ2 et u2. On suppose A = A (A symétrique ?). Le principe est simple, on forme la matrice B tel que B = A − λ1u1u1 . Cette matrice possède les mêmes valeurs propres, les mêmes vecteurs propres, sauf λ1 et u1. Par conséquent, si l'on applique la méthode de la puissance itérée, on va obtenir λ2 et u2. *
*
En pratique, on ne calcule pas B… La seule différence avec la méthode de la puissance itérée est dans la formule xk +1 = A(qk − α k u1 ) . (Phénomène d'arrondi compensatoire inverse…) Cette méthode permet en réitérant de trouver λ3, λ4 mais pas au delà, car il y a répercussion des erreurs d'arrondi. Méthode de la puissance itérée inverse Cette méthode permet de calculer la plus petite valeur propre λn et son vecteur propre un. On prend on applique la méthode de la puissance itérée à B, ce qui donne
un et
1
λn
B = A−1 et
.
Pour trouver la valeur propre la plus proche de µ, on applique la méthode de la puissance itérée à B = A − µ .Id , ce qui donne uk et λk − µ .
XX. Approximation polynomiale & Intégration numérique a. Approximations polynomiales i. Polynômes orthogonaux b
Soit
P, Q = ∫ P( x )Q( x )W ( x )dx avec W ( x ) ≥ 0 un poids. Considérons P0 , P1 , L , Pn avec Pi un a
polynôme de degrés i. Alors
Pi , Pj = 0 pour i ≠ j .
Legendre -
[− 1,1] , W (x ) = 1 ,
1
P, Q = ∫ P ( x )Q( x )dx . −1
6
vecteur propre à gauche pour λ si
A.BENHARI
A*v = λv 85
-
P0 = 1 , P1 ( x ) = x , Pn ( x ) = Pn
=
2
2n − 1 n −1 xPn−1 ( x ) − Pn − 2 ( x ) . n n
2 . 2n + 1
Laguerre -
[0,+∞[ , W (x ) = e − x ,
P, Q =
+∞
∫ P(x )Q(x )e
−x
dx .
0
-
L0 = 1 , L1 ( x ) = − x + 1 , Ln ( x ) = (2n − x − 1)Ln −1 ( x ) − (n − 1) Ln −2 ( x ) 2
Pn
= (n!) .
2
2
Hermite -
P, Q =
+∞
−x ∫ P(x )Q(x )e dx . 2
−∞
-
H 0 = 1 , H 1 ( x ) = 2 x , H n ( x ) = 2 xPn −1 (x ) − 2(n − 1)H n − 2 ( x ) . Pn
2
= 2 n n! π .
Tchebychev -
P, Q =
+∞
∫
P( x )Q( x )
dx . 1− x2 T0 = 1 , T1 ( x ) = x , Tn ( x ) = 2 xTn −1 ( x ) − Tn − 2 ( x ) . −∞
-
-
(
)
cos n cos −1 ( x ) , x ≤ 1 2k − 1 π formule explicite : Tn ( x ) = . Tn a n zéros, x k = cos . ∈ [− 1,1] −1 2 n ch nch ( x ) , x ≥ 1 k +1 pour 1 ≤ k ≤ n et n+1 extrema sur x ′k = cos . ∈ [− 1,1] . n
(
P0
2
= π , Pn
2
=
π 2
)
.
Théorèmes -
T (x )
Soit E n = {P / deg (P ) = n et a n = 1} . Alors ∀P ∈ E n , sup n n −1 ≤ sup P ( x ) . [−1,1] 2 [−1,1] Soit Fn = {P / deg (P ) = n et P (α ) =
βTn ( x ) ≤ sup P( x ) . [−1,1] Tn (α ) [−1,1]
β } avec α ∉ [− 1,1] et β fixé. Alors ∀P ∈ Fn ,
sup
-
Soit G n = {P / deg (P ) = n et P (α ) =
β } avec α ∉ [a, b] et β fixé. Alors ∀P ∈ G n ,
a + b − 2x a −b sup ≤ sup P( x ) . [a ,b ] [a ,b ] a + b − 2α Tn a−b
β .Tn
A.BENHARI
86
ii. Algorithme de Remes
Soient un intervalle
[a, b] , et un fonction f ∈ C ([a, b], R ) .
de degrés inférieur ou égal à n tel que
P− f
∞
≤ Q− f
f
∞
= sup f ( x ) . On cherche un polynôme P [a,b ]
pour tout polynôme Q de degrés inférieur ou égal
∞
à n.
Théorème On considère
x0 < x1 < L < x n +1 n+2 points de [a, b] .
∃! P / deg(P ) ≤ n et ∀i, f ( xi ) − P( xi ) = (− 1) ( f ( x0 ) − P( x0 )) (equioscillations) i
1.
max f ( xi ) − P( xi ) ≤ max f ( xi ) − Q( xi ) pour tout Q tel que deg(Q ) ≤ n , c'est-à-dire que P est la
2.
0 ≤i ≤ n +1
0 ≤ i ≤ n +1
meilleure approximation pour les points
xi , mais pas meilleure approximation uniforme.
Corollaire Posons
α = f ( xi ) − P( xi ) , ∀i . Si α = f − P
∞
alors
degrés n. P est la meilleure approximation uniforme sur
f −P
[a, b] .
∞
≤ f −Q
∞
pour tout polynôme Q de
Algorithme Du point de vue informatique, on se donne une tolérance polynôme Q de degrés n 1. 2. 3. 4.
f −P
∞
≤ f −Q
∞
ε > 0 , d'où si α − f − P
∞
≤ ε , alors pour tout
+ε …
Choisir n+2 points. Si condition vrai, alors fin. Sinon, échange : on introduit y en respectant le principe d'oscillation… ??? On recommence avec la nouvelle famille de points.
On démontre que l'algorithme converge.
iii. Approximation par interpolation
Considérons n+1 points
x0 < x1 < L < x n . Soit P un polynôme de degrés n tel que P ( xi ) = f ( xi ) . Un tel
polynôme existe et on démontre qu'il est unique. On définit
On a
n x − xk W j (x ) = ∏ k =0 x j − x k k≠ j
un polynôme de degrés n.
n 1 si i = j W j ( xi ) = . Alors P ( x ) = ∑ f (x j )W j ( x ) . j =0 0 si i ≠ j
Formule de Gregory - Newton Soit h le pas.
x k = x0 + kh . On définit ∆ ′f ( x ) = f ( x + h ) − f ( x ) , ∆2 f ( x ) = ∆ ′∆ ′f ( x ) ,… On commence
par calculer les
∆i f ( x 0 ) pour 0 ≤ i ≤ n . La formule de Gregory - Newton définit le polynôme P de degrés n
u u x − x0 u 1 P ( x ) = f ( x0 ) + ∆ ′f ( x 0 ) + K + ∆n f ( x0 ) avec u = et = u (u − 1)L (u − i + 1) . h 1 n i i! u h n +1 i Remarquons que si x = x k , u = k et = C k . On estime l'erreur f ( x ) − P ( x ) ≤ M n +1 avec 4(n + 1) i
A.BENHARI
87
M n +1 = f (n +1) ( x ) . Pn ne converge pas vers f à cause des M n . Aussi pour avoir la convergence uniforme ∞
sur
[a, b] , on réalise l'interpolation sur N sous-segments de longueur
b−a avec 5 ou 6 points (en pratique). N
Intégration numérique Si
Pn converge uniformément vers f sur [a, b] , alors
∫
b
a
Pn tend vers I = ∫ f . On partage l'intervalle [a, b] a
b
b−a , avec x 0 = a et x N = b . en N sous-segments [xi , x i +1 ] de longueur h = N
Stabilité Les formules sont de la forme
∑ a f (x ) avec nécessairement ∑ a i
i
i
La méthode est stable si pour tout h, il existe A tel que
∑ a f (x ) − ∑ a f (x i
i
i
i
ε = sup ε i
= b −a.
i
i
i
+ ε i ) < Aε , avec
i
.
i
Théorème : Si
a i ≥ 0 alors la formule est stable.
iv. Formule des rectangles
Sur chaque sous-segment
[xi , xi+1 ] , on approche f
égale à la valeur milieu. Donc
avec un polynôme de degrés 0, c'est-à-dire par une constante
N (b − a ) M h 2 . Cette h Rh = h ∑ f xi + . On estime l'erreur I − Rh ≤ 2 24 2 i =0
méthode est d'ordre 2, et non d'ordre 1 comme on le croit souvent ! Formule des trapèzes Les polynômes qui interpolent sont de degrès 1, ce sont des droites.
On estime l'erreur
I − Th ≤
(b − a ) M 12
2
f ( x0 ) f ( x N ) N −1 Th = h + + ∑ f ( xi ) . 2 i =1 2
h 2 . Cette méthode est d'ordre 2 et n'est pas meilleur que celle des
rectangles (sinon moins bonne). Formule de Simpson
Sh =
N −1 h h 2 f ( xi ) + 4 f xi + . La méthode est d'ordre 4. f ( x ) + f ( x ) + ∑ 0 N 6 2 i =0
v. Spline Théorème Soi k ≥ 1 . Il existe une et une seule fonction Γ sur [x1 , x N ] tel que Γ( xi ) = y i . Sur chaque segment
[xi , xi+1 ] , Γ est un polynôme de degrés 2k-1 avec Γ (2 k −2 ) (xi ) qui existe et Γ (2 k −2 ) (x1 ) = Γ (2k −2 ) (x N ) = 0 , de telle sorte donc que Γ soit de classe 2k-2 sur [x1 , x N ] .
A.BENHARI
88
XXI. Équations différentielles a. Généralités Problème de Cauchy Soit
f : [x0 , x0 + a ] × R M → R M , continue, telle que ( x, y ) a f ( x, y ) . Etant donnée une condition initiale
y ′( x ) = f ( x, y (x )) y 0 , on cherche y : [x0 , x0 + a ] → R M de classe C1 telle que , problème de Cauchy y (x0 ) = y 0 dimension M et d'ordre 1.
(
)
y ( P ) ( x ) = g x, y, y ′, L , y ( P −1) Le problème de Cauchy de dimension M et d'ordre P : . y ( x0 ) = y 0 , y ′( x0 ) = y 0′ , L , y ( P −1) (x 0 ) = y 0( P −1) y y′ On se ramène au problème de Cauchy d'ordre 1 en posant z = , de dimension PM . M ( P −1) y
Théorème (K - lipschitzienne) Si il existe K tel que
∀x, y1 , y 2 , f ( x, y1 ) − f ( x, y 2 ) ≤ K y1 − y 2 , alors le problème de Cauchy d'ordre 1
possède une solution unique.
b. Méthode de résolution numérique On se place dans le cadre de ce théorème, et l'on cherche à calculer une solution. On divise l'intervalle
[x0 , x0 + a ] en N de telle sorte que x N = x0 + a ; xn = x0 + nh avec le pas h = a . On voudrait que les N y n soient proches de y ( x n ) . La formule générale employée pour la résolution numérique des équations y n +1 = y n + hΦ (x n , y n , h )
différentielles est
y0
.
Stabilité On introduit une perturbation, méthode. Posons
ε = sup ε n
z n +1 = z n + hΦ( x n , z n , h ) + hε n , et l'on observe le comportement de la z0 = y0 . La méthode est stable si et seulement si
∃A / max z n − y n ≤ Aε . n
n
Consistance La méthode est consistante si et seulement si
max n
méthode est consistante d'ordre p si et seulement si
y ( x n +1 ) − y (x n ) − Φ( x n , y ( x n ), h ) h → 0 . La →0 h ∃A / max n
A.BENHARI
89
y ( x n +1 ) − y ( x n ) − Φ ( x n , y ( x n ), h ) ≤ Ah p . h
Convergence La méthode est convergente si et seulement si seulement si
max y n − y ( x n ) h → 0 . Il y a convergence d'ordre p si et →0
∃A / max y n − y ( x n ) ≤ Ah .
n
p
n
Si la méthode est stable et consistante [d'ordre p], alors la méthode est convergente [d'ordre p].
Théorème stabilité Si il existe K tel que
∀x, y1 , y 2 , Φ ( x, y1 , h ) − Φ( x, y 2 , h ) ≤ K y1 − y 2 , c'est-à-dire si φ est K -
lipschitzienne, alors la méthode est stable.
Théorème consistance - Si Φ ( x, y ,0 ) = f ( x, y ) , on a consistance d'ordre 1. 1 ∂f ∂Φ - Si de plus, ( x, y,0 ) = ( x, y ) , alors on a consistance d'ordre 2. 2 ∂x ∂h -
Si de plus,
-
Etc. …
∂ 2Φ 2 ( x, y,0) = ∂h
1 ∂2 f 3 ∂x 2
( x, y ) , alors on a consistance d'ordre 3.
c. Méthode de Euler
Φ( x, y, h ) = f ( x, y ) , ordre 1, stabilité acquise (φ et f lipschitzienne). Intuitivement, on traduit la formule du y − yn taux d'accroissement f ( x n , y n ) = n +1 . La formule sera donc y n +1 = y n + hf ( x n , y n ) . h
d. Méthode du développement de Taylor Φ ( x, y , h ) = f ( x, y ) +
1 ∂f 1 h 2 ∂f h ( x, y ) + ( x, y ) + K , consistante de l'ordre que l'on veut, 2 ∂x 3 2! ∂x
stabilité acquise. Mais en pratique les calculs de dérivées rend la méthode impraticable !
e. Méthode de Runge - Kutta Ordre 2
Φ( x, y, h ) = βf ( x, y ) + αf ( x + λh, y + µhf ( x, y )) . L'ordre 1 impose α + β = 1 et l'ordre 2 impose λ = µ et αλ = αµ = 1 / 2 . h h - Si α = 1 , alors β = 0 etλ = µ = 1 / 2 , d'où la formule y n +1 = y n + hf x n + , y n + f ( x n , y n ) . 2 2 h y n +1 / 2 = y n + f ( x n , y n ) Soit le prédicteur y n +1 / 2 , la méthode s'écrit : La méthode est 2 y n +1 = y n + hf ( x n + h / 2, y n+1 / 2 ) On cherche
d'ordre 2, et correspond à une amélioration de Euler : le taux d'accroissement est calculé pour le point milieu (xn + h / 2, y n+1 / 2 ) . -
Si
α = 1/ 2 …
A.BENHARI
90
Ordre 4 -
Φ ( x, y , h ) =
P1 = P2 = P3 = P4 =
1 (P1 + 2 P2 + 2 P3 + P4 ) 6
f ( x, y ) f ( x + h / 2, y + h / 2.P1 ) f ( x + h / 2, y + h / 2.P2 ) f ( x + h, y + h.P3 )
Choix de h On se donne une tolérance ε > 0. - On choisit arbitrairement h et on applique la méthode. - On recommence avec h / 2 . Si le résultat obtenu pour un pas divisé par 2, est à ε près celui obtenu pour un pas de h alors le pas est bon, sinon on réitère. Attention il faut comparer x n
h x 2 n = x0 + 2n. . 2
A.BENHARI
91
= x 0 + nh et
XXII. Exercices Exercices simples Exercice 1 : Ecrire un algorithme d’une action qui échange deux variables A et B Action : Echange Var : A, B, C : réels Début : Ecrire (« Saisissez deux variables ») Lire (A, B) C <= A A <= B B <= C Ecrire (« les valeurs de », A, « et de » , B, « ont été changées ») Fin
Exercice 2 : Ecrire une fonction qui donne les carré d’un réel Fonction : carré (x :réel) :réel Var : x_au_carré Début x_au_carré <= x*x retourner x_au_carré fin Remarques : Dans une fonction, la seule variable qui est définie est celle du résultat, les autres sont définies dans la fonction mère, et apparaissent ici en temps qu’entrées. Dans une fonction, ne pas oublier de retourner le résultat.
A.BENHARI
92
Exercice utilisant les structures SI…ALORS…SINON et SELON…QUE Exercice 3 : Ecrire une action qui fournit les félicitations ou l’ajournement d’un élève suivant sa note en utilisant Si-alorssinon. Action : Jury Var : note : réel Début : lire (note) Si note <10 alors écrire (« ajourné ») Sinon écrire (« reçu ») Fin Exercice 4 : Ecrire un programme qui donne la valeur absolue de 2 réels : Action : Valeur_absolue Var : a, b : réels Début : Ecrire (« saisissez 2 réels ») Lire (A, B) Ecrire « les valeurs absolues de A et de B sont : ») Si A<0 alors écrire (-A) Sinon écrire (A) Ecrire (« et ») Si B<0 alors écrire (-A) Sinon écrire (A) Fin Remarque : on peut aller plus vite en créant une fonction valeur absolue et en faisant appel à cette fonction dans une action : Fonction : valAbs (x :réel) :réel Var : absx : réel Début : si x <0 alors absx <= -x Sinon absx <= x Retourner absx Fin Et Action : Valeur_absolue2 Var : A, B réels Début : Ecrire (« saisissez 2 réels ») Lire (A, B) Ecrire (« les valeurs de A et B sont : », valAbs(A), « et », valAbs(B)) Exercice 5 : Faire un programme qui donne le volume d’un cylindre en faisant appel à une fonction ‘aire d’un cercle’. Fonction : aire_cercle (rayon :réel) :réel Var : Aire : réel Const : PI=3.14 Début : Aire <= PI*rayon*rayon Retourner (Aire) Fin Fonction : volume_cercle (hauteur, rayon :réels) :réel Var : volume : réel Début : Volume <=aire_cercle (rayon)*hauteur Retourner volume Fin
A.BENHARI
93
Exercice 6 : Ecrire un algorithme permettant de résoudre une équation du premier degré Action : premierdegre Var : a, b, x réels Début : Ecrire (« saisissez les valeurs a et b de l’équation ax+b=0 : ») Lire (a, b) Si a = 0 alors écrire (« pas de solution ») Sinon écrire (« la solution est x= », -b/a) Fin
Exercice 7 : Ecrire un algorithme permettant de résoudre une équation du second degré en utilisant des si alors.. Action : seconddegré Var : a, b, c, delta Début : Ecrire (« saisissez les valeurs a, b et c de l’équation ax²+bx+c=0 : ») Lire (a, b, c) Si a=0 alors écrire (« équation du premier degré ») Sinon delta<=b²-4*a*c Début Si delta>0 alors écrire (« les solutions de l’équation sont », (-b-sqrt(delta))/(2*a), « et », (b+sqrt(delta))/(2*a)) Sinon Début Si d=0 alors écrire ( -b/(2a)) Sinon écrire (« pas de solutions réelles ») Fin Fin Fin Ecrire le même algorithme avec des selon-que : Action : seconddegré Var : a, b, c, delta Début : Ecrire (“saisissez les valeurs de a, b et c de l’équation ax²+bx+c) Lire (a, b, c) Si a=0 alors écrire (« résoudre permier degré ») Sinon début Delta <= b²-4*a*c Selon que Delta > 0 : écrire ((-b-sqrt(delta))/(2*a), (-b+sqrt(delta))/(2*a)) Delta = 0 : écrire (( -b/(2a)) Sinon écrire (« pas de solution réelle ») Fin selon Fin
A.BENHARI
94
Exercice 8 Ecrire un algorithme qui donne la durée de vol en heure minute connaissant l’heure de départ et l’heure d’arrivée. 1) on considère que le départ et l’arrivée ont lieu même jour 2) idem mais sans faire les conversions en minutes 3) on suppose que la durée de vol est inférieure à 24 heures mais que l’arrivée peut avoir lieu le lendemain.
1) Action : DuréeVol1 Var : h1, h2, m1, m2, hr, mr : entiers Début : Ecrire (« entrer horaire de départ et d’arrivée ») Lire (h1, m1, h2, m2) mr <= [h2*60+m2] – [h1*60+m1] hr <= mr/60 mr <= mr%60 Ecrire (« durée de vol : » , hr, mr) Fin Remarque : l’opération % (modulo) permet de calculer le reste de la division entière. 2) Action : DuréeVol2 Var : h1, h2, hr, m1, m2, mr : entiers Début : Ecrire (« entrer horaire de départ et d’arrivée ») Lire (h1, m1, h2, m2) Si m2>m1 alors hr <= h2-h1 et mr <= m2-m1 Ecrire (hr, mr) Sinon hr <= h2-h1-1 et mr <= m2+60-m1 Ecrire (hr, mr) Fin
3) Action : DuréeVol3 Var : h1, h2, m1, m2, hr, mr : entiers Début : Ecrire (« entrer horaire de départ et d’arrivée ») Lire (h1, m1, h2, m2) Si h2>h1 alors Si m2>m1 alors hr <= h2-h1 et mr <= m2-m1 Ecrire (hr, mr) Sinon hr <= h2-h1-1 et mr <= m2+60-m1 Ecrire (hr, mr) Sinon Si m2>m1 alors hr <= h2-h1+24 et mr <= m2-m1 Ecrire (hr, mr) Sinon hr <= h2-h1+24-1 et mr <= m2+60-m1 Ecrire (hr, mr) Fin
A.BENHARI
95
Exercice 9 1) Ecrire une fonction max3 qui retourne le maximum de trois entiers 2) Ecrire une fonction min3 qui retourne le minimum de trois entiers 3) Ecrire une fonction max2 qui retourne le maximum de deux entiers 4) Ecrire une fonction max3 qui retourne le maximum de trois entiers en faisant appel à max2
1) Fonction : max3(a, b, c : entier) : entier : Var : max3 : entier Début : Si a>b alors Si a>c alors max3 <= a Sinon max3 <= c Sinon Si c>b alors max3 <= c Sinon max3 <= b Retourner (max3) Fin 2) Fonction : min3(a, b, c : entier ) : entier : Var min3 : entier Début Retourner (–max3(-a, -b, -c)) Fin 3) Fonction : max2 (a, b : entier) : entier Var : max2 : entier Début : Si a
Exercice 10 Ecrire avec des Si Alors Sinon une action permettant la saisie d’une note n (0≤n≤20) et qui affiche la mention (n≥16 : TB, n≥14 : B, n≥12 : AB, n≥10 : Passable, n≥10 : Ajourné) Action : Mention Var Note : réel Début : Ecrire (« saisissez une note ») Lire (Note) Si Note≥16 alors écrire (« TB ») Sinon Si Note≥14 alors écrire (« B ») Sinon Si Note≥12 alors écrire (« AB ») Sinon Si Note≥10 alors écrire (« Passable ») Sinon écrire (« ajourné ») Fin
A.BENHARI
96
Alternative : écrire le même programme avec des Selon Que : Action : Note Var : Note : réel Selon que Note ≥ 16 écrire (« TB ») Note ≥ 14 écrire (« B ») Note ≥ 12 écrire (« AB ») Note ≥ 10 écrire (« Passable ») Sinon écrire (« ajourné »)
Exercice 11 Soit l’algorithme suivant : Action : Permis_voiture Var : permis, voiture : booléen Début : Ecrire (« avez-vous le permis ? (0/1) ») Lire (permis) Ecrire (« avez vous une voiture ? (0/1) ») Lire (voiture) Si non permis ou voiture alors Si voiture alors écrire (« conduisez moi à la gare ») Sinon écrire (« j’ai une voiture pas chère ») Sinon Si voiture alors écrire (« vous êtes hors la loi ») Sinon écrire (« vive le vélo ») fin
1) 2) 3) 4)
Ecrire l’arbre des conditionnelles Corriger les tests pour que tous les cas soient couvert de manière cohérente Faites correspondre les actions et les tests correctement Si possible, écrire cet algorithme avec des selon que.
Permis et voiture gare Conduisez moi à la gare
permis Vive le vélo Voiture pas chère
voiture Conduisez moi à la gare Hors la loi
Ni permis ni voiture Voiture pas chère Vive le vélo
En clair, selon l’algorithme proposé : si l’on a le permis et la voiture on peut amener quelqu’un à la gare ; si l’on a que le permis on dit vive le vélo, si l’on n’a que la voiture on conduit aussi à la gare, enfin si l’on a ni permis ni voiture alors on achète une voiture pas chère. Le cas hors la loi n’est pas évoqué et les correspondance sont inexactes. Il faut évidemment avoir : - permis et voiture : conduire à la gare - permis : j’ai une voiture pas chère - voiture : vous êtes hors la loi - ni voiture, ni permis : vive le vélo Correction de l’algorithme proposé : Action : Permis_voiture Var : permis, voiture : booléen Début : Ecrire (« avez-vous le permis ? (0/1) ») Lire (permis) Ecrire (« avez vous une voiture ? (0/1) ») Lire (voiture) Si permis ou voiture alors Si voiture alors écrire (« conduisez moi à la gare ») Sinon écrire (« j’ai une voiture pas chère ») Sinon Si voiture alors écrire (« vous êtes hors la loi ») Sinon écrire (« vive le vélo »)
A.BENHARI
97
On peut effectivement écrire cet algorithme avec des selon-que : Action : permis_voiture Var : permis voiture : réel Début : Ecrire (« avez-vous le permis ? (0/1) ») Lire (permis) Ecrire (« avez vous une voiture ? (0/1) ») Lire (voiture) Selon que : Permis et voiture : écrire (« conduisez moi à la gare ») Permis et non voiture : écrire (« j’ai une voiture pas chère ») Non permis et voiture : (« vous êtes hors la loi ») Non permis et non voiture : (« vive le vélo ») Fin
Exercice 12 Ecrire un programme calculatrice permettant la saisie de deux entiers et une opération –booléen- ( +, - , / , x ) et affichant le résultat. Donner avant cela les spécifications, la solution en langage naturel, les structures de données. Spécifications : Données : 2 opérandes et un opérateur Résultat : résultat de l’opération choisie Solution en langage naturel : Saisie des données, envisager tous les cas : +, - , x, /. Attention à la division par zéro qui est impossible Structure de données :
2 opérandes : des entiers Un opérateur booléen : +, -, * , /
Algorithme : Action : calcul Var : a, b : réel op : booléen Début Ecrire (« saisissez le premier entier ») Lire (a) Ecrire (« saisissez l’opérateur ») Lire (op) Ecrire (« saisissez la deuxième variable ») Lire (b) Selon que : Op = ‘+’ : Ecrire (a+b) Op = ‘*’ : Ecrire (a*b) Op = ‘/’ : Si b= 0 alors écrire (« division impossible ») Sinon écrire (a/b) Op = ‘-‘ : Ecrire (a-b) Fin selon Fin
A.BENHARI
98
Exercices utilisant les structures répétitives TANT QUE et REPETER…JUSQU'A et POUR Exercice 13 Ecrire le programme qui affiche la somme d’une suite d’entiers saisie par l’utilisateur se terminant par zéro. Exemple : l’utilisateur entre 1, puis 5, puis 2, puis 0 : affiche : 8 1) donner les spécifications 2) donner la solution en langage naturel 3) indiquer les structures de données 4) faites l’algorithme Spécifications : - données : suite de nombre entiers se terminant par zéro - résultat : la somme de ces entiers Solution en langage naturel : tant que l’entier saisi n’est pas zéro, l’ajouter à la somme partielle et saisir l’entier suivant. Structure de données : - entier : entier courant (saisi) - entier : somme partielle Algorithme : Action : Somme Suite Var : a, s : entiers Début s<=0 Lire (a) Tant que a≠0 faire Début s<=s+a Lire (a) Fin Ecrire (s) Fin
Attention : dans une structure tant que ne pas oublier d’initialiser!!!
Exercice 14 Ecrire un algorithme qui affiche la moyenne d’une suite d’entiers se terminant par zéro (le zéro n’entrant pas en compte dans la moyenne : il est juste la pour indiquer la fin de saisie) 1) donner les spécifications 2) donner la solution en langage naturel 3) indiquer les structures de données 4) faites l’algorithme Spécification : - données : suite d’entier se terminant par zéro - résultat : la moyenne de ces entiers (zéro exclu) Solution en langage naturel : Tant que l’entier saisi différent de 0 alors ajouter l’entier aux entiers précédents et faire la moyenne (c’est à dire diviser par le nombre d’entiers Structures de données : - entier : entier saisi - entier : résultat moyenne Algorithme : Action : Moyenne Var : n, moy, s : entiers Début : moy<=0 s<=0
A.BENHARI
99
Lire (n) Tant que n≠0 faire Début Moy <= moy*s+n)/(s+1) s<=s+1 lire (n) fin Ecrire (moy) Fin
Exercice 15 Ecrire un algorithme permettant la saisie d’une suite d’entiers se terminant par zéro et vérifier si cette suite contient deux entiers consécutifs égaux en utilisant les structures tant que. 1) donner les spécifications 2) donner la solution en langage naturel 3) indiquer les structures de données 4) faites l’algorithme Spécifications : - données : suite d’entier se terminant par zéro - résultat : vrai si deux entiers consécutifs, faux sinon. Solution en langage naturel : comparer l’entier courant et le précédent. Et tant que ils sont différents, on continu la lecture et tant que l’entier courant est différent de zéro. Structures de données : - entier : nombre courant - entier : nombre précédent Algorithme : Action : Entiers consécutifs Var : nc, np : entier {on désignera par nc le nombre courant et np le nombre précédent} Début Lire (nc) np<=nc-1 {pour être sur que le nombre courant ne sera pas le même que le nombre précédent dès le départ on affecte la valeur nc-1 au nombre précédent. On aurait tout aussi bien pu lui donner la valeur zéro) Tant que nc≠0 et np ≠nc faire Début np<=nc lire (nc) fin Si nc≠0 alors écrire (« oui ») Sinon écrire (« non ») Fin Refaire le même algorithme en utilisant une structure répéter jusqu'à Action : Entiers consécutifs Var : nc, np : entiers Début Lire (nc) Si nc ≠ 0 alors Répéter Début np <= nc lire (nc) jusqu'à (nc=np ou nc=0) Si nc=0 alors écrire (« oui ») Sinon écrire (« non ») Fin
A.BENHARI
100
Exercice 16 Ecrire un algorithme qui affiche le maximum d’une suite se terminant par zéro 1) donner les spécifications 2) donner la solution en langage naturel 3) indiquer les structures de données 4) faites l’algorithme Spécifications : - données : une suite d’entiers se terminant par zéro - résultat : un entier : le maximum de cette suite Solution en langage naturel : comparer l’entier courant avec le maximum et tant que nc
Exercice 17 Ecrire un programme mettant en œuvre le jeu suivant : Le premier utilisateur saisi un entier que le second doit deviner. Pour cela, il a le droit à autant de tentatives qu’il souhaite. A chaque échec, le programme lui indique si l’entier cherché est plus grand ou plus petit que sa proposition. Un score indiquant le nombre de coups joués est mis à jour et affiché lorsque l’entier est trouvé. 1) donner les spécifications 2) donner la solution en langage naturel 3) indiquer les structures de données 4) faites l’algorithme Spécifications : - données : nombre entier - résultat : nombre de tentatives Solution en langage naturel : saisir un nombre entier par le premier joueur. Tant que le joueur 2 n≠saisie, dire si n est > ou < à nombre cherché, incrémenter de 1 et continuer. Quand le résultat est trouvé, afficher le nombre de tentatives. Structures de données : - a : nombre saisi par l’utilisateur 1 - n : nombre saisi par l’utilisateur 2 - t : tentatives Algorithme : Action : devinette
A.BENHARI
101
Var : a, n, t : entiers Début : Lire (a) Lire (n) t=0 Tant que a≠n faire Début Si n>a alors écrire (« nombre cherché plus petit « ) Sinon écrire (« nombre cherché plus grand ») t<=t+1 lire (n) fin écrire (t+1) fin Exercice 18 Ecrire un algorithme permettant de calculer le PGCD de deux nombres en utilisant l’astuce suivante : soustraite le plus petit des deux entiers du plus grand jusqu'à ce qu’ils soient égaux Ecrire le même programme en utilisant l’algorithme d’Euclide : d’une part en utilisant uniquement les structures TANT QUE, d’autre part en utilisant uniquement les structures REPETER JUSQU'A. Action : PGCD Var : a, b entiers Lire (a, b) Début a = ValAbs (a) b = ValAbs (b) Répéter Selon que a>b a<=a-b a
A.BENHARI
102
Exercice 19 Ecrire avec la commande POUR un algorithme qui permet de faire la somme d’une suite de nombre entrée par l’utilisateur. Faire la même chose en comptant par pas de –1. Action :somme_nombre Var : k, nb, n, somme : entier Début : Somme <= 0 Ecrire (« combien voulez-vous entrer de nombres ? ») Lire (nb) Pour k de 1 à nb faire Début Lire (n) Somme<=somme + n Fin Ecrire (somme) Fin Même programme par pas de –1 : Action : somme_entier Var : k, nb, n, somme : entiers Début : Somme<=0 Ecrire (« combien voulez-vous entrer de nombres ? » Lire (nb) Pour k de nb à 1 par pas de –1 faire Début Lire (n) Somme<=somme + n Fin Ecrire (somme) Fin
Exercice 20 Traduire le POUR de l’algorithme suivant en REPETER JUSQU'A : Action : bidon Var : k, nb : entiers Début Lire (nb) Pour k de 1 à nb faire Ecrire (k) Fin Action : Bidon Var : k, nb : entier Début Lire (nb) K<=1 Si nb>0 alors Répéter écrire (k) K<=k+1 Jusqu’à k>nb Fin
Exercice 21 Ecrire une fonction qui fait la somme des entiers compris dans un intervalle.
A.BENHARI
103
Fonction : intervalle (a, b ; entiers) : entier Var : k, somme : entier Début Somme <= 0 Pour k de a à b faire Somme<=somme + k Retourner (somme) Fin
Exercice 22 Ecrire une fonction multiplication de a et b par addition successives. Fonction : multiplication (a, b : entiers) : entier Var : k, produit : entiers Début produit<=0 Pour k de 1 à a faire Produit<=produit + b Retourner (produit) Fin
A.BENHARI
104
Exercices sur les Tableaux Exercice 23 Ecrire une action qui permette la saisie d’un tableau croissant : si T[k]T[k+1] on redemande la saisie d’un nombre plus grand Const : MAX=100 Ttype : Ttab=tableau [max]d’entier Action : saisie_tableau_croissant Var : tab : Ttab, i : entier Début Lire (Tab[0]) Pour i de 1 à MAX-1 faire Répéter lire (tab[i]) jusqu'à tab[i] ≥ tab[i-1] Fin
Exercice 24 Ecrire une fonction retournant le maximum d’un tableau de taille n. Faire le même algorithme mais qui ne retourne que l’indice de la case du tableau contenant le maximum du tableau. Fonction : maximum (tab : Tableau d’entier n :entier) : entier Var : max, i : entiers Début Max <= tab[0] Pour i de 1 à n-1 faire Si tab[i]>max alors max<=tab[i] Retourner (max) Fin
Fonction : maximum (tab : Tableau d’entier n :entier) : entier Var : indice, i, max : entiers Début Max<=tab[0] Indice <=0 Pour i de 1 à n-1 faire Si tab[i]>max alors max<=tab[i] indice<=i Retourner (indice) Fin
A.BENHARI
105
Exercices généraux sur les actions paramétrées 5) Exercice 25 6) Ecrire une fonction Afficher qui affiche a l’écran le contenu d’un tableau. Ecrire aussi l’action principale qui permettra de comprendre comment fonctionne cette fonction afficher. 7) 8) 9) {Ne pas oublier d’indiquer les paramètres du tableau !} 10) Const : MAX : entier=100 11) Type : Ttab : Tableau [MAX] d’entier 12) 13) Fonction Afficher (tab : tableau d’entiers, n entiers) 14) Var : i entier 15) Début : 16) Pour i de 0 à n-1 17) Ecrire (tab[i], « ») 18) Fin 19) 20) Action principale 21) Var t1 t2 : Ttab 22) Début 23) T1[0]<=1 24) T1[1]<=3 25) T2[0]<=4 26) T2[1]<=5 27) T2[2]<=7 28) Afficher (T1, 2) 29) Afficher (T2, 3) 30) Fin 31) 32) Résultat à l’écran : 33) 13 34) 457 35) 36) 37) Exercice 26 38) Ecrire une fonction qui permet la saisie d’un tableau. Faite aussi l’action principale qui permettra d’accéder a cette fonction saisie mais aussi d’afficher dans un second temps le résultat 39) 40) Fonction : saisie (Stab : tableau d’entiers, N :entier) 41) Var : i entier 42) Début : 43) Pour i de 0 à n-1 faire 44) Lire (tab[i]) 45) Fin 46) 47) Action principale 48) Var : tabl : Ttab 49) Début 50) Saisie (toto, 10) 51) Afficher (toto, 10) 52) Fin 53) 54) Ou afficher est la fonction de l’exercice 1. 55) 56) 57) 58) 59)
A.BENHARI
106
60) Exercice 27 61) Ecrire une fonction qui calcule le nombre d’inversion d’un tableau de taille n (c’est à dire itab[j] pour tout i et j.) 62) 63) Fonction inversion (tab : tableau d’entiers, N entier) 64) Var : j, C, i entiers 65) Début 66) C<=0 67) Pour i de 0 à n-2 faire 68) Début 69) Pour j de i+1 à n-1 faire 70) Si tab[i]>tab[j] alors C<=C+1 71) Fin 72) Retourner ( C ) 73) Fin 74) 75) 76) Exercice 28 77) Ecrire une action qui affiche les n premiers éléments de la suite définie par u0=1 et un+1=somme de k=0 jusqu'à n de (uk*un-k) 78) Aide : stocker les éléments dans un tableau toto avec toto[0]=1. Puis on utilise une boucle imbriquée pour calculer toto[n+1]=somme k=0 à k=n de toto[k]*toto[n-k]. 79) 80) Action Suite (E : d :entier) 81) Var : toto : Ttab, i, k : entiers 82) Début : 83) Toto[0]<=1 84) Pour I de 1 à d-1 faire 85) Toto[i]<=0 86) Pour k de 0 à n-1 faire 87) Toto[i]<=toto[i]+toto[k]+toto[i-1-k] 88) Afficher (toto, d) 89) Fin 90) 91) 92) Exercice 29 93) Voyons maintenant quelques exercices rudimentaires de changements dans un tableau 94) Ecrire une action permettant de remplacer toutes les occurrences de x par y dans un tableau de taille n. 95) Ecrire un algorithme qui échange les valeurs des cases i et j dans un tableau. 96) Ecrire un programme qui inverse un tableau. (exemple : 1 5 6 7 3 devient 3 7 6 5 1) 97) 98) Action : Remplacer (E : x : entier, E : y : entier, ES tab : tableau d’entiers, E : n : entier) 99) Var : i :entier 100) Début 101) Pour i de 0 à n-1 faire 102) Si tab[i]=x alors tab[i]<=y 103) Fin 104) 105) 106) Action : Echanger (E : i : entier, E : j : entier, ES : tab : tableau d’entier, E : n :entier) 107) Var : temp 108) Début 109) Si i
A.BENHARI
107
117) 118) 119) 120) 122) 123) 124) 125)
Var : i :entier Début Pour i de 0 à n/2 – 1 faire Echanger (i, n-1-in tab, n) 121) {ou Echanger est la deuxième action de cet exercice} Fin
A.BENHARI
108
Entités : types structurés 1 2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Explications 1 : Les types structurés sont : - les tableaux (voir les exercices précédents) - les entités (ou l’on regroupe plusieurs types sous un même objet) Exemple : Etudiant (nom, groupe, note) Type : Etd : entité ( Nom : chaîne de caractère ; Groupe : caractère ; Note : entier ; ); Pour faire appel à ce type d’entité on fera dans la fonction : Var : Tetd toto ; Toto.nom=alex Toto.groupe=A Toto.note=15 Ecrire (« l’étudiant », toto.nom, « du groupe », toto.groupe, « a eu », toto.note)
Exercice 30 Proposer une entité de données pour stocker un point dans le plan Type : Tpoint=Entité ( 24 abs : entier ; 25 ord : entier ; 26 )
27 28 29 30
Exercice 31 Ecrire les en-têtes des fonctions/actions suivantes : - saisie d’un point - affichage d’un point - calcul de la distance entre deux points - projection d’un point sur l’axe des abscisses 31 Ecrire ensuite les algorithmes de ces fonctions. 32 Faire une action principale qui demande la saisie de deux points, calcule la distance entre ces deux points et affiche les résultats. 33 34 Action SaisieTpoint (S : P : Tpoint) {Tpoint a été défini à l’exercice 30} 35 Début 36 Lire (P.abs) 37 Lire (P.ord) 38 Fin 39 40 Action AfficherTpoint (E : P : Tpoint) 41 Début 42 Ecrire (« ( », P.abs, « ; », P.ord, « ) ») 43 Fin 44 45 Fonction distance (P : Tpoint ; Q : Tpoint) : réel 46 Var : dist : réel 47 Début 48 Dist<=sqrt[(P.abs-Q.abs)² + (P.ord-Q.ord)²] 49 Retourner (dist) 50 Fin 51 52 Action ProjectionX (ES : P : Tpoint)
A.BENHARI
109
53 Début 54 P.ord<=0 55 Fin 56 57 Action Principale 58 Var : P, Q : Tpoint 59 Dist : réel 60 Début 61 SaisieTpoint(P) 62 SaisieTpoint(Q) 63 Dist<=distance(P, Q) 64 Ecrire (« la distance entre »,AfficherTpoint(P), « et », AfficherTpoint(Q), « est », dist) 65 Fin 66 67 68 Explications 2: 69 Nous ne rentrerons pas ici le tableau comme nous l’avons fait précédemment : 70 Nous utiliserons les entités. Ainsi la déclaration se fera de la manière suivante : 71 Const MAX=100 72 Type : TtabVar=entité ( 73 Tab : tab[MAX] d’entier 74 Taille : entier 75 ) 76 77 Ainsi, dans une fonction, on aura : 78 TtabVar : toto 79 Toto.tab[15]<=1 {pour entrer une valeur de tableau} 80 Toto.taille++ {On augmente la taille du tableau au fur et a mesure 81 Avantage de cette nouvelle manière d’entrer un tableau : on peu avoir un tableau de taille variable. 82 83 84 Exercice 32 85 Ecrire un algorithme qui permet de rentrer les données d’un tableau de type TtabVar et dont on connaît la taille. 86 Ecrire ensuite un algorithme qui permet de rentrer les données d’un tableau de type TtabVar et ou l’on ne connaît pas la taille. 87 88 Action saisieTtabVar (S : tabvar : TtabVar, E : n : entier) 89 Var : i : entier 90 Début 91 Pour i de 0 à n-1 faire 92 Lire (tabvar.tab[i]) 93 Tabvar.taille<=n 94 Fin 95 96 Action saisieTtabVar (S tabvar : TtabVar) 97 Var : réponse : chaîne de caractère 98 Début 99 Tabvar.taille<=0 100 Répéter 101 Ecrire (« voulez-vous entrer un entier ? ») 102 Lire (réponse) 103 Si réponse≠ « non » alors 104 Lire (tabvar.tab[tabvar.taille]) 105 Tabvar.taille++ 106 Jusqu’à (réponse= « non » ou tabvar.taille=MAX) 107 Fin 108 109 110
A.BENHARI
110
111 112 Exercice 33 113 Ecrire un algorithme qui permet de rentrer un tableau de taille variable de Tpoint (voir exercice 30 et 31). Pour cela, il faudra au préalable créer un nouveau type d’entité. 114 115 Const MAX=100 116 Type TtabVarPt=entité (tab : tableau[MAX] de Tpoint, taille : entier) 117 118 Action : SaisieTtabVarTpoint (S : tabvarPt : TtabVarTpoint) 119 Var : réponse : chaîne de caractère 120 Début 121 Tabvar.taille<=0 122 Répéter 123 Ecrire (« voulez-vous entrer un entier ? ») 124 Lire (réponse) 125 Si réponse≠ « non » alors 126 Lire (tabvarpt.tab[tabvarpt.taille].abs) 127 Lire (tabvarpt.tab[tabvarpt.taille].ord) 128 Tabvarpt++ 129 Jusqu’à (réponse= « non » ou tabvar.taille=MAX) 130 131 132 Exercice 34 133 Ecrire un algorithme qui détermine le point ( ( !) c’est à dire son indice)le plus au nord et le point le plus a l’ouest dans un tableau de Tpoint. 134 Faire ensuite une action principale qui demande la saisie d’un tableau de Tpoint à l’utilisateur (voir exercice 33) et affiche l’élément le plus au nord et l’élément le plus à l’ouest. 135 136 Action NordOuest (E : tvp : TtabVarPt, S : nord : entier, S : ouest : entier) 137 Var : i : entier 138 Début 139 Nord<=0 140 Ouest<=0 141 Pour i de 0 tpv.taille-1 faire 142 Si tvp.taille[i].abs
A.BENHARI
111
155 156 157 158 159 160
164 165 166 167
Exercice 35 Ecrire un algorithme qui détermine la distance maximale entre deux points d’un tableau de Tpoint Action DistMax (E : tvp : TtabVarPt) Var : i, j : entiers ; Dmax, dist : reels Début 161 Dmax<=0 162 Pour i de 0 à tvp.taille-2 faire 163 Pour j de i+1 à tvp.taille-1 faire Dist<=distance(tvp.tab[i] ; tvp.tab[j]) Si dist>Dmax alors Dmax<=dist Ecrire (« la distance maximale entre deux points du tableau est », Dmax) Fin
A.BENHARI
112
Tableaux triés et découpages fonctionnels Exercice 36 Le but de l’exercice est de créer une action de saisie de tableau, qui trie, au fur et à mesure des entrées, les valeurs par ordre croissant dans le tableau. Exemple : Soit le tableau suivant : 0
1
2
3
2 5 7 9 Comment insérer 6 dans le tableau trié (en supposant qu’il n’y a pas de doublon dans le tableau) ? - je cherche la bonne position (ici : la case d’indice 2) - décalage à droite si nécessaire : 0
1
2
5 -
2
3
4
7 7 9 Insertion de l’élément
0
1
2
3
4
2
5
6
7
9
126) On a donc ici le découpage fonctionnel : On va donc créer une fonction IndiceEltSup qui cherche la bonne position, une action Insérer qui inclue le nombre entré dans la bonne case du tableau, et une action DécalageDroite qui décale comme dans l’exemple toutes les cases d’un rang vers la droite si nécessaire. Const MAX=100 Type TtabVar = entité (tab : tableau[MAX] d’entiers, taille : entier) Fonction IndiceEltSup (tvt : TtabVar, entier, n : entier) : entier Var : i : entier Début Tant que (i≤tvt.taille ET tvt.tab[i]
A.BENHARI
113
Exercice 37 127) Faire un algorithme qui fait une recherche dichotomique dans un tableau trié. On pourra utiliser les fonctions de l’exercice précédent. Nous allons créer une action qui définie la zone de recherche, puis l’action RechercheDicho qui opérera la recherche dichotomique dans l’intervalle définie par la zone de recherche. Action ZoneRecherche (E : tvt : TtabVar, E : n : entier, ES : Binf : entier, ES : Bsup : entier) Var : milieu : entier Début Milieu <= (Binf + Bsup)/2 Si tvt.tab[milieu]=n alors Début Binf<=milieu Bsup<=milieu Fin Sinon Si tvt.tab[milieu]>n alors Bsup<=milieu –1 Sinon Binf<=milieu+1 Fin Fonction RechercheDicho (E : tvt : TtabVar, E : n : entier) Var : Binf, Bsup : entiers Début Binf<=0 Bsup<=tvt.taille –1 Tant que Bsup>Binf faire ZoneRecherche (tvt, n, Binf, Bsup) Si Bsup=Binf alors Retourner (Binf) Sinon retourner ( -1)
Exercice 38 128) Faire un algorithme qui supprime une valeur dans un tableau trié. On pourra utiliser des fonctions des deux exercices précédents. Le but est d’utiliser la recherche dichotomique de l’exercice précédent pour trouver dans le tableau l’indice de la valeur que l’on veut supprimer puis faire un décalage à gauche pour remettre en place les valeurs (sans qu’il y ait de vide dans une case du tableau) Action Supprimer (ES : tvt : TtabVar, E : n : entier) Var : i : entier Début i<=RechercheDicho(tvt, n) Si i≠ -1 alors DecalageGauche (tvt, i) Fin Action DecalageGauche (Es : tvt : TtabVar, E : i : entier) Var : j: entier Début Pour j de i+1 à tvt.taille –1 faire Tvt.tab[j –1] <= tvt.tab[j] Tvt.taille <= tvt.taille –1 Fin
A.BENHARI
114
Les Chaînes On va maintenant faire des exercices sur les chaînes de caractères. En pratique on pourra définir une chaîne de caractères de deux manières : Const MAX entier = 100 Type Tchaine = entité ( tab : tableau[MAX] de caractères Longueur : entier) Ou bien : Const MAX entier = 100 Type Tchaine = tableau [MAX] de caractères {Avec la sentinelle END}
Exercice 39 Faire un algorithme qui détermine la longueur d’une chaîne de caractères. Faire ensuite de deux manières différentes, une fonction qui permet de copier la chaîne d’une source dans une chaîne destination. Fonction Longueur (chaine : Tchaine) : entier Var i : entier Début i 0 Tant que chaine[ i ] != END faire i i+1 Retourner (i) Fin
Fonction de copie : première méthode : Fonction Copier (E : src : Tchaine, S : dest : Tchaine) Var i, Lsrc : entier Début Lsrc Longueur(src) Pour i de 0 à Lsrc faire dest[ i ] src [ i ] Fin Fonction de copie : deuxième méthode : plus optimisée : Fonction CopieOptimisée (E : src : Tchaine, S : dest : Tchaine) Var i : entier Début i 0 tant que src[ i ] != END faire dest [ i ] src [ i ] i i+1 dest [ i ] src [ i] {pour copier en fin de fichier la sentinelle} Fin
A.BENHARI
115
Exercice 40 Faire une fonction de concaténation (ajoute à la fin de la première chaîne de caractères le contenu de la deuxième chaîne de caractères.) Faire une fonction de Comparaison qui compare deux chaînes de caractères suivant l’ordre lexicographique. Faire une fonction qui efface une partie de la chaîne en spécifiant une longueur d’effacement et un indice à partir duquel il faut effacer. Action Concaténation (ES : src1 : Tchaine, E : src2 : Tchaine) Var i, Lsrc1 : entiers Début i 0 Lsrc Longueur (src1) Tant que src2 [ i ] != END Src1[ Lsrc1+i] src2[ i ] i i+1 src1[Lsrc1+i] src2[ i ] Fin
Pour faire la fonction comparer, il faut d’abord créer une fonction qui compare les caractères : Fonction ComparerChar (char a, char b) Début Si ab retourner (1) Fin On peut maintenant faire la fonction de comparaison de chaînes de caractères qui utilisera la fonction ComparerChar : Fonction Comparer (E : src1 : Tchaine, E : src2 : Tchaine) Var i, L1, L2, cmp : entiers Début L1 Longueur (src1) L2 Longueur (src2) I 0 Tant que (i
Fonction Effacer (ES : src : Tchaine, E : indice : entier, E : lg : entier) Var i, Lsrc : entiers Début Lsrc Longueur (src) Pour i de indice+lg à Lsrc faire Src[i-lg] src[ i ] Fin
A.BENHARI
116
Exercice 41 Ecrire l’en-tête d’une action multi décalage à droite qui décale à droite les éléments d’une chaîne à partir d’un certain indice et insère des cases vides à la place. (des actions de multi décalage ont déjà été vue avec les tableaux, on ne demande pas d’en refaire une ici, ce référer aux exercices sur les tableaux) Faire une action d’insertion. On pourra pour cela utiliser au paravent la fonction multi décalage à droite précédente. Faire une action de remplacement d’une partie d’une chaîne de caractères par une autre chaîne de caractères dont la longueur n’est pas forcément la même. On pourra utiliser des fonctions des exercices 39 et 40. Faire une fonction Extraire qui prend une partie de chaîne de caractères à partir d’un certain indice et la met dans une chaîne destination. Faire une fonction de recherche qui recherche une chaîne dans une chaîne de caractère et retourne un indice si à partir de cette case on a la chaîne cherchée. Sinon, elle retourne –1. Faire une action qui changent toutes les occurrences d’une chaîne dans une chaîne de caractères par une autre chaîne tampon. Action MultidécalageDroite (ES : src : Tchaine, E : indice : entier, E : lg : entier) Action Insérer (ES : src : Tchaine, E : indice : entier, E : motif : Tchaine) Var i, Lsrc, Lmotif : entier Début Lmotif Longueur(motif) MultidécalageDroite (src, indice, Lmotif) Pour i de 0 à Lmotif-1 faire src[indice+i] motif[ i ] Fin Action Remplacer (ES : src : Tchaine, E indice : entier, E lg : entier, E : motif : Tchaine) Début Effacer (src, indice, lg) Insérer (src, indice, motif) Fin Fonction Recherche (src : Tchaine, motif : Tchaine, Binf : entier) Var : i, Lsrc, Lmotif : entiers Tampon : Tchaine Début Lsrc Longueur (src) Lmotif Longueur(motif) i Binf Extraire (src, i, Lmotif, tampon) Tant que (i
A.BENHARI
117
Les fichiers Rappelons tout d’abord comment on manipule les fichiers en ASD. On ne manipule que les identificateurs de fichiers. On ne se soucie donc pas des fichiers sources. Pour ouvrir un fichier : OuvrirFichier (IdFic, ModeOuverture) Avec ModeOuverture = lecture ou écriture ou rajout. Pour fermer un fichier FermerFichier (IdFic) Pour lire un fichier LireFichier (IdFic, élément)
cela correspond à Lire(n)
Pour écrire un fichier EcrireFichier (IdFic, élément)
cela correspond à Ecrire(n)
cin>>n
cout<
Exercice 42 Faire l’algorithme d’une action qui lit un fichier d’entiers et affiche tous les entiers de ce fichiers qui sont pairs. Ecrire une action qui lit un fichier d’entiers et met dans un autre fichier d’entiers les valeurs paires. 129) Faire une fonction qui recherche un entier x dans un fichier d’entiers et retourne vrai si x est dans le fichier. Action EntierPairs (E : Fic : fichier d’entiers) Var n : entier Début OuvrirFichier (Fic, lecture) Si EtatFichier (Fic) = succès alors LireFichier (Fic, n) Tant que (EtatFichier (Fic) ≠ FdF) faire {ou FdF signifie Fin de Fichier} Si n%2=0 alors Ecrire(n) LireFichier(n) FermerFichier (Fic) Sinon Ecrire (« Erreur, impossible d’ouvrir le fichier en lecture ») Fin Action EntiersPairsFichier (E : f1 : fichier d’entiers, ES : f2 : fichier d’entiers) Var n : entier Début OuvrirFichier (f1, lecture) Si EtatFichier (f1) = succès alors OuvrirFichier (f2, écriture) Si EtatFichier (f2) = succès alors LireFichier (f1, n) Tant que EtatFichier(f1)≠FdF faire Si n%2=0 alors EcrireFichier(f2, n) LireFichier (f1, n) FermerFichier(f2) Sinon écrire (« Erreur en écriture ») FermerFichier (f1) Sinon écrire (« Erreur en lecture ») Fin
Fonction Recherche (x : entier, f : fichier d’entiers) : booléen Var bool rep false Début OuvrirFichier (f, lecture) Si EtatFichier(f)=succès alors
A.BENHARI
118
LireFichier(f, n) Tant que (EtatFichier(f) ≠ FdF ET n≠x) faire LireFichier(f, n) Si n=x alors rep true FermerFichier (f) Sinon Ecrire (« Erreur en lecture ») Fin
Exercice 43 130) Faire une action de fusion de deux fichiers d’entiers. Le fichier de sortie doit être trié. Action Fusion ( E : f1 : fichier d’entiers, E : f2 : fichier d’entiers, S : f3 : fichier d’entiers) Var : f3 : fichier d’entiers Début OuvrirFichier (f1, lecture) Si EtatFichier (f1)=succès alors OuvrirFichier (f2, lecture) Si EtatFichier (f2)=succès alors OuvrirFichier (f3, écriture) Si EtatFichier (f3)=succès alors LireFichier (f1, n1) LireFichier (f2, n2) Tant que (EtatFichier(f1) ≠FdF ET EtatFichier(f2)≠FdF) faire Si n1
A.BENHARI
119
Exercice 44 Soit le type suivant : Type : Tetd = entité (
Nom : chaîne Numéro : étudiant Notes : tableau [5] d’entiers Moyenne : entier) On suppose que la fonction de saisie Fonction SaisieEtd () : Tetd 131) Permettant de saisir un tableau de Tetd existe. On pourra donc s’en servir Ecrire une fonction qui permet de saisir un groupe d’étudiant dans un fichier. Ecrire une fonction qui permet de calculer la moyenne générale d’un groupe d’étudiant.
Action SaisieGroupe (E : nb : entier, S : Fic : fichier de Tetd) Var : etd : Tetd i : entier Début OuvrirFichier (fic, écriture) Si EtatFichier (fic)=succès alors Pour i de 1 à nb faire Etd SaisieEtd( ) EcrireFichier (fic, etd) FermerFichier (fic) Sinon écrire (« Erreur ») Fin Fonction Moyenne (fic : fichier de Tetd ) : réel Var : Som : réel Début Som 0 nb 0 OuvrirFichier (fic, lecture) Si EtatFichier (fic)=succès alors LireFichier (fic, etd) Tant que EtatFichier (fic)≠FdF) faire nb nb+1 Som Som + etd.moyenne LireFichier(fic, etd) Retourner (Som/nb) FermerFichier (fic) Sinon écrire (« Erreur ») Fin Bibliographie [1] T. H. Cormen, C. E. Leiserson, and R. L. Rivest . Introduction to Algorithms. The MIT Press, 1990 [2] A. Darte and S. Vaudenay. Algorithmique et optimisation Dunod 2001 [3] D. Froidevaux, M. Gaudel, and D. Soria. Types de données et algorithmes . Mcgraw-Hill, 1990 [4] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein. Introduction to Algorithms, Third Edition. The MIT Press Cambridge, Massachusetts London, England , 2009
A.BENHARI
120