Soient xune liste de longueur net iun entier. eest une valeur quelconque.
—x[i] : accès à l’élément i,Θ(1)
—x.append(e) : insertion en fin de liste, Θ(1)
—x=x+[e]: construction d’une nouvelle liste contenant les éléments de xsuivis de e,θ(n)
—x.insert(i, e) : insertion de een position i,Θ(nombre d’éléménts déplacés) = Θ(n−i), ou Θ(1) si
aucun élément n’est déplacé.
—e = x.pop(i) : suppression de l’élément à la position i,Θ(nombre d’éléments déplacés) = Θ(n−i), ou
Θ(1) si aucun élément n’est déplacé.
Hypothèse simplificatrice : on suppose que l’espace mémoire alloué par Python pour stocker les éléments de
la liste est suffisant pour ajouter un élément en fin. L’insertion en fin est donc en Θ(1) et l’insertion en milieu
de liste en Θ(nombre d’éléments déplacés)2.
2.2 Structure de données = implantation + constructeurs + testeurs + sélecteurs
+ modifieurs (10mn)
L’utilisateur de notre structure de données ne devrait pas avoir à se soucier de la représentation interne de
notre vecteur creux (on parle de structure de données "opaque" ou "abstraite").
Lorsqu’on doit choisir une structure de données, avant de se poser la question « Comment représenter un
vecteur creux en Python ? » (c’est-à-dire « Quelle structure de données utiliser ? »), il faut se poser la question
«Pourquoi représenter un vecteur creux ? », c’est à dire « Quel jeu de fonctions proposer à l’utilisateur ? ».
Nous allons fournir à l’utilisateur des fonctions permettant de modifier ou de lire cette structure de données.
Pour notre vecteur creux, ces opérations sont les mêmes que pour np.array, mais leur implémentation et
leur complexité sera différente.
Ces fonctions sont de plusieurs types :
— les constructeurs permettent de créer une structure de données vide ou de créer une structure de données
à partir d’un fichier ou d’une autre structure de données (exemple : np.array(...)) ;
— les testeurs et sélecteurs permettent d’interroger la structure de données sans la modifier (est-ce qu’un
élément est présent dans l’ensemble ? combien d’éléments contient l’ensemble ?) (exemples : x.shape(),
x[...]) ;
— les modifieurs permettent de modifier la structure de données (ajouter un élément, en supprimer un,
extraire un élément quelconque) (exemple : x[...] = ...) ;
— des opérateurs qui prennent en entrée plusieurs instance de la structure et renvoient une valeur fonction
de ces entrées ;
— éventuellement, les destructeurs permettent de détruire la structure de données (en Python, dans beau-
coup de cas ils ne sont pas nécessaires).
Elles constituent l’interface de la structure de données.
2.3 Spécification de l’interface (10mn)
Spécifier l’interface, c’est donner la réponse à la question « Pourquoi ? » ci-dessus, sous la forme de liste de
fonctions avec leurs paramètres et leurs valeurs de retour, sans en donner le contenu.
Note : la bibliothèque NumPy utilise les opérateurs (+,[], ...) pour l’interface de programmation des vecteurs,
mais vous n’avez pas les notions de Python nécessaires pour le faire : toute l’interface utilisera donc des fonctions
(def ...).
Donner une liste des fonctions de l’interface d’une structure de données « ensemble », par catégorie, avec
pour chaque fonction ce qu’elle fait et la liste des paramètres.
Par exemple :
—creer_vecteur(n) renvoie un vecteur vide de taille n
—creuser(v_dense) construit un vecteur creux représentant la même valeur mathématique que la liste
Python v_dense.
—remplir(v_creux) construit une liste Python représentant la même valeur mathématique que le vecteur
creux v_creux
—taille_vecteur(v) renvoie la taille du vecteur
2. En réalité, la complexité de ces opérations fait appel à la notion de complexité amortie qui n’est pas au programme, cf.
https://wiki.python.org/moin/TimeComplexity
3