02I_Algo02

10
Algorithme, Tableaux, Structures, fichiers et bdd Note préliminaire : le formalisme des instructions utilisé ici approche le formalisme utilisé dans l'interpréteur Alg'Exec. Mais il ne lui correspond pas exactement car Alg'Exec est contraignant sur certains points où son formalisme est inadapté à l'algorithmique. Dans certains cas, il sera fait référence à d'autre formalismes, ce sera alors explicitement indiqué. 1 Introduction Les variables que nous avons vues sont jusqu'à présent élémentaires. Elles ne contiennent qu'une seule valeur d'un type simple. Cependant, il arrive que nous soyons obligés de traiter des données groupées en table et des données différentes appartenant à un même groupe. Dans le premier cas, nous observerons les tableaux de données, dans le second, de donnée de type structuré vus conjointement aux fichiers et tables de BDD. Vous trouverez, enfin, des exemples mixé de données structurées, de tableaux, de fichiers ou tables de bases de données. 2 Tableaux Les tableaux sont une suite de cases de type élémentaire, assemblées en un seul bloc (comme des cubes collées les uns aux autres, ou une rangée d'alvéoles) Nous allons voir comment lire, modifier, modifier, rechercher, intervertir des éléments. 2.1 Déclaration d'un tableau Lors de la déclaration, on indique le nombre total d'éléments du tableau (que ceux-ci soient affectés ou non). Ce nombre sera le nombre d'éléments maximum que l'on pourra mettre dans le tableau. Dans la partie déclaration on écrit : monTableau[1 : 10] : tableau de entier 'Déclaration de mon tableau Décortiquons : monTableau : nom de la variable [] : indication d'intervalle d'indices 1 : indice minimum (facultatif, 1 par défaut) 10 : indice maximum (obligatoire ; les indices min et max sont séparés par un : ) Tableau : type tableau de : mot de séparation du type tableau et du type des éléments entier : type de chaque élément.

Transcript of 02I_Algo02

Page 1: 02I_Algo02

Algorithme, Tableaux, Structures, fichiers et bdd

Note préliminaire : le formalisme des instructions utilisé ici approche le formalisme utilisé dans l'interpréteur Alg'Exec. Mais il ne lui correspond pas exactement car Alg'Exec est contraignant sur certains points où son formalisme est inadapté à l'algorithmique.

Dans certains cas, il sera fait référence à d'autre formalismes, ce sera alors explicitement indiqué.

1 Introduction Les variables que nous avons vues sont jusqu'à présent élémentaires.

Elles ne contiennent qu'une seule valeur d'un type simple.

Cependant, il arrive que nous soyons obligés de traiter des données groupées en table et des données différentes appartenant à un même groupe.

Dans le premier cas, nous observerons les tableaux de données, dans le second, de donnée de type structuré vus conjointement aux fichiers et tables de BDD.

Vous trouverez, enfin, des exemples mixé de données structurées, de tableaux, de fichiers ou tables de bases de données.

2 TableauxLes tableaux sont une suite de cases de type élémentaire, assemblées en un seul bloc (comme des cubes collées les uns aux autres, ou une rangée d'alvéoles)

Nous allons voir comment lire, modifier, modifier, rechercher, intervertir des éléments.

2.1 Déclaration d'un tableauLors de la déclaration, on indique le nombre total d'éléments du tableau (que ceux-ci soient affectés ou non). Ce nombre sera le nombre d'éléments maximum que l'on pourra mettre dans le tableau.

Dans la partie déclaration on écrit : monTableau[1 : 10] : tableau de entier 'Déclaration de mon tableau

Décortiquons : monTableau : nom de la variable

[] : indication d'intervalle d'indices

1 : indice minimum (facultatif, 1 par défaut)

10 : indice maximum (obligatoire ; les indices min et max sont séparés par un : )

Tableau : type tableau

de : mot de séparation du type tableau et du type des éléments

entier : type de chaque élément.

Remarques :

L'indice maximum indique le nombre maximum d'éléments. Dépasser ce nombre provoque une erreur.

Un tableau déclaré de cette façon sera homogène. Tous les éléments ont toujours le même type.

2.2 Accès aux élémentsPour repérer un élément parmi les autre, on utilise un index, nombre entier qui permet d'accéder à un élément (imaginez un ascenseur et ne n° des étages).

Pour lire un élément ou le modifier, on indiquera la valeur de l'indice :

a <- monTableau[1] // a prend la valeur de l'élément n°1monTableau[5] <- 3456 // l'élément n°5 prend la valeur 3456

Page 2: 02I_Algo02

monTableau[3] <- [123, 456] // les éléments n°3 et n°4 prennent respectivement les valeurs 234 et 456

b <- 3a <- monTableau[b] // a prend la valeur de la cellule n° 3

2.3 Lecture séquentielle d'un tableauPour lire tout un tableau, on utilisera alors une boucle 'pour' et non un 'TantQue' ou 'Répéter' :

pour indice de 1 à 10 faireTraitements

finPour

exemple : fonction somme(tabEntier[] : tableau de entier, iMax : entier) : entier/* faire la somme du tableau d'entiers donné, le nombre d'éléments est aussi donné.*/var // Déclarations

i : entier ' indice de travailsomme : entier ' résultat de la somme

début // Corpssomme <- 0pour i de 1 à iMax

somme <- somme+tabEntier[i]finPourretourner somme // attention, retourner n'existe pas dans Alg'Exec

Fin

Remarque : pas besoin d'indiquer indiceMin et indiceMax dans la définition du tableau transmis en paramètre.

Note : dans Alg'Exec, à la place de "retourner", il faut utiliser une variable prédéfinie "valret" qui permet de retourner une valeur dans les fonctions. /ex, à la place de "retourner somme" il faudrait écrire "valret <-somme". C'est ce qui me fait dire qu'Alg'Exec n'est pas la panacée et en DOIT PAS être la référence en terme de formalisation algorithmique.

2.4 Rechercher dans un tableauPour rechercher un élément dans un tableau, on ne peut plus utiliser de boucle pour car on ne sait pas à quel moment on s'arrêtera.

Exemple : rechercher le plus grand élément d'un tableau

2.5 Effacement dans un tableauPour effacer un élément du tableau, on a le choix entre différentes solutions :

1. On attend que l'élément soit écrasé par une nouvelle valeur.

2. On met l'élément à une valeur signifiant "élément vide" par convention.

3. On compresse les éléments et on note le nombre d'élément "valides" dans une variable associée au tableau.

4. Autres solutions …

La solution 1 est facile à mettre en œuvre, mais on ne sait pas, à priori quelles sont les éléments que l'on peut écraser. Eventuellement, la variable indice peut y être liée.

La seconde solution est déjà un peu meilleure mais on se prive d'une valeur possible et on est obligé de rechercher les éléments vides avant de pouvoir mettre un nouvel élément.

Page 3: 02I_Algo02

La troisième solution nécessite un traitement à chaque suppression mais, connaissant l'indice du dernier élément (ou du premier disponible) il est facile d'ajouter un élément.

A noter que si les éléments d'un tableau doivent être triés, cela complique le problème car il faut rechercher la juste place de l'élément à ajouter et l'insérer dans le tableau, ce qui nécessite de lui faire de la place en décalant tous les éléments avant de l'ajouter ou le mettre à la fin et re-trier le tableau.

Les autres solutions sont d'utiliser autre chose qu'un tableau pour faire une liste d'éléments. Nous n'étudierons pas cette autre chose dans ce cours.

Exemple : Faire un extrait des algorithmes permettant d'illustrer chacune des trois solutions

2.6 Compresser les éléments d'un tableauLes élément du tableau sont tous des entiers naturels (positifs). La valeur –1 marque un trou dans le tableau.

a) faire l'algorithme d'initialisation du tableau

b) Faire l'algorithme pour combler tous les trous dans le tableau.

