Skip to content
Snippets Groups Projects
Verified Commit 9e61737f authored by orestis.malaspin's avatar orestis.malaspin
Browse files

added cours 11

parent b68186a1
Branches
No related tags found
No related merge requests found
---
title: "Piles et files d'attente"
title: "Piles"
date: "2022-12-14"
patat:
eval:
......@@ -399,153 +399,4 @@ void stack_destroy(stack *s) {
}
```
# La file d'attente (1/2)
* 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/2)
## 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 (comme une
pile).
![Illustration d'une file
d'attente.](figs/fig_queue_representation.png)
## Structure de données en C?
. . .
```C
txpedef 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):
. . .
![Insertion dans une file d'attente vide.](./figs/fig_empty_queue_insert.png){width=40%}
2. La file n'est pas vide (faire un dessin):
. . .
![Insertion dans une file d'attente non-vide.](./figs/fig_non_empty_queue_insert.png){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):
. . .
![Extraction d'une file d'attente](./figs/fig_queue_extract.png){width=80%}
2. La file un seul élément (faire un dessin):
. . .
![Extraction d'une file d'attente de longueur 1.](./figs/fig_queue_extract_one.svg){width=25%}
3. La file est vide (problème)
# Défilage
## Live (implémentation)
. . .
```C
int queue_dequeue(queue *fa) {
elmt = fa->head;
int val = elmt->data;
fa->head = fa->head->next;
free(elmt);
if (NULL == fa->head) {
fa->tail = NULL;
}
return val;
}
```
---
title: "Files d'attente et listes triées"
date: "2022-12-21"
---
# 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.
![Illustration d'une file d'attente.](figs/fig_queue_representation.png){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):
. . .
![Insertion dans une file d'attente vide.](./figs/fig_empty_queue_insert.png){width=40%}
2. La file n'est pas vide (faire un dessin):
. . .
![Insertion dans une file d'attente non-vide.](./figs/fig_non_empty_queue_insert.png){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):
. . .
![Extraction d'une file d'attente](./figs/fig_queue_extract.png){width=80%}
2. La file un seul élément (faire un dessin):
. . .
![Extraction d'une file d'attente de longueur 1.](./figs/fig_queue_extract_one.svg){width=25%}
3. La file est vide (problème)
# Défilage
## Live (implémentation)
. . .
```C
int queue_dequeue(queue *fa) {
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.
![Exemple de liste triée.](./figs/sorted_list_example.svg)
. . .
* 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
## 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.
. . .
![Insertion dans une liste vide, `list == NULL`.](figs/sorted_list_insert_one.svg){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.
. . .
![Insertion en tête de liste, `list->data >=
val`.](figs/sorted_list_insert_first.svg){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.
. . .
![Insertion sur une autre position, list->data <
val.](figs/sorted_list_insert_any.svg){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;
}
```
# L'extraction
## Trois cas
1. L'élément à extraire n'est **pas** le premier élément de la liste
. . .
![Extraction d'un élément qui n'est pas le premier.](figs/sorted_list_extract_any.svg){width=70%}
. . .
\footnotesize
```C
sorted_list sorted_list_extract(sorted_list list, int val) {
element *prec = *crt = list; // needed to glue elements together
while (NULL != crt && val > crt->data) {
prec = crt;
crt = crt->next;
}
if (NULL != crt && prec != crt && crt->data == val) { // glue things together
prec->next = crt->next;
free(crt);
}
return list;
}
```
# L'extraction
2. L'élément à extraire est le premier élément de la liste
. . .
![Extraction d'un élément qui est le
premier.](figs/sorted_list_extract_first.svg){width=70%}
. . .
\footnotesize
```C
sorted_list sorted_list_extract(sorted_list list, int val) {
element *prec = *crt = list; // needed to glue elements together
while (NULL != crt && val > crt->data) {
prec = crt;
crt = crt->next;
}
if (NULL != crt && crt->data == val && prec == crt) { // glue things together
list = list->next;
free(crt);
}
return list;
}
```
# L'extraction
3. L'élément à extraire n'est **pas** dans la liste.
* La liste est vide.
* La valeur est plus grande que le dernier élément de la liste.
* La valeur est plus petite que la valeur de `crt`.
. . .
On retourne la liste inchangée.
. . .
\footnotesize
```C
sorted_list sorted_list_extract(sorted_list list, int val) {
element *prec = *crt = list; // needed to glue elements together
while (NULL != crt && val > crt->data) {
prec = crt;
crt = crt->next;
}
if (NULL == crt || crt->data != val) { // val not present
return list;
}
}
```
# La recherche
```C
element* sorted_list_search(sorted_list list, int val);
```
* Retourne `NULL` si la valeur n'est pas présente (ou la liste vide).
* Retourne un pointeur vers l'élément si la valeur est présente.
. . .
```C
element* sorted_list_search(sorted_list list, int val) {
// search for element smaller than val
element* pos = sorted_list_position(list, val);
if (NULL == pos && val == list->data) {
return list; // first element contains val
} else if (NULL != pos->next && val == pos->next->data) {
return pos->next; // non-first element contains val
} else {
return NULL; // well... val's not here
}
}
```
# La recherche
## La fonction `sorted_list_position`
```C
element* sorted_list_position(sorted_list list, int val);
```
![Trois exemples de retour de la fonction `sorted_list_position()`.](figs/sorted_list_position.svg)
# La recherche
## Exercice: implémenter
```C
element* sorted_list_position(sorted_list list, int val);
```
. . .
```C
element* sorted_list_position(sorted_list list, int val) {
element* pos = list;
if (sorted_list_is_empty(list) || val <= list->data) {
pos = NULL;
} else {
while (NULL != pos->next && val > pos->next>data) {
pos = pos->next;
}
}
return pos;
}
```
# Complexité de la liste chaînée triée
## L'insertion?
. . .
$$
\mathcal{O}(N).
$$
## L'extraction?
. . .
$$
\mathcal{O}(N).
$$
## La recherche?
. . .
$$
\mathcal{O}(N).
$$
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="433.38751mm"
height="35.189583mm"
viewBox="0 0 433.38751 35.189583"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
sodipodi:docname="sorted_list_example.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.46038425"
inkscape:cx="606.01552"
inkscape:cy="-2.1720986"
inkscape:window-width="1892"
inkscape:window-height="918"
inkscape:window-x="14"
inkscape:window-y="44"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(183.74416,-27.912786)">
<image
width="433.38751"
height="35.189583"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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
0P8D14JzHAu7wQwAAAAASUVORK5CYII=
"
id="image844"
x="-183.74416"
y="27.912786" />
</g>
</svg>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment