—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 instances 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 « vecteur creux », par catégorie,
avec pour chaque fonction ce qu’elle fait et la liste des paramètres.
2.4 Représentation et implantation (30mn)
Implanter une fonction ou un algorithme, c’est la réponse à la question « Comment? » ci-dessus.
Il faut choisir quel(s) type(s) Python utiliser, mais aussi comment les valeurs y sont stockées.
Nous proposons d’étudier la représentation d’un vecteur creux par une liste de doublets [indice, valeur]
(valeur est une valeur numérique quelconque. Pour simplifier on travaille avec des entiers, mais le code marchera
aussi avec des flottants par exemple). Pour mémoriser la taille du vecteur, on force la dernière valeur à être
représentée par un doublet même si elle est nulle. Les autres valeurs nulles ne sont pas représentées (on interdit
la présence d’un doublet [indice, 0] si indice n’est pas le dernier élément 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
2