2.7 Intervertir des élémentsAvec le tableau de caractères suivant : bonjour[7] qui contiendra {'B', 'O', 'N', 'J', 'O', 'U', 'R'}.

On utilisera la procédure iniBonjour(es bonjour[] : tableau de caractère) pour initialiser le tableau et afficherBonjour(bonjour[] : tableau de caractère) pour afficher le contenu du tableau.

a) faire l'algorithme pour intervertir les éléments deux à deux, observez le résultat.

b) faire l'algorithme qui inverse le sens des éléments (ruojnob).

2.8 Tableaux et fonctions ou procéduresOn peut transmettre un tableau aux fonctions ou procédures dans les paramètres.

Illustration :Fonction sommeTableau(tableauEntier[1..10] : tableau de entier) : entier

/* Fonction qui renvoie la somme des éléments d'un tableau */var // Déclarations

i, somme : entier ' respectivement indice et somme du tableaudébut // Corps

pour i de 1 à 10 fairesomme <- somme+tableauEntier[i]

finPourretourner somme

fin// fin de l'algorithme

De même, il est possible de retourner un tableau :Procédure insérerElément(es ancienTab[1..10] tableau de caractère; élément : caractère)/* Procédure qui insère un élément dans un tableau trié. Attention, le tableau est modifié ! Si le tableau original est plein, soit le dernier élément est perdu : (['a', 'c', 'd'], 'b') => ['a', 'b', 'c']

soit l'élément à insérer est ignoré : (['a', 'c', 'd'], 'e') => ['a', 'b', 'd']*/var // Déclarations

i, j : entier ' respectivement indices du nouveau et de l'ancien tableau

Page 4: 02I_Algo02

nouvTab : tab[1..10] de caractèredébut // Corps

j<-1pour i de 1 à 10

si (élémentInséré = 'OUI' ou tableau[j] < élément) alorsnouvTab[i] <- ancienTab[j]i <- i+1 // passer à l'élément suivant de l'ancien tableau

sinonnouvTab[i] <- élémentélémentInséré <- 'OUI' // l'élément a été inséré

finSifinPourancienTab <- nouvTab

fin

Notez la présence de l'indicateur "es" avant le paramètre modifiable dans la procédure. Le cas le plus fréquent de modification du contenu d'un paramètre concerne les tableaux.

3 Variables structuréesSi on manipule des personnes, rien n'est plus gênant de devoir toujours utiliser plusieurs variables pour la même personne.

Exemple : Saisir les nom, prénom et âge de 10 personnes

Solution 1 : on utilise un tableau pour chaque donnéeenregistrerPers()var // Déclarations

i : entier ' indice commun aux tableauxtNom, tPrénom[1..10] : tableau de chaîne ' noms & prénoms des personnestAge[1..10] : tableau de entier ' âges des personnes

début // Corpspour i de 1 à 10 faire

afficher("personne n° ", i)saisir("nom =? ", tNom[i])saisir("prénom =? ", tPrenom[i])saisir ("âge =? ", tAge[i])

finPourfin

Quels problèmes pose cet algorithme ?

il faut traiter autant de tableaux que de données,

chaque tableau est traité séparément pour une même personne

les indices doivent correspondre, sinon risque de traiter une donnée d'une personne et une autre d'une autre personne simultanément

il n'est pas possible de retourner le tableau car on ne peut retourner qu'une seule donnée à la fois

une fausse solution serait d'utiliser un tableau à deux dimensions, mais toutes les données seraient alors du même type et l'algorithme deviendrai difficile à lire.

Solution 2, utiliser un tableau d'éléments structurés :enregistrerPers() var // Déclarations

i : entier ' indice commun aux tableauxtPers[1..10] : tableau de structure personne

nom : chaîne ' nom de personneprénom : chaîne ' prénom de personneâge : entier ' âge de personneFinStructure

Page 5: 02I_Algo02

début // Corpspour i de 1 à 10 faire

ecrire("personne n° ", i)lire("nom =? ", tPers[i].nom)lire("prénom =? ", tPers[i].prénom)lire("âge =? ", tPers[i].âge)

finPourfin

Quels sont les avantages de cet algo ?

