View
10
Download
0
Category
Preview:
Citation preview
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
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.
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
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
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 //..
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).
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
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
Recommended