834 lines
24 KiB
Plaintext
834 lines
24 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
|
||
|
||
.. important:: la manière naturelle d'implémenter cet algorithme est ici la récursivité
|
||
|
||
.. 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
|
||
|
||
la fonction suivante permet de partager une liste l en deux sous-listes g et
|
||
d contenant les éléments de l plus petits (resp. plus grands) qu’une valeur
|
||
donnée p
|
||
|
||
.. 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]
|
||
|
||
|
||
autre exemple de tri : le tri fusion. Il y en a d'autres.
|
||
|
||
|
||
Le tri en python
|
||
----------------
|
||
|
||
Pour comprendre comment marche le tri en Python, il faut comprendre que presque tout en Python est ordonnable car comparable
|
||
|
||
.. code-block:: python
|
||
|
||
>>> 1 > 0 # les nombres sont comparables
|
||
True
|
||
>>> 1 < 0
|
||
False
|
||
>>> "a" < "b" # les lettres, par ordre alphabetique
|
||
True
|
||
>>> True > False # les booléan (!)
|
||
True
|
||
>>> (1, 2) > (2, 1) # les iterables comparés, élément par élément dans l'ordre
|
||
False
|
||
>>> (1, 2) > [2, 1] # mais ils doivent être du même type
|
||
True
|
||
>>> {1:1} < {1:1, 0:0} # les dictionnaires, par nombre d'éléments
|
||
True
|
||
>>> "a" > 2 # si on mélange des types ça peut vide devenir bizarre
|
||
True
|
||
>>> 1j > 1 # PRESQUE tout est ordonnable
|
||
Traceback (most recent call last):
|
||
File "<ipython-input-11-ed3c013d3df8>", line 1, in <module>
|
||
1j > 1
|
||
TypeError: no ordering relation is defined for complex numbers
|
||
|
||
C’est ce qu’on appelle l’ordre naturel des éléments. Quand il n’y a pas d’ordre naturel évident (et que ce n’est pas une opération explicitement interdite comme avec les complexes),
|
||
Python va comparer l’id (imaginez l’adresse en mémoire)
|
||
|
||
|
||
|
||
.. code-block:: python
|
||
|
||
>>> class PersonnageDeLost(object):
|
||
... pass
|
||
...
|
||
>>> mort1 = PersonnageDeLost()
|
||
>>> mort2 = PersonnageDeLost()
|
||
>>> mort1 < mort2
|
||
True
|
||
>>> id(mort1) # son id est plus petit, donc il est inférieur
|
||
39611408
|
||
>>> id(mort2)
|
||
41720976
|
||
|
||
|
||
.. code-block:: python
|
||
|
||
class PersonnageDeCityHunter(object):
|
||
|
||
def __init__(self, nom, erectopouvoir):
|
||
self.nom = nom
|
||
self.erectopouvoir = erectopouvoir
|
||
|
||
|
||
def __lt__(self, other):
|
||
# on doit retourner un booléan qui confirme ou infirme
|
||
# l'opération "lt" ("lower than", c'est à dire "plus petit que")
|
||
return self.erectopouvoir < other.erectopouvoir
|
||
|
||
def __gt__(self, other):
|
||
# on doit retourner un booléan qui confirme ou infirme
|
||
# l'opération "gt" ("greater than", c'est à dire "plus grand que")
|
||
return self.erectopouvoir > other.erectopouvoir
|
||
|
||
# on peut faire la même chose pour les autres méthodes qui
|
||
# concernent les opérateurs <=, >=, == et !=
|
||
|
||
>>> PersonnageDeCityHunter('Ryo Saeba', 99999) > PersonnageDeCityHunter('Mamouth', 1)
|
||
True
|
||
>>> PersonnageDeCityHunter('Ryo Saeba', 99999) < PersonnageDeCityHunter('Mamouth', 1)
|
||
False
|
||
|
||
Ordonner une liste
|
||
-------------------
|
||
|
||
Avec `sort()` Les éléments sont triés dans leur ordre naturel automatiquement, du plus petit au plus grand:
|
||
|
||
.. code-block:: python
|
||
|
||
>>> l = ['b', 'a', 'c']
|
||
>>> l.sort()
|
||
>>> l
|
||
['a', 'b', 'c']
|
||
>>> l = [(2, 1), (1, 2), (7, 8), (2, 2), (2, 0), (2, 3)]
|
||
>>> l.sort()
|
||
>>> l # ordonne sur le premier élément, puis le second si il y a égalité
|
||
[(1, 2), (2, 0), (2, 1), (2, 2), (2, 3), (7, 8)]
|
||
>>> persos = [PersonnageDeCityHunter('Ryo Saeba', 99999), PersonnageDeCityHunter('Mamouth', 1), PersonnageDeCityHunter('Kaori', 0)]
|
||
>>> persos.sort()
|
||
>>> for perso in persos:
|
||
... print perso.nom
|
||
...
|
||
Kaori
|
||
Mamouth
|
||
Ryo Saeba
|
||
|
||
et inversement:
|
||
|
||
.. code-block:: python
|
||
|
||
>>> l = [1, 7, 3, 8]
|
||
>>> l.sort(reverse=True)
|
||
>>> l
|
||
[8, 7, 3, 1]
|
||
|
||
`sort()` et `sorted()` acceptent toutes les deux les mêmes arguments. Ce que vous apprenez pour l’un vaut pour l’autre. La seul différence est que sort() retourne None et modifie sur place, tandis que sorted() retourne une nouvelle liste. sorted() est un peu moins performant.
|
||
|
||
|
||
.. code-block:: python
|
||
|
||
>>> sorted((1, 7, 3, 8), reverse=True)
|
||
[8, 7, 3, 1]
|
||
|
||
Utilisations de tri personnalisés
|
||
----------------------------------
|
||
|
||
Parfois on a besoin de trier sur quelque chose de plus complexe qu’une lettre ou un chiffre. Par exemple, vous avez des scores dans un dictionnaires. Un dictionnaire n’est pas ordonné. Si vous imprimez un classement, il faut en faire une liste de tuples :
|
||
|
||
::
|
||
|
||
>>> sorted(scores.items())
|
||
[('Cunegonde', 3), ('Gertrude', 4), ('Robert', 2), ('Roger', 1)]
|
||
|
||
C’est là qu’intervient le paramètre key. key est très particulier, c’est un paramètre qui attend qu’on lui passe un callback, donc key attend qu’on lui passe une fonction.
|
||
::
|
||
|
||
>>> def get_score(nom_et_score):
|
||
... return nom_et_score[1] # retourne le 2nd element du tuple
|
||
...
|
||
>>> sorted(scores.items(), key=get_score) # on passe la fonction a key
|
||
[('Roger', 1), ('Robert', 2), ('Cunegonde', 3), ('Gertrude', 4)]
|
||
|
||
|
||
.. ifconfig:: exercice
|
||
|
||
classer des objets voiture en fonction de la puissance du moteur
|
||
|
||
autre exemple: ordonner des objets voitures selon leur coût d’entretien d’abord, et ensuite par coût d’achat.
|
||
|
||
|
||
::
|
||
|
||
class Voiture(object):
|
||
|
||
def __init__(self, cout_entretien, cout_achat):
|
||
self.cout_entretien = cout_entretien
|
||
self.cout_achat = cout_achat
|
||
|
||
def __repr__(self):
|
||
return "<Voiture E-{} / A-{}>".format(self.cout_entretien, self.cout_achat)
|
||
|
||
>>> voitures = [Voiture(10000, 10000), Voiture(50000, 10000), Voiture(10000, 60000)]
|
||
>>> voitures
|
||
[<Voiture E-10000 / A-10000>, <Voiture E-50000 / A-10000>, <Voiture E-10000 / A-60000>]
|
||
>>> def get_entretien_achat(voiture):
|
||
... return (voiture.cout_entretien, voiture.cout_achat)
|
||
...
|
||
>>> sorted(voitures, key=get_entretien_achat)
|
||
[<Voiture E-10000 / A-10000>, <Voiture E-10000 / A-60000>, <Voiture E-50000 / A-10000>]
|
||
|
||
|
||
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 types sommes
|
||
~~~~~~~~~~~~~~~~
|
||
|
||
appelés aussi type construits, ou types algébriques
|
||
|
||
.. code-block:: ocaml
|
||
|
||
# type couleur = Pique | Coeur | Carreau | Trefle;;
|
||
# let v = (Pique , Coeur);;
|
||
val v : couleur * couleur = (Pique , Coeur)
|
||
# let a = Trefle ;;
|
||
val a : couleur = Trefle
|
||
|
||
|
||
.. code-block:: ocaml
|
||
|
||
type nombre =
|
||
Ent of int | Reel of float | Cplx of float × float
|
||
Ent, Reel, Cplx sont les constructeurs du type.
|
||
|
||
Les arbres
|
||
----------
|
||
|
||
Structure de données construite sur un type somme récursif.
|
||
|
||
arbre binaire :
|
||
|
||
.. code-block:: ocaml
|
||
|
||
type arbre = Vide | Noeud of int * arbre * arbre
|
||
let a =
|
||
Noeud(10,
|
||
Noeud(2,Noeud(8,Vide,Vide),Vide),
|
||
Noeud(5,Noeud(11,Vide,Vide),Noeud(3,Vide,Vide)));;
|
||
|
||
arbre binaire polymorphe :
|
||
|
||
|
||
.. code-block:: ocaml
|
||
|
||
type ’a arbre = Vide | Noeud of ’a * ’a arbre * ’a arbre;;
|
||
let b = Noeud(10,Noeud(5,Vide,Vide),Vide);;
|
||
let c = Noeud(’f’,Vide,Noeud(’a’,Vide,Noeud(’g’,Vide,Vide)));;
|
||
|
||
- parcours d’un arbre binaire
|
||
- itérateurs sur un arbre binaire
|
||
- taille d'un arbre
|
||
|
||
arbre n-aire::
|
||
|
||
type ’a arbre = Vide | Noeud of ’a * ’a arbre list;;
|
||
|
||
- transformation d'un arbre en un autre
|
||
- arbre ordonné (arbre de recherche)
|
||
- équilibrage des arbres de recherche
|
||
|
||
|
||
Un arbre binaire est ordonné (ou de recherche) par rapport à une relation
|
||
d’ordre quelconque si :
|
||
|
||
- c’est l’arbre vide (Vide)
|
||
- c’est un arbre non-vide Noeud(x,g,d) et
|
||
|
||
1. les éléments du sous-arbre gauche g sont inférieurs à la racine x
|
||
2. la racine x est inférieure aux éléments du sous-arbre droit d
|
||
3. les sous-arbres g et d sont eux-mêmes ordonnés
|
||
|
||
::
|
||
|
||
let a1 =
|
||
Noeud(5, Noeud(2, Vide, Vide),
|
||
Noeud(20, Noeud(10, Noeud(6, Vide, Vide),
|
||
Noeud(14,Vide, Vide)),
|
||
Noeud(21,Vide,Vide)));;
|
||
|
||
.. image:: _static/AbreOrdonne.png
|
||
|
||
Recherche d'un élément dans un arbre ordonné
|
||
---------------------------------------------
|
||
|
||
La structure ordonnée des arbres binaires de recherche permet d’effectuer
|
||
la recherche d’un élément avec une compléxité en moyenne de O(log n)
|
||
|
||
::
|
||
|
||
let rec recherche elt abr =
|
||
match abr with
|
||
| Vide -> false
|
||
| Noeud (x,_,_) when x = elt -> true
|
||
| Noeud (x,g,_) when elt < x -> recherche elt g
|
||
| Noeud (_,_,d) -> recherche elt d
|
||
;;
|
||
|
||
Autres structures de données complexes
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
- graphes
|
||
- dates
|
||
- le parcours de graphes
|
||
- les calculs de dates
|