- lisibilité (même si ce n'est pas très évident ici)

- représentation individuelle de chaque personne : à chaque élément du tableau tPers correspond une et une seule personne

- on peut retourner ce tableau (en une fois)

3.1 Réutiliser une structure ; type structurépour réutiliser une structure, on construit un type personnalisé :

Type Personne // déclaration du type structurénom : chaîneprénom : chaîneâge : entier

finTypevar unePersonne : Personne // déclaration d'une variable de type Personne

unTabDePers[1..10] : tableau de Personne // et d'un tableau de Personnes…

unePersonne.nom <- nomLu // utilisation d'une variable de type PersonneunTabDePers[indice].nom <- nomLu // utilisation d'un tableau de PersonnesunTabDePers[indice] <- unePersonne // affectation directe car même types

3.2 ExemplesSi chaque personne est enregistrée avec son nom et son prénom.

Rédigez les algorithmes rechercher(var : nomRecherché) et inverser(var : pos1, pos2) selon la méthode avec tableaux puis avec un type structuré de données (réutilisez les tableaux et types vus ci-dessus).

Concluez.

3.3 Pour la petite histoireSi on pouvait utiliser un langage permettant de masquer les propriétés (variables) d'un type et qu'on pouvait y déclarer aussi des bouts d'algo pour effectuer des traitements propres au type structuré, on aurai un langage … orienté objet !

Le type s'appellerai alors une classe et les variables de ce type objets ou instances.

C'est le cas avec les langages java, C++, C#, …

4 Lecture de fichiers et bases de données

4.1 Introduction, algorithme typeLire un livre, faire une recherche dans un dictionnaire sont des algorithmes similaires à la lecture de fichiers ou l'extraction de données d'une base.

L'algorithme global de la lecture d'un livre est de lire chaque page, du début à la fin du livre :

début // Corps //… équivalent pour fichier ou table de BDD Ouvrir livreOuvert pour le lire // ouverture fichier ou BDD (connexion+ouverture)Lire(page) // 1ère lecture, permet de contrôler s'il y a qqch.TantQue (non fin de livreOuvert) // Tant que non fin de fichier ou de table

Traitements(page) // traiter la lecture couranteLire(page) // lire suivant

FinTantQue // FTQFermer(livreOuvert) // fermer fichier ou BDD (fermer et déconnecter)

Fin //..

Page 6: 02I_Algo02

Lire un fichier se fait de la même façon, on ouvre le fichier, on lit chaque ligne jusqu'à la fin et on le referme :

début // CorpsOuvrir fichierTraité en lectureLire enregistrementDuFichierTantQue non fin du fichier fichierTraité

Traitements(enregistrementDuFichier)Lire enregistrementDuFichier

FinTantQueFermer fichierTraité

Fin

Enfin, lire une base de donnée est à peu près effectué de la même façon :début // Corps

Connexion('serveur', 'utilisateur', 'motDePasse') OuvrirBase('nomDeLaBase') OuvrirRequête('requête_SQL') Lire enregistrementDeLaTable TantQue non fin de la table

Traitements(enregistrementDeLaTable)Lire enregistrementDeLaTable

FinTantQue FermerBase('nomDeLaBase')Déconnexion

Fin

4.2 La lecture de fichier et table, l'écriture de fichiers (Entrées/sorties)La lecture et l'écriture (les entrées/sorties) des fichiers utilisent les instructions lire() et écrire().

Implicitement, on utilisera lire et écrire pour un fichier et saisir et afficher pour le clavier et l'écran.

Ces instructions traitent un enregistrement complet (tous les champs de la ligne en une seule fois)

Lire enregFichierEcrire enregFichier

A la lecture de l'enregistrement, les variables affectées sont celles déclarées dans l'enregistrement (ici enregFichier) à la déclaration du fichier et sont directement exploitables.

D'où la nécessité de décrire l'enregistrement d'un fichier ou une structure de données pour les tables.

Pour effacer un enregistrement dans un fichier, on utilise l'instruction supprimerSupprimer enregFichier

Cette fonction ne supprime que l'enregistrement lu en dernier.

Pour modifier un enregistrement dans un fichier, on utilise l'instruction modifierModifier enregFichier

Cette fonction ne modifie que l'enregistrement lu en dernier, mais tout l'enregistrement (annule et remplace).

Note : dans certains langages, on ne peut pas effacer dans un fichier (ouille!). Pour faire quelque chose qui y ressemble, on va copier un fichier vers un autre en omettant ("oubliant") les éléments à effacer (c'est similaire à combler les "trous" dans un tableau, voir l'exemple correspondant).

Page 7: 02I_Algo02

4.2.1 Lire dans une table de BDD

Si lire est utilisable pour les tables comme pour les fichiers, on ne peut pas utiliser écrire, ni supprimer, ni modifier avec les tables. Il faut passer par une requête qui fait le boulot. Voir les exemples.

4.2.2 Autres conventions d'écriture de l'instruction lire()

Dans certains cas nous utiliserons lire() sous les formes suivantes :

Certains langages demandent d'indiquer la source et la destination comme suit :

Lire(nomIdentifiantLeFichierOuLaTable, variableRecevantLeRésultat)Ecrire(nomIdentifiantLeFichier, variableEnregistrementAEcrire)

ou

lire 1 ligne du fichier & l'affecter à la variable enreg.enreg <- Lire(nomIdentifiantLeFichierOuLaRequête)

ouenreg <- Lire(nomIdentifiantLeFichierOuLaRequête, longueurEnreg)

Idem ci dessus, mais on indique la longueur de l'enregistrement (var. longueurEnreg) sous-entendant que lire ne sait pas déterminer automatiquement la longueur d'un enregistrement.

Ces autres conventions dépendent du langage avec lequel le développeur à pour habitude de programmer.

4.3 L'ouverture et la fermeture Avant de lire un livre, il faut l'ouvrir. Après avoir lu un livre, il faut le fermer (sous peine de l'abîmer)

De la même façon, on va déclarer l'ouverture d'un fichier, le traiter puis le refermer comme suit :

Ouvrir 'nom_du_fichier' en mode_accèsFermer 'nom_du_fichier'

la variable fichierOuvert contiendra un numéro qui permettra d'accéder au fichier par lire() et écrire().

Ce numéro est unique pour chaque ouverture et évite de confondre le fichiers lors d'une lecture alors que plusieurs fichiers sont ouverts.

Exemple : Procédure copier(nomF1 : chaîne, nomF2 : chaîne)/* Description : copie d'un fichier.

Les fichiers F1 et F2 doivent avoir la même forme d'enregistrement Et sont déclarés dans l'algo appelant de copier, si besoin

*/var // Déclarations … début // Corps

Ouvrir 'nomF1' en lectureOuvrir 'nomF2' en écritureLire enregF1TantQue non fin de nomF1

enregF2 <- enregF1Ecrire enregF2Lire enregF1

FinTantQueFermer 'nomF2'Fermer 'nomF1'

Fin

Page 8: 02I_Algo02

Remarquez l'imbrication des ouvertures et fermetures : ouvrir F1 puis F2, fermer F2 puis F1.

Attention : lors de l'ouverture, il faut impérativement indiquer le mode d'accès au fichier. Il y en a trois : lecture, écriture et lecture/écriture.

4.4 Ecriture dans une base de donnéesDans une base de données, on écrit, modifie ou supprime à l'aide de requêtes SQL …

Voir le cours 2 sur le SQL (insert, delete, update).

4.5 Déclaration d'un fichier, d'une table de BDDUn fichier doit être déclaré et on doit indiquer son contenu, sa structure.

Exemple :Fichier personnes enregistrement enreg_personnes

Num : entierNom : chaînePrénom : chaîne…

finEnregistrement

Le mot clé "fichier" peut être remplacé par "table"

Une table de base de données ne doit pas être déclarée mais on utilisera une variable structurée pour contenir un enregistrement de la table.

Structure PersonneNum : entierNom : chaînePrénom : chaîne…

finStructure

on récupérera individuellement chaque champ lors de la lecture de chaque ligne de la table, mais une structure simplifiera son utilisation et donnera un code plus "propre".

5 Trucs et astucesTableaux

Lors de la déclaration d'un tableau, prévoir systématiquement la déclaration de la variable indice de ce tableau.

/ex.

TPersonnes : Tableau[1..100] de chaîne

IPersonne : entier 'Indice du tableau TPersonnes