diff --git a/README.md b/README.md index f255107..1fb8812 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,13 @@
Réseau et Web

Architectures matérielles et systèmes d'exploitation

Langages et programmation
-
Algorithmique
+
Algorithmique
+ ## Progression | Semestre | Objectifs | Séquence 1 | Séquence 2 | diff --git a/algorithmes/PARCOURS.md b/algorithmes/PARCOURS.md new file mode 100644 index 0000000..e12bf44 --- /dev/null +++ b/algorithmes/PARCOURS.md @@ -0,0 +1,71 @@ +# Parcours séquentiel d'un tableau + +> Quelques exemples d'algorithmes qui nécessitent un parcours simple d'un tableau. +> +> On utilisera ici une seule boucle **for** : la complexité est donc **linéaire**. + +On supposera que tous les tableaux traités ici contiennent des nombres. + +### Exemples + +#### Recherche d'occurence + +Si on souhaite savoir si un élément nommé *e* en particulier se trouve dans un tableau *tab* : + +```python +def recherche(tab,e): + occurrence = False + for i in range (len(tab)): + if tab[i] == b: + occurrence = True + return occurrence + return occurrence +``` + +***Complexité :*** + +Le programme effectue n+1 affectation : + +- La première, avant la boucle. +- Les n suivantes, selon la taille du tableau + +Le coût est donc *linéaire* : proportionnel à n, il dépend donc de la taille du tableau, ***O(n)*** + +------------- + +#### Recherche d'un extremum (maximum ou minimum) + +Si on souhaite trouver le plus grand élément d'un tableau *tab* : + +```python +def recherche_max(tab): + max = tab[0] + for i in range (len(tab)): + if tab[i] > max: + max = tab[i] + return max +``` + +Complexité ? + +-------- + +#### Calcul d'une moyenne + +```python +def moyenne(tab): + m = 0 + for i in range(len(tab)): + m = m + tab[i] + moyenne = m // len (tab) + return moyenne +``` + +Complexité ? + +----------- + +#### Autres exemples simples : + +- Vérifier si une un tableau est rangé par ordre croissant ou décroissant +- Chercher un mot de plus de n lettres dans une liste de mots... \ No newline at end of file diff --git a/algorithmes/PROPRIETES.md b/algorithmes/PROPRIETES.md new file mode 100644 index 0000000..f6af849 --- /dev/null +++ b/algorithmes/PROPRIETES.md @@ -0,0 +1,49 @@ +## Propriétés et caractéristiques d'un algorithme + +Il est essentiel, pour un bon algorithme, de posséder certaines propriétés : + +- La **terminaison** : Votre algo doit donner un résultat en un **nombre fini d'étapes** et donc ne surtout pas rester coincé dans une boucle. + +- La **validation** : Votre algorithme doit amener au résultat attendu, peu importe la situation. + +En plus de ces deux propriétés, on peut également citer ***le coût*** ou ***complexité*** : + +- en **temps** : le nombre d'opérations nécessaires à son exécution +- en **espace** : la quantité d'espace mémoire nécessaire à son exécution + +Ici, nous ne nous intéresserons uniquement qu'au **coût en temps, la complexité temporelle.** + +### Complexité d'un algorithme + +On ne va pas vous demander de chronométrer l'exécution, mais plutôt de trouver **l'ordre de grandeur**. + +Il s'agit de différencier les algorithmes selon un type de complexité : on va les grouper par *familles*. + +Soit *n* la taille des données d'entrée, on notera la complexité d'un algorithme en fonction de *n* : +$$ +O(f(n)) +$$ + +> On note O pour ***Ordre de grandeur*** + +| Complexité | Notation | Temps pour n = 10 | Temps pour n = 1000 | Temps pour n = 106 | +| ------------- | ---------------- | ----------------- | ------------------- | ----------------------------- | +| Constante | O(1) | 10 ns | 10 ns | 10 ns | +| Logarithmique | O(log(n)) | 10 ns | 30 ns | 60 ns | +| Linéaire | O(n) | 100 ns | 10 μs | 10 ms | +| Quandratique | O(n2) | 1 μs | 10 ms | 2,8 heures | + + + +``` +Pour comprendre la notion de complexité, utilisons l'exemple de tri de tableau : il s'agit d'un des cas les plus récurrents d'utilisation d'un algorithme. On a un tableau, contenant des élèments que l'on devra trier dans un ordre précis. + +Si un algorithme met un temps donné pour trier un tableau de taille n, combien de temps lui faudra t-il pour trier un tableau 10 ou 100 fois plus grand ? +``` + +- La **complexité d'un algorithme** est une mesure du temps requis par l'algorithme pour accomplir sa tâche, en fonction de la taille des données à traiter. +- On dira d'un problème qu'il est aussi complexe que le meilleur algorithme connu pour le résoudre. +- Si la **complexité** est **constante**, alors le temps d'execution sera sensiblement toujours le même, peu importe la taille du tableau traité. +- Si elle est **logarithmique**, alors le temps d'execution augmente très faiblement quand le paramètre croit. +- **Complexité** **linéaire** : le nombre d'étapes à effectuer va varier en proportion directe de la taille de l'échantillon à traiter : si l'échantillon croît par un facteur de 10000, la complexité sera accrue elle aussi par un facteur de 10000. + diff --git a/algorithmes/TRIS.md b/algorithmes/TRIS.md new file mode 100644 index 0000000..18c66e0 --- /dev/null +++ b/algorithmes/TRIS.md @@ -0,0 +1,191 @@ +# Algorithmes de tri + +> En python, on dispose de plusieurs algorithmes permettant de trier des tableaux et relativement faciles à implémenter. + +Il existe un problème récurrent en informatique : le tri de données. Comme vu précédemment, on travaille souvent sur de grands nombres de données, et il faut bien trier tout ça à un moment pour plusieurs raisons : + +- espace +- temps +- argents +- facilité d'utilisation + +En python, deux méthodes permettent de trier les tableaux simplement par ordre croissant : + +- sort() + +```python +>>> l = [3, 2, 1] +>>> l.sort() +>>> l +[1, 2, 3] +``` + +La méthode *sort* va modifier la liste elle-même (et renvoie *None* pour éviter les confusions). + +Ne fonctionne qu'avec le type *list*. + +- sorted () + +```python +sorted([3, 2, 1]) +[1, 2, 3] +``` + +Renvoie une nouvelle liste triée. + +Fonctionne avec n'importe quel type *itérable*. + +## Tri par insertion + +### Présentation + +Le tri par insertion est efficace dans le cas de tableaux de petite taille ou de tableaux triés en partie. + +![insertion](assets/insertion.gif) + +Le principe est ici de parcourir tous les éléments : + +- Chaque élément est inséré à sa place dans les éléments déjà triés qui le précèdent +- Il n'est pas nécessaire de faire une copie de la liste +- Deux éléments égaux resteront toujours dans le même ordre +- Les éléments peuvent être fournis au fur et à mesure + + + +Supposons un tableau suivant : + +```python +tab = [9,8,5,4,7,6] +``` + +```python +procédure tri_insertion(tableau T) + pour i de 1 à taille(T) - 1 + + # mémoriser T[i] dans x + x ← T[i] + + # décaler les éléments T[0]..T[i-1] qui sont plus grands que x, en partant de T[i-1] + j ← i + tant que j > 0 et T[j - 1] > x + T[j] ← T[j - 1] + j ← j - 1 + + # placer x dans le "trou" laissé par le décalage + T[j] ← x +``` + + + +Le tri par insertion est *naturel* dans l'esprit : on parcourt le tableau de la gauche vers la droite et pour chaque élément, on le classe dans la partie du tableau situé sur sa gauche. + +### Preuve de correction + +| Valeur de i | Tableau avant la boucle | Valeur de la clé | Tableau en fin de boucle | +| ----------- | ----------------------- | ---------------- | ------------------------ | +| 1 | [9,8,5,4,7,6] | 8 | [**8,9**,5,4,7,6] | +| 2 | [8,9,5,4,7,6] | 5 | [**5,8,9**,4,7,6] | +| 3 | [5,8,9,4,7,6] | 4 | [**4,5,8,9**,7,6] | +| 4 | [4,5,8,9,7,6] | 7 | [**4,5,7,8,9**,6] | +| 5 | [4,5,7,8,9,6] | 6 | [**4,5,6,7,8,9**] | + +> À la fin de chaque boucle, le tableau est trié de la case n°0 à la case n°i + +Une preuve de correction de l'algorithme est la propriété *p(i)* : "le tableau est trié jusqu'à la case n°i" : cette propriété est vraie **avant** et **après** chaque tour de boucle : c'est ce qu'on appelle ***Invariant de boucle*** + +À l'inverse, le **variant** de boucle est une expression dans la valeur varie à chaque tour de boucle et qui doit justement permettre de mettre fin à la-dite boucle : le variant d'un algorithme de tri sera alors la taile de la liste restante à trier. + +### Complexité + +Dans le pire des cas (éléments classés par ordre décroissant), la boucle while effectue 2n opérations : chaque tour de boucle for compte pour 2n + 3, répérées n - 1 fois. On a donc (n - 1) (2n + 3). + +L'ordre de grandeur est donc de n2 ou O(n2 ) : on aura donc un coût **quadratique** dans le pire des cas. + +Par contre si la liste est déjà triée, le coût est **linéaire**. + +[Une excellente méthode pour comprendre](https://www.youtube.com/watch?v=ROalU379l3U) + +----------------- + +## Tri par selection + +> Contrairement au tri par insertion, le tri par selection a pour avantage de déplacer moins de valeurs. + +![selection](assets/selection.gif) + +Principe: + +- On recherche du plus petit élément et on le met à sa place (indice 0 donc) +- Puis on recherche le deuxième plus petit et on le met à l'indice 1 +- Et on continue comme cela avec tous les éléments +- Il n'est pas necessaire de faire une copie de la liste +- Deux éléments égaux ne resteront pas forcément à la même place + +Supposons le tableau suivant : + +```python +tab = [9,8,5,4,7,6] +``` + +```python +procédure tri_selection(tableau t) + n ← longueur(t) + pour i de 0 à n - 2 + min ← i + pour j de i + 1 à n - 1 + si t[j] < t[min], alors min ← j + fin pour + si min ≠ i, alors échanger t[i] et t[min] + fin pour +fin procédure +``` + +> En python, pour échanger des cases, on peut écrire : +> +> ```python +> tab[i], tab[mini] = tab[mini], tab [i] +> ``` + + + +### Preuve de correction + +| Valeur de i | Tableau avant la boucle | Tableau après la boucle | +| ----------- | ----------------------- | ----------------------- | +| 0 | [9,8,5,4,7,6] | [**4**,8,5,9,7,6] | +| 1 | [4,8,5,9,7,6] | [**4,5**,8,9,7,6] | +| 2 | [4,5,8,9,7,6] | [**4,5,6**,9,7,8] | +| 3 | [4,5,6,9,7,8] | [**4,5,6,7**,9,8] | +| 4 | [4,5,6,7,9,8] | [**4,5,6,7,8,9**] | + +Il faut montrer l'invariant : à la fin du tour i de la boucle for, les cases tab[0] à tab[i] incluses sont à leur place définitives. + +### Complexité + +- La première boucle for tourne pour i variant de 0 à n-2. Elle s'effectue donc n-2 fois. +- La seconde boucle s'effectue n-1 - i fois. +- On a donc n*n en ordre de grandeur, donc la complexité est de type O(n2) : **quadratique** + +[Et donc la méthode pour mieux comprendre](https://www.youtube.com/watch?v=Ns4TPTC8whw) + +----- + + + +#### Exercices + +- Ecrire les fonctions + +```python +tri_selection (tab) +``` + +et + +```python +tri_insertion(tab) +``` + +qui permettent de trier différement les tableaux donnés en entrée. + +Expliquer pourquoi ces algorithmes sont en O(n2 ) avec vos propres mots. \ No newline at end of file diff --git a/algorithmes/assets/insertion.gif b/algorithmes/assets/insertion.gif new file mode 100644 index 0000000..4e34513 Binary files /dev/null and b/algorithmes/assets/insertion.gif differ diff --git a/algorithmes/assets/selection.gif b/algorithmes/assets/selection.gif new file mode 100644 index 0000000..b441c4e Binary files /dev/null and b/algorithmes/assets/selection.gif differ diff --git a/données_en_table/Exercices/CORRECTION.md b/données_en_table/Exercices/CORRECTION.md new file mode 100644 index 0000000..ba179e5 --- /dev/null +++ b/données_en_table/Exercices/CORRECTION.md @@ -0,0 +1,190 @@ +## Exercices + + + +### 1. Manipulation de fichiers CSV + +- On peut représenter un enregistrement par un dictionnaire. +- Une virgule (CSV : Comma Separated Values - Valeurs séparées par une virgule). Néanmoins, le format CSV autorise d'autres séparateurs. +- La table étant une liste de dictionnaires, on obtient donc le premier élèment de la liste, c'est à dire un dictionnaire, donc une ligne de la table. + + + + +---------- + + + +### 2. Opérations sur les tables + + + +- Pour selectionner des colonnes selon un critère donné, on va utiliser la fonction projection. + +```python +def projection(table, liste_attributs): + return [{clé:ligne[clé] for clé in ligne if clé in liste_attributs} for ligne in table] +``` + +- La fonction *select* ici va selectionner les lignes dont une des valeurs vaut au moins 19. + + +- Il y a deux (2) noms qui sont communs aux tables : on aura donc deux (2) lignes. De plus, la table U rajoute ses deux (2) colonnes (âge, mail) au quatre de la table T : on aura donc 6 (six) colonnes. + + + +--------- + + + +### 3. Determiner des fonctions basiques + +- Puisqu'il s'agit de compter le nombre de lignes, donc d'enregistrement, on peut donc utiliser la fonction *len* pour obtenir la longueur de la liste de dictionnaires. + +```python +def cardinalité(table): + return len(table) +``` + + + +- La liste des attributs d'une table = + + + +------------- + + + +### 4. Reconnaître une fonction + +Quel est le principe de la fonction suivante : + +```python +def mystère(t, cs): + t_p = [] + for l in t : + nvlle_l = {} + for c in l: + if c in cs: + nvelle_l[c] = l[c] + t_p.append(nvelle_l) + return t_p +``` + + + +### 5. Tester la cohérence d'une table + +- Determiner une fonction *coherence*(table) qui teste si chaque ligne a le même ensemble d'attributs. +- Determiner une fonction *doublons*(table, attribut) qui vérifie si un attribut de référerence apparaît deux fois avec la même valeur dans une table. + +### 6. Lier tableur, fichier CSV et liste de dictionnaires + +On dispose d'une liste de dictionnaires suivante : + +```python +PlanningTwitch =[{'NomStream' : 'AntoineDaniel', 'Genre' : 'M', 'Jeu' : 'Fall_Guys','Numéro' : '1'},{'NomStream' : 'MV', 'Genre' : 'M', 'Jeu' : 'Isaac','Numéro' : '2'}, {'NomStream' : 'AngleDroit', 'Genre' : 'F', 'Jeu' : 'Fall_Guys','Numéro' : '3'}, {'NomStream' : 'BagheraJones', 'Genre' : 'F', 'Jeu' : 'Fall_Guys','Numéro' : '4'}] +``` + +- On travaille avec le tableur LibreOffice Calc de la suite LibreOffice qui produit des fichiers au format ont (alors qu'Excel de la suite Microsoft Office produit des fichiers au format xlsx). Quelle est la première ligne de la feuille de calcul obtenue dans un tableau à partir de cette liste ? +- Quelle commande lancer pour obtenir le fichier CSV correspondant ? +- Quelle est la deuxième ligne du fichier CSV correspondant ? +- Quelle valeur trouve t-on à la cellule C8 de la feuille correspondante ? +- Par quelle commande obtient-on cette valeur ? +- Une erreur de saisie a lieu : MV joue à worms en fait. Quelle commande permet de modifier le fichier correpondant du tableur ? + +### 7. Ajouter une ligne ou une colonne + +On dispose de la table suivante au format CSV, dans le repertoire courant sous le nom ***'./Groupe1.csv'*** + +| Prénom | Math | Anglais | NSI | +| -------- | ---- | ------- | ---- | +| Joey | 16 | 17 | 18 | +| Chandler | 19 | 15 | 17 | +| Ross | 14 | 19 | 13 | + +- Comment obtenir la liste de dictionnaires correspondante en utilisant une fonction déjà vue ? +- Ajouter les notes de l'élève Rachel qui a eu 17 en Maths, 18 en NSI et 19 en anglais. +- On voudrait ajouter une colonne contenant les moyennes de chaque élève afin d'obtenir le tableau suivant : + +| Prénom | Math | Anglais | NSI | Moyenne | +| -------- | ---- | ------- | ---- | ------- | +| Joey | 16 | 17 | 18 | 17 | +| Chandler | 19 | 15 | 17 | 17 | +| Ross | 14 | 19 | 13 | 15,3 | +| Rachel | 17 | 19 | 18 | 18 | + +On doit envoyer une nouvelle table qui ne modifie pas la table d'origine. Pour effectuer une copie d'une liste d'objets complexes (ici une liste de dictionnaires), on peut utiliser la fonction *deepcopy* de la bibliothèque coup. La fonction à créer pourra donc avoir la structure suivante qu'il faudra compléter : + +```python +from copy import deepcopy +def ajouter_moyenne(table): + nvelle_table = deepcopy(table) + pass + + return nvelle_table +``` + +Pour obtenir l'affichage d'un nombre flottant arrondi à 2 chiffres derrière la virgule, on peut utiliser la méthode *format* + +Par exemple : + +```python +>> '{:.2f}'.format(314/100) #indique un flottant avec 2 chiffres après la virgule +'3,14' +``` + +Ajouter une ligne qui contient les moyennes par matières. + +Cela devrait donner un tableau du genre : + +| Prénom | Math | Anglais | NSI | +| -------- | ---- | ------- | ---- | +| Joey | 16 | 17 | 18 | +| Chandler | 19 | 15 | 17 | +| Ross | 14 | 19 | 13 | +| Rachel | 17 | 19 | 18 | +| Moyenne | 16,5 | 17,5 | 16,5 | + + + +### 8. Selectionner, trier, joindre + +On dispose de la table Hero suivante + +| NumHero | NomHero | VIlleHero | +| ------- | --------- | --------- | +| 0 | Sangoku | Kyoto | +| 1 | Naruto | Konoha | +| 2 | Luffy | Fuchsia | +| 3 | Ryo Saeba | Tokyo | +| 4 | Saitama | VIlle Z | +| 5 | Onizuka | Tokyo | + +Ainsi que celle- ci : + +| NumHero | NomHero | Arme | +| ------- | --------- | ----------------- | +| 0 | Sangoku | Ki | +| 1 | Naruto | Chakra | +| 2 | Luffy | Corps | +| 3 | Ryo Saeba | Magnum | +| 4 | Saitama | Point | +| 5 | Onizuka | Tout est une arme | + + + +- Renvoyer HeroTokyo, une table extraite de Hero ne contenant que les lignes dont l'attribut VilleHero vaut "Tokyo" + +- Renvoyer HeroAlpha, une table extraite de Hero triée selon l'ordre alphabétique du nom des héros. + +- Renvoyer HeroComplet, une table contenant le nom, la ville ainsi que l'arme favorite des héros. + +- Renvoyer HeroVille, la table contenant le numéro ainsi que la ville des héros. + +- Renvoyer HeroImpair, la table contenant le nom et la ville des hero ne venant pas de Tokyo, et dont le numéro est impair. + + + + \ No newline at end of file diff --git a/données_en_table/import_csv.py b/données_en_table/import_csv.py new file mode 100644 index 0000000..336ed8b --- /dev/null +++ b/données_en_table/import_csv.py @@ -0,0 +1,11 @@ +import csv + +def import_csv(fichier): + lecteur = csv.DictReader(open(fichier + '.csv', 'r')) + return [dict(ligne) for ligne in lecteur ] + + +def select(table, critere): + def test(ligne): + return eval(critere) + return [ligne for ligne in table if test(ligne)]