Skip to content
Snippets Groups Projects
Commit 5f492594 authored by paul.albuquer's avatar paul.albuquer
Browse files

added source code and handout for sorted lists

parent 2ff97713
Branches
No related tags found
No related merge requests found
Pipeline #14894 failed
Showing
with 420 additions and 2 deletions
...@@ -94,8 +94,7 @@ Il faut considérer plusieurs cas: ...@@ -94,8 +94,7 @@ Il faut considérer plusieurs cas:
#### Extraction en tête de file d'attente #### Extraction en tête de file d'attente
Voici l'entête de la procédure: Voici l'entête de la procédure: `int queue_extraire(queue* fa);`
`int queue_extraire(queue* fa);`
On commence par récupérer, la valeur en tête de file d'attente via l'appel `queue_tete(*fa);` On commence par récupérer, la valeur en tête de file d'attente via l'appel `queue_tete(*fa);`
......
# Algorithmes et structures de données
# Structure de liste triée
*****
## 1. Définition
On considère une liste chaînée d'articles. Chaque article comportera un champ pour stocker les valeurs
dans la liste et un champ contenant une variable de type pointeur pour assurer le chaînage.
Schématiquement:
![Illustration d'une file d'attente](./figures/fig_queue_representation.png)
La liste est triée pour autant que l'insertion de chaque nouvelle valeur dans la liste maintienne cette
propriété.
L'accès à la liste se fera uniquement par le pointeur lst qui référence le début de la liste.
Une telle liste chaînée sera déclarée par exemple sous la forme suivante:
```C
typedef struct _element { // Elément de liste
int n;
struct _element* suivant;
} element;
typedef element* liste; // Pointeur sur des éléments de liste
```
## 2. Insertion dans une liste triée
Voici l'entête de la procédure : `liste inserer(liste lst,int val);`
Il faut considérer plusieurs cas.
### La liste est vide: `lst == NULL`
![Insertion dans une liste triée vide](./figures/fig_empty_sorted_list_insert.png)
### L'insertion se fait en 1ère position: `val <= lst->n`
Par exemple, pour `val = 1`
![Insertion en 1ère position d'une liste triée](./figures/fig_1st_position_sorted_list_insert.png)
### Les positions autres que la 1ère position
Par exemple, pour `val = 13`
![Insertion aux autres positions d'une liste triée](./figures/fig_other_position_sorted_list_insert.png)
```C
(1) tmp = malloc(sizeof(element));
tmp->n = 13;
```
On déplace un pointeur crt jusqu'à l'élément précédent la position d'insertion de sorte que
```C
crt->n < val <= crt->suivant->n
```
On utilise une boucle:
```C
(2) while (NULL != crt->suivant && val > crt->suivant->n) {
crt = crt->suivant;
}
```
Puis on raccroche l'élément pointé par tmp à la liste
```C
(3) tmp->suivant = crt->suivant;
(4) crt->suivant = tmp;
return lst;
```
## 3. Extraction d'un élément dans une liste triée
Voici l'entête de la procédure : `liste extraire(liste lst,int val);`
Si la liste est vide, on retourne la liste vide.
Ensuite, on déplace deux pointeurs prec et crt à travers la liste jusqu'à ce que : `prec->n < val <= crt->n`
On utilise une boucle:
```C
while (NULL != crt && val > crt->n) {
prec = crt;
crt = crt->suivant;
}
```
Il faut à nouveau considérer plusieurs cas.
### La valeur à retirer est supérieure à la dernière valeur de la liste.
Ceci équivaut à: `crt == NULL` ou `prec->suivant == NULL`
On retourne la liste inchangée.
Par exemple, pour `val = 30`
![Extraction d'une valeur supérieure à la dernière valeur d'une liste triée](./figures/fig_greater_value_sorted_list_extract.png)
### La valeur à retirer n'est pas celle dans l'élément pointé par `crt`.
Ceci équivaut à: `val < crt->n`
On retourne la liste inchangée.
Par exemple, pour `val = 9`
![Extraction d'une valeur pas dans une liste triée (1)](./figures/fig_no_value_sorted_list_extract_1.png)
ou pour val = 1
![Extraction d'une valeur pas dans une liste triée (2)](./figures/fig_no_value_sorted_list_extract_2.png)
### La valeur à retirer est celle dans l'élément pointé par `crt`.
Ceci équivaut à: `val == crt->n`
#### La valeur à retirer est en début de liste.
Ceci équivaut à: `crt == prec`
On doit déplacer la tête de liste : lst = crt->suivant;
Par exemple, pour `val = 3`
![Extraction d'une valeur en début de liste triée ](./figures/fig_1st_element_sorted_list_extract.png)
#### La valeur à retirer n'est pas en début de liste.
On doit raccrocher l'élément pointé par prec à celui suivant `crt`: `prec->suivant = crt->suivant;`
Par exemple, pour `val = 12`
![Extraction d'une valeur pas en début de liste triée](./figures/fig_other_element_sorted_list_extract_1.png)
ou pour `val = 21`
![Extraction d'une valeur pas dans une liste triée (1)](./figures/fig_other_element_sorted_list_extract_2.png)
Finalement, on libère la mémoire de l'élément pointé par `crt`: `free(crt);`
![Extraction d'une valeur pas dans une liste triée (1)](./figures/fig_free_element_sorted_list_extract.png)
## 4. Recherche dans une liste triée
La fonction recherche retourne un pointeur sur l'élément qui contient la valeur recherchée ou un pointeur `NULL` si la valeur est absente de la liste triée.
Voici l'entête de la procédure : `element* recherche(liste lst,int val);`
On considère d'abord la fonction utilitaire `position` qui retourne un pointeur sur l'élément avant la
position d'insertion d'une valeur ou un pointeur `NULL` s'il s'agit de la tête de liste.
```C
element* position(liste lst,int val) {
element* pos = lst;
if (est_vide(lst) || val <= lst->n) {
pos = NULL;
} else {
while (NULL != pos->suivant && val > pos->suivant->n) {
pos = pos->suivant;
}
}
return pos;
}
```
Par exemple, pour val = 1 ou 3
![Recherche d'une valeur en début de liste triée](./figures/fig_1st_element_sorted_list_search.png)
et pour val = 29
![Recherche d'une valeur en fin de liste triée](./figures/fig_last_element_sorted_list_search.png)
et finalement pour val = 10 ou 12
![Recherche d'une valeur en milieu de liste triée](./figures/fig_other_element_sorted_list_search.png)
Ainsi, la fonction de recherche s'écrit simplement :
```C
element* recherche(liste lst,int val) {
element* pos = position(lst,val);
if (est_vide(lst)) {
return NULL;
}
if (NULL == pos && val == lst->n) {
return lst;
} else if (NULL != pos->suivant && val == pos->suivant->n) {
return pos->suivant;
} else {
return NULL;
}
}
```
## Exercice
Ecrire directement la fonction `recherche` sans utiliser la fonction `position`.
Faire les dessins illustrant les différents cas possibles.
lessons/figures/fig_1st_element_sorted_list_extract.png

9.01 KiB

lessons/figures/fig_1st_element_sorted_list_search.png

43.3 KiB

lessons/figures/fig_1st_position_sorted_list_insert.png

20.5 KiB

lessons/figures/fig_empty_sorted_list_insert.png

12.7 KiB

lessons/figures/fig_free_element_sorted_list_extract.png

109 KiB

lessons/figures/fig_greater_value_sorted_list_extract.png

6.73 KiB

lessons/figures/fig_last_element_sorted_list_search.png

31.1 KiB

lessons/figures/fig_no_value_sorted_list_extract_1.png

6.44 KiB

lessons/figures/fig_no_value_sorted_list_extract_2.png

6.91 KiB

lessons/figures/fig_other_element_sorted_list_extract_1.png

116 KiB

lessons/figures/fig_other_element_sorted_list_extract_2.png

113 KiB

lessons/figures/fig_other_element_sorted_list_search.png

38.3 KiB

lessons/figures/fig_other_position_sorted_list_insert.png

12 KiB

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef struct _element {
int n;
struct _element* suivant;
} element;
typedef element* liste;
// Crée une liste vide
liste liste_creer() {
return NULL;
}
// Teste si la liste vide
bool liste_est_vide(liste lst) {
return NULL == lst;
}
// Retourne un pointeur sur l'élement avant l'emplacement d'insertion;
// ce pointeur est nul si la liste est vide ou si l'insertion est en tête de liste
element* position(liste lst,int val) {
element* pos = lst;
if (liste_est_vide(lst) || val <= lst->n) {
pos = NULL;
} else {
while (NULL != pos->suivant && val > pos->suivant->n) {
pos = pos->suivant;
}
}
return pos;
}
// Insère un élément dans la liste triée et retourne la liste mise à jour
liste liste_inserer(liste lst,int val) {
element* tmp = malloc(sizeof(element));
tmp->n = val;
element* crt = position(lst,val);
if (NULL == crt) { // insertion dans une liste vide ou en tête de liste
tmp->suivant = lst;
lst = tmp;
} else { // insertion au milieu ou en fin de liste
tmp->suivant = crt->suivant;
crt->suivant = tmp;
}
return lst;
}
// Extrait un élément avec la valeur <val> et retourne la liste mise à jour;
// la liste est inchangée si elle est initialement vide
// ou si la valeur est absente
liste liste_extraire(liste lst,int val) {
element *crt = lst, *prec = lst;
// boucle pour placer <val>: prec->n < val <= crt->n
while (NULL != crt && val > crt->n) {
prec = crt;
crt = crt->suivant;
}
// liste non-vide et <val> présente de la liste
if (NULL != crt && val == crt->n) {
if (crt == prec) { // extraction en début de liste
lst = lst->suivant;
} else { // extraction en milieu ou fin de liste
prec->suivant = crt->suivant;
}
free(crt);
}
return lst;
}
// Retourne un pointeur sur l'élément qui contient <val> ou un pointeur nul
// si la liste est vide ou la valeur absente
element* liste_recherche(liste lst,int val) {
// à compléter
return NULL;
}
// Imprime le contenu de la liste
void print(liste lst) {
element* crt = lst;
while (NULL != crt) {
printf("%d ",crt->n);
crt = crt->suivant;
}
}
int main(int argc, char** argv) {
liste lst = liste_creer();
char str[20];
do {
printf("Insert: ");
scanf("%s", str);
if (0 == strcmp("quit",str)) break;
lst = liste_inserer(lst,atoi(str));
print(lst);
printf("\n");
} while (true);
do {
printf("Extract: ");
scanf("%s", str);
if (0 == strcmp("quit",str)) break;
lst = liste_extraire(lst,atoi(str));
print(lst);
printf("\n");
} while (true);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef struct _element {
int n;
struct _element* suivant;
} element;
typedef element* liste;
// Crée une liste vide
liste liste_creer() {
return NULL;
}
// Teste si la liste vide
bool liste_est_vide(liste lst) {
return NULL == lst;
}
// Retourne un pointeur sur l'élement avant l'emplacement d'insertion;
// ce pointeur est nul si la liste est vide ou si l'insertion est en tête de liste
element* position(liste lst,int val) {
element* pos = lst;
if (liste_est_vide(lst) || val <= lst->n) {
pos = NULL;
} else {
while (NULL != pos->suivant && val > pos->suivant->n) {
pos = pos->suivant;
}
}
return pos;
}
// Insère un élément dans la liste triée et retourne la liste mise à jour
liste liste_inserer(liste lst,int val) {
element* tmp = malloc(sizeof(element));
tmp->n = val;
element* pos = position(lst,val);
if (NULL == pos) { // insertion dans une liste vide ou en tête de liste
// à compléter
} else { // insertion au milieu ou en fin de liste
// à compléter
}
return lst;
}
// Extrait un élément avec la valeur <val> et retourne la liste mise à jour;
// la liste est inchangée si elle est initialement vide
// ou si la valeur est absente
liste liste_extraire(liste lst,int val) {
element* prec = lst;
element* crt = lst;
// boucle pour placer <val>: prec->n < val <= crt->n
// à compléter
// liste non-vide et <val> présente de la liste
if (NULL != crt && val == crt->n) {
if (crt == prec) { // extraction en début de liste
lst = lst->suivant;
} else { // extraction en milieu ou fin de liste
prec->suivant = crt->suivant;
}
free(crt);
}
return lst;
}
// Retourne un pointeur sur l'élément qui contient <val> ou un pointeur nul
// si la liste est vide ou la valeur absente
element* liste_recherche(liste lst,int val) {
// à compléter
return NULL;
}
// Imprime le contenu de la liste
void print(liste lst) {
//à compléter
}
int main(int argc, char** argv) {
liste lst = liste_creer();
char str[20];
do {
printf("Insert: ");
scanf("%s", str);
if (0 == strcmp("quit",str)) break;
lst = liste_inserer(lst,atoi(str));
print(lst);
printf("\n");
} while (true);
do {
printf("Extract: ");
scanf("%s", str);
if (0 == strcmp("quit",str)) break;
lst = liste_extraire(lst,atoi(str));
print(lst);
printf("\n");
} while (true);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment