From 6016640b0410ef14d3f24a3b7d5e8331a9aceba7 Mon Sep 17 00:00:00 2001 From: Orestis <orestis.malaspinas@pm.me> Date: Mon, 11 Dec 2023 15:32:09 +0100 Subject: [PATCH] maj 2023 --- slides/cours_10.md | 150 --------- slides/cours_11.md | 765 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 765 insertions(+), 150 deletions(-) create mode 100644 slides/cours_11.md diff --git a/slides/cours_10.md b/slides/cours_10.md index 47475fe..dd1ea96 100644 --- a/slides/cours_10.md +++ b/slides/cours_10.md @@ -336,153 +336,3 @@ bool evaluate(char *postfix, double *val) { // init stack -# La liste chaînée et pile (1/6) - -## Structure de données - -* Chaque élément de la liste contient: - 1. une valeur, - 2. un pointeur vers le prochain élément. -* La pile est un pointeur vers le premier élément. - -{width=80%} - -# La liste chaînée et pile (2/6) - -## Une pile-liste-chaînée - -```C -typedef struct _element { - int data; - struct _element *next; -} element; -typedef element* stack; -``` - -## Fonctionnalités? - -. . . - -```C -void stack_create(stack *s); // *s = NULL; -void stack_destroy(stack *s); -void stack_push(stack *s, int val); -void stack_pop(stack *s, int *val); -void stack_peek(stack s, int *val); -bool stack_is_empty(stack s); // reutrn NULL == stack; -``` - -# La liste chaînée et pile (3/6) - -## Empiler? (faire un dessin) - -. . . - -```C - - - - - - - -``` - -## Empiler? (le code ensemble) - -. . . - -```C -void stack_push(stack *s, int val) { - element *elem = malloc(sizeof(*elem)); - elem->data = val; - elem->next = *s; - s = elem; -} -``` - -# La liste chaînée et pile (4/6) - -## Jeter un oeil? (faire un dessin) - -. . . - -```C - - - - - - - -``` - -## Jeter un oeil? (le code ensemble) - -. . . - -```C -void stack_peek(stack s, int *val) { - *val = s->data; -} -``` - -# La liste chaînée et pile (5/6) - -## Dépiler? (faire un dessin) - -. . . - -```C - - - - - - - -``` - -## Dépiler? (le code ensemble) - -. . . - -```C -void stack_pop(stack *s, int *val) { - stack_peek(*s, val); - element *tmp = *s; - *s = (*s)->next; - free(tmp); - return val; -} -``` - -# La liste chaînée et pile (6/6) - -## Détruire? (faire un dessin) - -. . . - -```C - - - - - - - -``` - -## Détruire? (le code ensemble) - -. . . - -```C -void stack_destroy(stack *s) { - while (!stack_is_empty(*s)) { - int val = stack_pop(s); - } -} -``` - - diff --git a/slides/cours_11.md b/slides/cours_11.md new file mode 100644 index 0000000..bdaaf95 --- /dev/null +++ b/slides/cours_11.md @@ -0,0 +1,765 @@ +--- +title: "Files d'attente et listes triées" +date: "2023-12-12" +--- + +# La calculatrice (Rappel) + +## Écrire `2 * 3 * 4 + 2` en notation `postfixe` + +. . . + +```C +2 3 4 * * 2 + = (2 * (3 * 4)) + 2. +``` + +## Quelle structure de données utiliser pour la calculatrice? + +. . . + +La pile! + +# La calculatrice (Rappel 2) + +\footnotesize + +## Quel est l'algorithme pour `infix_to_postfix`? + +. . . + +```C +char *infix_to_postfix(char* infix) { // init and alloc stack and postfix + for (size_t i = 0; i < strlen(infix); ++i) { + if (is_operand(infix[i])) { + // we just add operands in the new postfix string + } else if (infix[i] == '(') { + // we push opening parenthesis into the stack + } else if (infix[i] == ')') { + // we pop everything into the postfix + } else if (is_operator(infix[i])) { + // this is an operator. We add it to the postfix based + // on the priority of what is already in the stack and push it + } + } + // pop all the operators from the s at the end of postfix + // and end the postfix with `\0` + return postfix; +} +``` + + +# La calculatrice (nouveautés) + +## Évaluation d'expression postfixe: algorithme + +* Chaque *opérateur* porte sur les deux opérandes qui le précèdent. +* Le *résultat d'une opération* est un nouvel *opérande* qui est remis au + sommet de la pile. + +## Exemple + +```C +2 3 4 + * 5 - = ? +``` + +* On parcours de gauche à droite: + +```C +Caractère lu Pile opérandes + 2 2 + 3 2, 3 + 4 2, 3, 4 + + 2, (3 + 4) + * 2 * 7 + 5 14, 5 + - 14 - 5 = 9 +``` + +# La calculatrice (nouveautés 2) + +## Évaluation d'expression postfixe: algorithme + +1. La valeur d'un opérande est *toujours* empilée. +2. L'opérateur s'applique *toujours* au 2 opérandes au sommet. +3. Le résultat est remis au sommet. + +## Exercice: écrire l'algorithme en C (et poster sur matrix) + +. . . + +```C +bool evaluate(char *postfix, double *val) { // init stack + for (size_t i = 0; i < strlen(postfix); ++i) { + if (is_operand(postfix[i])) { + stack_push(&s, postfix[i]); + } else if (is_operator(postfix[i])) { + double rhs = stack_pop(&s); + double lhs = stack_pop(&s); + stack_push(&s, op(postfix[i], lhs, rhs)); + } + } + return stack_pop(&s); +} +``` + + + +# La liste chaînée et pile (1/6) + +## Structure de données + +* Chaque élément de la liste contient: + 1. une valeur, + 2. un pointeur vers le prochain élément. +* La pile est un pointeur vers le premier élément. + +{width=80%} + +# La liste chaînée et pile (2/6) + +## Une pile-liste-chaînée + +```C +typedef struct _element { + int data; + struct _element *next; +} element; +typedef element* stack; +``` + +## Fonctionnalités? + +. . . + +```C +void stack_create(stack *s); // *s = NULL; +void stack_destroy(stack *s); +void stack_push(stack *s, int val); +void stack_pop(stack *s, int *val); +void stack_peek(stack s, int *val); +bool stack_is_empty(stack s); // reutrn NULL == stack; +``` + +# La liste chaînée et pile (3/6) + +## Empiler? (faire un dessin) + +. . . + +```C + + + + + + + +``` + +## Empiler? (le code ensemble) + +. . . + +```C +void stack_push(stack *s, int val) { + element *elem = malloc(sizeof(*elem)); + elem->data = val; + elem->next = *s; + s = elem; +} +``` + +# La liste chaînée et pile (4/6) + +## Jeter un oeil? (faire un dessin) + +. . . + +```C + + + + + + + +``` + +## Jeter un oeil? (le code ensemble) + +. . . + +```C +void stack_peek(stack s, int *val) { + *val = s->data; +} +``` + +# La liste chaînée et pile (5/6) + +## Dépiler? (faire un dessin) + +. . . + +```C + + + + + + + +``` + +## Dépiler? (le code ensemble) + +. . . + +```C +void stack_pop(stack *s, int *val) { + stack_peek(*s, val); + element *tmp = *s; + *s = (*s)->next; + free(tmp); + return val; +} +``` + +# La liste chaînée et pile (6/6) + +## Détruire? (faire un dessin) + +. . . + +```C + + + + + + + +``` + +## Détruire? (le code ensemble) + +. . . + +```C +void stack_destroy(stack *s) { + while (!stack_is_empty(*s)) { + int val = stack_pop(s); + } +} +``` + + +# La file d'attente (1/N) + +* Structure de données abstraite permettant le stockage d'éléments. +* *FIFO*: First In First Out, ou première entrée première sortie. +* Analogue de la vie "réelle"": + * File à un guichet, + * Serveur d'impressions, + * Mémoire tampon, ... + +## Fonctionnalités + + . . . + +* Enfiler: ajouter un élément à la fin de la file. +* Défiler: extraire un élément au devant de la file. +* Tester si la file est vide. + +. . . + +* Lire l'élément de la fin de la file. +* Lire l'élément du devant de la file. +* Créer une liste vide. +* Détruire une liste vide. + +# La file d'attente (2/N) + +\footnotesize + +## Implémentation possible + +* La structure file, contient un pointeur vers la tête et un vers le début de la file. +* Entre les deux, les éléments sont stockés dans une liste chaînée. + +{width=80%} + +## Structure de données en C? + +. . . + +```C +typedef struct _element { // Elément de liste + int data; + struct _element* next; +} element; +typedef struct _queue { // File d'attente: + element* head; // tête de file d'attente + element* tail; // queue de file d'attente +} queue; +``` + +# Fonctionnalités d'une file d'attente + +## Creation et consultations + +. . . + +```C +void queue_init(queue *fa); // head = tail = NULL +bool queue_is_empty(queue fa); // fa.head == fa.tail == NULL +int queue_tail(queue fa); // return fa.head->data +int queue_head(queue fa); // return fa.tail->data +``` + +## Manipulations et destruction + +. . . + +```C +void queue_enqueue(queue *fa, int val); +// adds an element before the tail +int queue_dequeue(queue *fa); +// removes the head and returns stored value +void queue_destroy(queue *fa); +// dequeues everything into oblivion +``` + +# Enfilage + +## Deux cas différents: + +1. La file est vide (faire un dessin): + +. . . + +{width=40%} + +2. La file n'est pas vide (faire un dessin): + +. . . + +{width=70%} + +# Enfilage + +## Live (implémentation) + +. . . + +```C +void queue_enqueue(queue *fa, int val) { + element* elmt = malloc(sizeof(*elmt)); + elmt->data = val; + elmt->next = NULL; + if (queue_is_empty(*fa)) { + fa->head = elmt; + fa->tail = elmt; + } else { + fa->tail->next = elmt; + fa->tail = elmt; + } +} +``` + +# Défilage + +## Trois cas différents + +1. La file a plus d'un élément (faire un dessin): + +. . . + +{width=80%} + +2. La file un seul élément (faire un dessin): + +. . . + +{width=25%} + + +3. La file est vide (problème) + +# Défilage + +## Live (implémentation) + +. . . + +```C +int queue_dequeue(queue *fa) { + element* elmt = fa->head; + int val = elmt->data; + fa->head = fa->head->next; + free(elmt); + if (NULL == fa->head) { + fa->tail = NULL; + } + return val; +} +``` + +. . . + +## Problème avec cette implémentation? + +# Destruction + +## Comment on faire la désallocation? + +. . . + +On défile jusqu'à ce que la file soit vide! + +# Complexité + +## Quelle sont les complexité de: + +* Enfiler? + +. . . + +* Défiler? + +. . . + +* Détruire? + +. . . + +* Est vide? + + +# Implémentation alternative + +## Comment implémenter la file autrement? + +. . . + +* Données stockées dans un tableau; +* Tableau de taille connue à la compilation ou pas (réallouable); +* `tail` seraient les indices du tableau; +* `capacity` seraient la capacité maximale; +* On *enfile* "au bout" du tableau, au défile au début (indice `0`). + +. . . + +## Structure de données + +```C +typedef struct _queue { + int *data; + int tail, capacity; +} queue; +``` + +# File basée sur un tableau + +* Initialisation? + +. . . + +```C + + + + +``` + +* Est vide? + +. . . + +```C + + + + +``` + + +* Enfiler? + +. . . + +```C + + + + +``` + +* Défiler? + +. . . + +```C + + + + +``` + +# Complexité + +## Quelle sont les complexités de: + +* Initialisation? + +. . . + +```C + + + + +``` + +* Est vide? + +. . . + +```C + +``` + + +* Enfiler? + +. . . + +```C + + + + +``` + +* Défiler? + +. . . + +```C + + + + +``` + +# Une file plus efficace + +## Comment faire une file plus efficace? + +* Où est-ce que ça coince? + +. . . + +* Défiler est particulièrement lent $\mathcal{O}(N)$. + +## Solution? + +. . . + +* Utiliser un indice séparé pour `head`. + +```C +typedef struct _queue { + int *data; + int head, tail, capacity; +} queue; +``` + +# Une file plus efficace (implémentation) + +## Enfilage + +\footnotesize + +```C +void queue_enqueue(queue *fa, int val) { + if ((fa->head == 0 && fa->tail == fa->capacity-1) || + (fa->tail == (fa->head-1) % (fa->capacity-1))) { + return; // queue is full + } + if (fa->head == -1) { // queue was empty + fa->head = fa->tail = 0; + fa->data[fa->tail] = val; + } else if (fa->tail == fa->capacity-1 && fa->head != 0) { + // the tail reached the end of the array + fa->tail = 0; + fa->data[fa->tail] = val; + } else { + // nothing particular + fa->tail += 1; + fa->data[fa->tail] = val; + } +} +``` + +# Une file plus efficace (implémentation) + +## Défilage + +```C +void queue_dequeue(queue *fa, int *val) { + if (queue_is_empty(*fa)) { + return; // queue is empty + } + *val = fa->data[fa->head]; + if (fa->head == fa->tail) { // that was the last element + fa->head = fa->tail = -1; + } else if (fa->head == fa->capacity-1) { + fa->head = 0; + } else { + fa->head += 1; + } +} +``` + + +# Les listes triées + +Une liste chaînée triée est: + +* une liste chaînée +* dont les éléments sont insérés dans l'ordre. + + + +. . . + +* L'insertion est faite telle que l'ordre est maintenu. + +## Quelle structure de données? + +```C + + + + + +``` + +# Les listes triées + +## Quel but? + +* Permet de retrouver rapidement un élément. +* Utile pour la recherche de plus court chemin dans des graphes. +* Ordonnancement de processus par degré de priorité. + +## Comment? + +* Les implémentations les plus efficaces se basent sur les tableaux. +* Possibles aussi avec des listes chaînées. + +# Les listes triées + +\footnotesize + +## Quelle structure de données dans notre cas? + + +Une liste chaînée bien sûr (oui c'est pour vous entraîner)! + +```C +typedef struct _element { // chaque élément + int data; + struct _element *next; +} element; +typedef element* sorted_list; // la liste +``` + +## Fonctionnalités + +```C +// insertion de val +sorted_list sorted_list_push(sorted_list list, int val); +// la liste est-elle vide? +bool is_empty(sorted_list list); // list == NULL +// extraction de val (il disparaît) +sorted_list sorted_list_extract(sorted_list list, int val); + // rechercher un élément et le retourner +element* sorted_list_search(sorted_list list, int val); +``` + +# L'insertion + +## Trois cas + +1. La liste est vide. + +. . . + +{width=30%} + +. . . + +```C +sorted_list sorted_list_push(sorted_list list, int val) { + if (sorted_list_is_empty(list)) { + list = malloc(sizeof(*list)); + list->data = val; + list->next = NULL; + return list; + } +} +``` + +# L'insertion + +2. L'insertion se fait en première position. + +. . . + +{width=80%} + +. . . + +```C +sorted_list sorted_list_push(sorted_list list, int val) { + if (list->data >= val) { + element *tmp = malloc(sizeof(*tmp)); + tmp->data = val; + tmp->next = list; + list = tmp; + return list; + } +} +``` + +# L'insertion + +3. L'insertion se fait sur une autre position que la première. + +. . . + +{width=70%} + +. . . + +\footnotesize + +```C +sorted_list sorted_list_push(sorted_list list, int val) { + element *tmp = malloc(sizeof(*tmp)); + tmp->data = val; + element *crt = list; + while (NULL != crt->next && val > crt->next->data) { + crt = crt->next; + } + tmp->next = crt->next; + crt->next = tmp; + return list; +} +``` + + -- GitLab