578 lines
16 KiB
Plaintext
578 lines
16 KiB
Plaintext
|
Les structures de données
|
|||
|
===========================
|
|||
|
|
|||
|
.. glossary::
|
|||
|
|
|||
|
ATD
|
|||
|
|
|||
|
Abstract Data Type, structure de données abstraites.
|
|||
|
La représentation des données est forcément un choix.
|
|||
|
Il est impossible de rendre compte globalement d'un élément du réel,
|
|||
|
il faut en faire une interprétation abstraite.
|
|||
|
|
|||
|
**Exemple**:
|
|||
|
|
|||
|
- Un être humain peut être représenté par les données présentes dans sa
|
|||
|
carte d'identité. Mais un être humain n'est pas sa carte d'identité.
|
|||
|
- Un être humain peut être représenté par les données présentes dans ses préférences
|
|||
|
de surf sur internet. Mais un être humain **n'est pas** l'ensemble de ses logs de surf sur le net.
|
|||
|
|
|||
|
Les séquences
|
|||
|
-------------
|
|||
|
|
|||
|
Les types séquences (listes)
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
# 4::1::5::8::1::[];;
|
|||
|
- : int list = [4 ;1 ;5 ;8 ;1]
|
|||
|
|
|||
|
|
|||
|
Un ensemble de valeurs portant le même nom de variable et repérées par un nombre, s’appelle un tableau, ou encore une liste, ou une variable indicée.
|
|||
|
Le nombre qui, au sein d’un tableau, sert à repérer chaque valeur s’appelle l’indice.
|
|||
|
Chaque fois que l’on doit désigner un élément du tableau, on fait figurer le nom du tableau, suivi de l’indice de l’élément.
|
|||
|
|
|||
|
**manipulation** :
|
|||
|
|
|||
|
- `insert()`
|
|||
|
- `append()`
|
|||
|
- `remove()`
|
|||
|
- `find()`
|
|||
|
- `print()`
|
|||
|
- ...
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
zoo = ['bear', 'lion', 'panda', 'zebra']
|
|||
|
print(zoo)
|
|||
|
|
|||
|
# But these list elements are not
|
|||
|
biggerZoo = ['bear', 'lion', 'panda', 'zebra', ['chimpanzees', 'gorillas', 'orangutans', 'gibbons']]
|
|||
|
print(biggerZoo)
|
|||
|
|
|||
|
- Lists Versus Tuples : types mutables, immutables
|
|||
|
- Lists Versus Sets : non ordonné, collection simple
|
|||
|
|
|||
|
- Recherche dans une liste, recherche du maximum dans une liste
|
|||
|
- Recherche d’un mot dans une chaîne de caractères.
|
|||
|
|
|||
|
Algorithme de la longueur d'une liste
|
|||
|
--------------------------------------
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
# let rec longueur l =
|
|||
|
match l with
|
|||
|
[] -> 0
|
|||
|
| ::s -> 1 + (longueur s);;
|
|||
|
|
|||
|
Cette fonction est prédéfinie en Ocaml : `List.length`
|
|||
|
|
|||
|
.. ifconfig:: exercice
|
|||
|
|
|||
|
**Exercice** : écrire un algorithme qui déclare et
|
|||
|
remplisse un tableau de 7 valeurs numériques en les mettant toutes à zéro.
|
|||
|
|
|||
|
.. ifconfig:: correction
|
|||
|
|
|||
|
**Correction** :
|
|||
|
::
|
|||
|
|
|||
|
Tableau Truc(6) en Numérique
|
|||
|
Variable i en Numérique
|
|||
|
Debut
|
|||
|
Pour i <- 0 à 6
|
|||
|
Truc(i) <- 0
|
|||
|
i Suivant
|
|||
|
Fin
|
|||
|
|
|||
|
exemple d'implémentation en python
|
|||
|
|
|||
|
.. code-block: python
|
|||
|
|
|||
|
>>> liste = []
|
|||
|
>>> for i in range(6):
|
|||
|
... liste.append(i)
|
|||
|
...
|
|||
|
>>> liste
|
|||
|
[0, 1, 2, 3, 4, 5]
|
|||
|
>>>
|
|||
|
|
|||
|
|
|||
|
.. ifconfig:: exercice
|
|||
|
|
|||
|
**Exercice** : Calcul du premier élément maximal dans une liste,
|
|||
|
proposer une implémentation en python qui renvoie le maximum et
|
|||
|
la position du max dans la liste.
|
|||
|
|
|||
|
.. ifconfig:: correction
|
|||
|
|
|||
|
**Correction** :
|
|||
|
|
|||
|
.. code-block: python
|
|||
|
|
|||
|
def max_list(L) :
|
|||
|
k = len(L)
|
|||
|
max, x = L[0], 0
|
|||
|
i = 1
|
|||
|
while i < k :
|
|||
|
if max < L[i]:
|
|||
|
max = L[i]
|
|||
|
x = i
|
|||
|
i = i + 1
|
|||
|
return max, x
|
|||
|
|
|||
|
couple = max_list([4,5,6,9,12,5,10,3,18,5,6,7])
|
|||
|
print ’Max de L est ’, couple[0]
|
|||
|
print ’et se trouve à la position ’, couple[1]
|
|||
|
|
|||
|
Exemple de généricité : ce code fonctionne avec une chaîne de caractères.
|
|||
|
|
|||
|
.. code-block: python
|
|||
|
|
|||
|
couple = max_list(’totovaaumarche’)
|
|||
|
print ’Max de L est ’, couple[0]
|
|||
|
print ’et se trouve à la position ’, couple[1]
|
|||
|
|
|||
|
.. glossary::
|
|||
|
|
|||
|
Matrice
|
|||
|
|
|||
|
Tableaux de dimension multiple, c'est un tableau de tableau
|
|||
|
|
|||
|
.. ifconfig:: exercice
|
|||
|
|
|||
|
**Exercice** : Écrivez un algorithme remplissant un tableau de 6 sur 13, avec des zéros.
|
|||
|
|
|||
|
.. ifconfig:: correction
|
|||
|
|
|||
|
**Correction** :
|
|||
|
|
|||
|
implémentation en python
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
>>> matrice = []
|
|||
|
>>> for i in range(12):
|
|||
|
... matrice.append([0 for i in range(5)])
|
|||
|
...
|
|||
|
>>> from pprint import pprint
|
|||
|
>>> pprint(matrice)
|
|||
|
[[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0],
|
|||
|
[0, 0, 0, 0, 0]]
|
|||
|
>>>
|
|||
|
|
|||
|
Algorithmes de tri
|
|||
|
------------------
|
|||
|
|
|||
|
On désigne par "tri" l'opération consistant à ordonner un ensemble d'éléments en fonction de clés sur lesquelles est définie une relation d'ordre.
|
|||
|
|
|||
|
Les algorithmes de tri ont une grande importance pratique.
|
|||
|
Ils sont fondamentaux dans certains domaines (exemples : map-reduce en database non relationnelle).
|
|||
|
|
|||
|
L'étude du tri est également intéressante en elle-même, c'est un des domaines de l'algorithmique très étudié et connu.
|
|||
|
|
|||
|
Tri par insertion
|
|||
|
~~~~~~~~~~~~~~~~~~
|
|||
|
|
|||
|
Cet algorithme de tri suit de manière naturelle la structure récursive des
|
|||
|
listes. Soit l une liste à trier :
|
|||
|
|
|||
|
- si l est vide alors elle est déjà triée
|
|||
|
- sinon, l est de la forme x::s et on trie récursivement la suite s et on obtient une liste triée s’
|
|||
|
on insert x au bon endroit dans s’ et on obtient une liste triée
|
|||
|
|
|||
|
Description de l'algorithme
|
|||
|
|
|||
|
- la fonction inserer permet d’insérer un élément x dans une liste l
|
|||
|
- si la liste l est triée alors x est inséré au bon endroit
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
# let rec inserer x l =
|
|||
|
match l with
|
|||
|
[] -> [x]
|
|||
|
| y::s -> if x<=y then x::l else y::(inserer x s);;
|
|||
|
val inserer : ’a -> ’a list -> ’a list
|
|||
|
# inserer 5 [3 ;7 ;10];;
|
|||
|
- : int list = [3 ; 5 ; 7 ; 10]
|
|||
|
|
|||
|
Tri rapide
|
|||
|
~~~~~~~~~~~~
|
|||
|
|
|||
|
soit une liste l à trier :
|
|||
|
|
|||
|
- si l est vide alors elle est triée
|
|||
|
- sinon, choisir un élément p de la liste (le premier par exemple)
|
|||
|
nommé le **pivot**
|
|||
|
- partager l en deux listes g et d contenant les autres éléments de l
|
|||
|
qui sont plus petits (resp. plus grands) que la valeur du pivot p
|
|||
|
- trier récursivement g et d, on obtient deux listes g’ et d’ triées
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
:caption: fonction de partage d'une liste
|
|||
|
|
|||
|
#let rec partage p l =
|
|||
|
match l with
|
|||
|
[] -> ([] , [])
|
|||
|
|x::s -> let g,d = partage p s in
|
|||
|
if x<=p then (x::g , d) else (g , x::d) ;;
|
|||
|
val partage : ’a -> ’a list -> ’a list * ’a list = <fun>
|
|||
|
# partage 5 [1 ;9 ;7 ;3 ;2 ;4];;
|
|||
|
- : int list * int list = ([1 ; 3 ; 2 ; 4], [9 ; 7])
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
:caption: algorithme de tri rapide
|
|||
|
|
|||
|
# let rec tri rapide l =
|
|||
|
match l with
|
|||
|
[] -> []
|
|||
|
| p::s -> let g , d = partage p s in
|
|||
|
(tri rapide g)@[p]@(tri rapide d) ;;
|
|||
|
val tri rapide : ’a list -> ’a list = <fun>
|
|||
|
# tri rapide [5 ; 1 ; 9 ; 7 ; 3 ; 2 ; 4];;
|
|||
|
- : int list = [1 ; 2 ; 3 ; 4 ; 5 ; 7 ; 9]
|
|||
|
|
|||
|
|
|||
|
Définition d'un itérateur
|
|||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
>>> l = range(10)
|
|||
|
>>> for i in l:
|
|||
|
... print l[i]
|
|||
|
...
|
|||
|
0
|
|||
|
...
|
|||
|
8
|
|||
|
9
|
|||
|
>>> l.__iter__()
|
|||
|
<listiterator object at 0x7f78bb450410>
|
|||
|
|
|||
|
|
|||
|
Les listes chaînées
|
|||
|
~~~~~~~~~~~~~~~~~~~~
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
typedef struct list{
|
|||
|
int elt ;
|
|||
|
struct list* suivant ;
|
|||
|
} ;
|
|||
|
|
|||
|
|
|||
|
**Outils de manipulation** :
|
|||
|
|
|||
|
- `next()`
|
|||
|
- `pointer()`
|
|||
|
- `insert(l, a)`
|
|||
|
- `remove(a, n)`
|
|||
|
|
|||
|
|
|||
|
Les piles
|
|||
|
----------
|
|||
|
|
|||
|
**manipulation**
|
|||
|
|
|||
|
- `insert()` : insérer un élément à la fin de la pile
|
|||
|
- `dequeue()` : (remove and return) : retirer un élément du haut de la pile
|
|||
|
- FIFO : "first in first out"
|
|||
|
|
|||
|
|
|||
|
Traduction d'une structure de données dans une autre
|
|||
|
-----------------------------------------------------
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
>>> listOfStrings = ['One', 'Two', 'Three']
|
|||
|
>>> strOfStrings = ' '.join(listOfStrings)
|
|||
|
>>> print(strOfStrings)
|
|||
|
One Two Three
|
|||
|
>>>
|
|||
|
>>> # List Of Integers to a String
|
|||
|
... listOfNumbers = [1, 2, 3]
|
|||
|
>>> strOfNumbers = ''.join(str(n) for n in listOfNumbers)
|
|||
|
>>> print(strOfNumbers)
|
|||
|
123
|
|||
|
>>>
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
>>> l = [('host1', '10.1.2.3', '6E:FF:56:A2:AF:18'), ('host3', '10.1.2.5', '6E:FF:56:A2:AF:19')]
|
|||
|
>>> result = []
|
|||
|
>>> for hostname, ip, macaddress in l:
|
|||
|
... result.append(dict(hostname=hostname, ip=ip, macaddress=macaddress))
|
|||
|
...
|
|||
|
>>> result
|
|||
|
[{'hostname': 'host1', 'ip': '10.1.2.3', 'macaddress': '6E:FF:56:A2:AF:18'},
|
|||
|
{'hostname': 'host3', 'ip': '10.1.2.5', 'macaddress': '6E:FF:56:A2:AF:19'}]
|
|||
|
>>>
|
|||
|
|
|||
|
|
|||
|
.. ifconfig:: exercice
|
|||
|
|
|||
|
**Exercice** : Proposer un algorithme de traduction de cette structure de donnée
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
[
|
|||
|
{
|
|||
|
'address': '192.168.0.0',
|
|||
|
'mask': '255.255.255.0',
|
|||
|
'dynamicRanges': [
|
|||
|
{ 'low': '192.168.0.5', 'high': '192.168.0.12', 'only_unknown': True },
|
|||
|
{ 'low': '192.168.0.50', 'high': '192.168.0.55', 'only_unknown': False },
|
|||
|
],
|
|||
|
},
|
|||
|
{
|
|||
|
'address': '192.168.0.0',
|
|||
|
'mask': '255.255.255.0',
|
|||
|
'dynamicRanges': [
|
|||
|
{ 'low': '192.168.0.12', 'high': '192.168.0.45', 'only_unknown': True },
|
|||
|
{ 'low': '192.168.0.8', 'high': '192.168.0.35', 'only_unknown': False },
|
|||
|
],
|
|||
|
},
|
|||
|
{
|
|||
|
'address': '192.168.0.1',
|
|||
|
'mask': '255.255.255.0',
|
|||
|
'dynamicRanges': [
|
|||
|
{ 'low': '192.168.0.5', 'high': '192.168.0.12', 'only_unknown': True },
|
|||
|
{ 'low': '192.168.0.50', 'high': '192.168.0.55', 'only_unknown': False },
|
|||
|
],
|
|||
|
},
|
|||
|
|
|||
|
]
|
|||
|
|
|||
|
En cette structure de données :
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
[
|
|||
|
{
|
|||
|
address: '192.168.0.0',
|
|||
|
mask: '255.255.255.0',
|
|||
|
dynamicRanges: [
|
|||
|
{ low: '192.168.0.5', high: '192.168.0.12', only_unknown: true },
|
|||
|
{ low: '192.168.0.50', high: '192.168.0.55', only_unknown: false },j
|
|||
|
], [
|
|||
|
{ low: '192.168.0.12', high: '192.168.0.45', only_unknown: true },
|
|||
|
{ low: '192.168.0.8', high: '192.168.0.35', only_unknown: false },
|
|||
|
],
|
|||
|
},
|
|||
|
{
|
|||
|
'address': '192.168.0.1',
|
|||
|
'mask': '255.255.255.0',
|
|||
|
'dynamicRanges': [
|
|||
|
{ 'low': '192.168.0.5', 'high': '192.168.0.12', 'only_unknown': True },
|
|||
|
{ 'low': '192.168.0.50', 'high': '192.168.0.55', 'only_unknown': False },
|
|||
|
],
|
|||
|
},
|
|||
|
]
|
|||
|
|
|||
|
.. ifconfig:: correction
|
|||
|
|
|||
|
**Correction** :
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
>>> from pprint import pprint
|
|||
|
pprint(l)
|
|||
|
[{'address': '192.168.0.0',
|
|||
|
'dynamicRanges': [{'high': '192.168.0.12',
|
|||
|
'low': '192.168.0.5',
|
|||
|
'only_unknown': True},
|
|||
|
{'high': '192.168.0.55',
|
|||
|
'low': '192.168.0.50',
|
|||
|
'only_unknown': False}],
|
|||
|
'mask': '255.255.255.0'},
|
|||
|
{'address': '192.168.0.0',
|
|||
|
'dynamicRanges': [{'high': '192.168.0.45',
|
|||
|
'low': '192.168.0.12',
|
|||
|
'only_unknown': True},
|
|||
|
{'high': '192.168.0.35',
|
|||
|
'low': '192.168.0.8',
|
|||
|
'only_unknown': False}],
|
|||
|
'mask': '255.255.255.0'}]
|
|||
|
>>> newdata = []
|
|||
|
>>> for i in l:
|
|||
|
... if i['address'] not in [j['address'] for j in newdata]:
|
|||
|
... newdata.append(i)
|
|||
|
... else:
|
|||
|
... for k in newdata:
|
|||
|
... if k['address'] == i['address']:
|
|||
|
... k['dynamicRanges'].extend(i['dynamicRanges'])
|
|||
|
...
|
|||
|
>>> pprint(newdata)
|
|||
|
[{'address': '192.168.0.0',
|
|||
|
'dynamicRanges': [{'high': '192.168.0.12',
|
|||
|
'low': '192.168.0.5',
|
|||
|
'only_unknown': True},
|
|||
|
{'high': '192.168.0.55',
|
|||
|
'low': '192.168.0.50',
|
|||
|
'only_unknown': False},
|
|||
|
{'high': '192.168.0.45',
|
|||
|
'low': '192.168.0.12',
|
|||
|
'only_unknown': True},
|
|||
|
{'high': '192.168.0.35',
|
|||
|
'low': '192.168.0.8',
|
|||
|
'only_unknown': False}],
|
|||
|
'mask': '255.255.255.0'},
|
|||
|
{'address': '192.168.10.0',
|
|||
|
'dynamicRanges': [{'high': '192.168.0.12',
|
|||
|
'low': '192.168.0.5',
|
|||
|
'only_unknown': True},
|
|||
|
{'high': '192.168.0.55',
|
|||
|
'low': '192.168.0.50',
|
|||
|
'only_unknown': False}],
|
|||
|
'mask': '255.255.255.0'}]
|
|||
|
>>>
|
|||
|
|
|||
|
.. ifconfig:: exercice
|
|||
|
|
|||
|
**Exercice** : Proposer un algorithme qui permette de récupérer la liste
|
|||
|
des adresses IP disponibles
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
{
|
|||
|
"local": {
|
|||
|
"leases": [
|
|||
|
{
|
|||
|
"mac": "02:00:c0:a8:00:66",
|
|||
|
"name": "pcxubuntu",
|
|||
|
"address": "192.168.0.200"
|
|||
|
},
|
|||
|
{
|
|||
|
"mac": "02:00:c0:a8:00:67",
|
|||
|
"name": "pcxubuntu",
|
|||
|
"address": "192.168.0.201"
|
|||
|
},
|
|||
|
{
|
|||
|
"mac": "02:00:c0:a8:00:68",
|
|||
|
"name": "pcxubuntu",
|
|||
|
"address": "192.168.0.202"
|
|||
|
}
|
|||
|
]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.. ifconfig:: correction
|
|||
|
|
|||
|
**Correction** :
|
|||
|
|
|||
|
.. code-block:: python
|
|||
|
|
|||
|
>>> l = {
|
|||
|
... "local": {
|
|||
|
... "leases": [
|
|||
|
... {
|
|||
|
... "mac": "02:00:c0:a8:00:66",
|
|||
|
... "name": "pcxubuntu",
|
|||
|
... "address": "192.168.0.200"
|
|||
|
... },
|
|||
|
... {
|
|||
|
... "mac": "02:00:c0:a8:00:67",
|
|||
|
... "name": "pcxubuntu",
|
|||
|
... "address": "192.168.0.201"
|
|||
|
... },
|
|||
|
... {
|
|||
|
... "mac": "02:00:c0:a8:00:68",
|
|||
|
... "name": "pcxubuntu",
|
|||
|
... "address": "192.168.0.202"
|
|||
|
... }
|
|||
|
... ]
|
|||
|
... }
|
|||
|
... }
|
|||
|
>>> leases = l["local"]["leases"]
|
|||
|
>>> from pprint import pprint
|
|||
|
>>> pprint(leases)
|
|||
|
[{'address': '192.168.0.200', 'mac': '02:00:c0:a8:00:66', 'name': 'pcxubuntu'},
|
|||
|
{'address': '192.168.0.201', 'mac': '02:00:c0:a8:00:67', 'name': 'pcxubuntu'},
|
|||
|
{'address': '192.168.0.202', 'mac': '02:00:c0:a8:00:68', 'name': 'pcxubuntu'}]
|
|||
|
>>> addresses = [lease['address'] for lease in leases]
|
|||
|
>>> addresses
|
|||
|
['192.168.0.200', '192.168.0.201', '192.168.0.202']
|
|||
|
>>>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Structures de données complexes
|
|||
|
-------------------------------
|
|||
|
|
|||
|
Les types produits nommés
|
|||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
|
|||
|
On les appelle enregistrements, dictionnaires ou tables de hachage.
|
|||
|
|
|||
|
::
|
|||
|
|
|||
|
algorithme monAlgorithme
|
|||
|
// déclaration d'un enregistrement
|
|||
|
enregistrement Personne
|
|||
|
chaine nom;
|
|||
|
chaine prenom;
|
|||
|
entier age;
|
|||
|
réel taille;
|
|||
|
finenregistrement
|
|||
|
...
|
|||
|
Personne[50] t;
|
|||
|
début
|
|||
|
// Initialisation
|
|||
|
t[0].nom <- "Duchmol";
|
|||
|
t[0].prenom <- "Robert";
|
|||
|
t[0].age <- 24;
|
|||
|
t[0].taille <- 1.80;
|
|||
|
...
|
|||
|
fin
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
# type adresse = { rue : string ; ville : string ; cp : int};;
|
|||
|
# type fiche = {
|
|||
|
nom : string ;
|
|||
|
prenom : string ;
|
|||
|
adresse : adresse ;
|
|||
|
date naissance : int * int * int ;
|
|||
|
tel fixe : string ;
|
|||
|
portable : string
|
|||
|
};;
|
|||
|
# let v1 = { a = 1 ; b = false ; c = 'r'};;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- les sommes (constructeurs)
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
# type couleur = Pique | Coeur | Carreau | Trefle;;
|
|||
|
# let v = (Pique , Coeur);;
|
|||
|
val v : couleur * couleur = (Pique , Coeur)
|
|||
|
|
|||
|
.. code-block:: ocaml
|
|||
|
|
|||
|
type nombre =
|
|||
|
Ent of int | Reel of float | Cplx of float × float
|
|||
|
Ent, Reel, Cplx sont les constructeurs du type.
|
|||
|
|
|||
|
Autres structures de données complexes
|
|||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
|
|||
|
- arbres
|
|||
|
- graphes
|
|||
|
- dates
|
|||
|
|
|||
|
- le parcours de graphes
|
|||
|
- les calculs de dates
|