Algorithmique et structures de données I

publicité
Algorithmique et structures de données I
Frédéric Bapst
• Algorithme =
enchaînement d'opérations destiné à résoudre un problème
• Structure de données =
façon d'organiser des informations pour en faciliter la manipulation
Survol de la matière
• Notion d'analyse de complexité algorithmique
• Techniques de programmation (récursivité, chaînage…)
• Algorithmes classiques (tris…)
• Structures de données du langage (tableaux…)
• Structures de données abstraites (piles, listes…)
• Applications (cryptographie, mots croisés...)
• Métier de programmeur (tests, traitement d'erreurs, assertions...)
• Langage de programmation utilisé dans le cours : Java
-1-
Une distinction très importante
Spécification
• Sorte de "mode d'emploi" d'une méthode, d'une classe...
• Spécification =
+
signature : entêtes java, type des paramètres...
explications sur l'effet attendu
• Le choix des identificateurs, commentaires
• Il peut y avoir des mises en garde : "il est interdit de..."
• Les explications peuvent être des commentaires Java, ou un document
séparé (guide du programmeur)
• Analogie : définir une perceuse, les commandes/boutons qu'elle accepte
Implémentation
• Réaliser le codage, écrire les instructions nécessaires pour que la
méthode/classe fasse son travail
• Analogie: fabriquer l'intérieur de la perceuse (moteur, circuits électroniques...)
Utilisation
• Employer la méthode/classe pour réaliser un autre programme
en respectant scrupuleusement la spécification, et
sans avoir besoin de connaître l'implémentation
• Analogie : utiliser la perceuse (percer, visser, fraiser, poncer, autres usages...)
-2-
Exemple
• Spécification
public static double max(double[] t);
// --- computes the maximum value in the array t
// --- the array must have at least one element
• Implémentation
public static double max(double[] t) {
double m = t[0];
for(int i=1; i<t.length; i++)
if (t[i] > m) m = t[i];
return m;
}
• Utilisation
static double maxInBoth(double[] a, double[] b) {
double ma, mb;
ma = max(a);
mb = max(b);
if (ma>mb) return ma;
return mb;
}
-3-
Type abstrait
• Structure de données : façon de représenter des données, et description des
opérations autorisées sur ces données
• Notamment pour stocker une collection d'éléments.
Opérations typiques :
- ajouter un élément
- rechercher un élément
- enlever un élément
• Exemple de structure de données prévue par Java : le tableau. Opérations :
- construire un tableau à n cases
- lire la case numéro i
- écrire dans la case numéro i
O(n)
O(1)
O(1)
temps d'accès constant !
• Type abstrait : structure de données qu'on ne définit que par ses opérations
(c.-à-d. sans référence aux détails de la représentation)
• On utilise souvent "type abstrait" et "structure de données" comme synonymes
• 3 aspects :
définition
implémentation
utilisation
• Implémentation : serait souvent facile, si on ne cherchait pas l'efficacité !
Minimiser l'ordre de grandeur de la complexité algorithmique des opérations
-4-
Exemple de type abstrait : la Pile
• Collection d'éléments
• Modèle d'organisation des données : Last In First Out (LIFO)
• Importante propriété : la pile peut être vide
push
• Spécification en Java :
public class CharStack {
public CharStack();
public CharStack(int estSize);
public boolean isEmpty();
public void
push(char x);
public char
top();
public char
pop();
//
//
//
//
//
//
//
pop
unknown capacity
expected capacity
returns true if empty
adds x as the most recent elt
gives the most recent elt
gives and removes the most
recent element
}
• Il y a des préconditions : il est interdit de faire pop() si isEmpty() est vrai
(le comportement n'est pas défini, "à vos risques et périls")
• On utilise toujours les identificateurs push() et pop(), parfois peek() pour top()
-5-
Utilisation : Exemple d'application
• Problème : vérifier qu'une chaîne "avec parenthèses" est balancée
Exemple :
"aaa(aa(aaa[aaa{{(aaa)aaaa}aaa}]aaaa))a"
• Algorithme en pseudo-code:
pour chaque caractère x de la chaîne {
si x est une des parenthèses ouvrantes, empiler x
si x est une des parenthèses fermantes
(*)dépiler un caractère et vérifier la correspondance
• En (*), la pile doit être non-vide, et à la fin, elle doit être vide
• Codage en Java :
public static boolean isBalanced(String a) {
CharStack s = new CharStack();
...
// cf. série d'exercice !
}
• La pile est une structure de données essentielle. Par exemple, la machine
virtuelle Java utilise une pile pour les appels de méthodes
p()
;
q()
;
r()
;
-6-
...
{
[
(
(
Implémentation à l'aide d'un tableau
• Il nous faut :
- 1 tableau buffer
- 1 entier
topIndex
topIndex
0 1 2 3 4 5
a b c
pour stocker les éléments
pour désigner l'indice du sommet de la pile
push(e)
buffer
• Cas de la pile vide :
(tenter d'éviter les cas particuliers !)
topIndex
0 1 2 3 4 5
e
buffer
topIndex
-1 0 1 2 3 4 5
buffer
• Codage en Java (cf. série d'exercice !):
public class CharStack {
private ...
// décl. des attributs
public CharStack() {...} // impl. des constructeurs
public void push(char e);// impl. des autres méthodes
}
• Quelle taille pour le tableau ? On a le choix entre plusieurs approches :
- taille indiquée lors de la création
ou taille par défaut ?
- en cas de dépassement, lever une exception ou redimensionner ?
• Complexité des opérations : push, pop, top, isEmpty demande un nombre constant
d'opérations, quelle que soit la taille de la pile. On dit que c'est en O(1)
-7-
Téléchargement