I. Introduction▲
Dernière structure de données basée sur les listes (enfin !), il s'agit des files. Pour nous faciliter la vie, et ne pas réinventer la roue, nous allons utiliser la bibliothèque de listes doublement chaînées pour créer celle des files.
II. Principe▲
Les files sont très similaires aux piles, la seule différence se situe au niveau de l'ajout de nouvel élément : il se fait en début de liste. Par contre la suppression se fait toujours en fin de liste. Les files sont aussi appelées liste FIFO (First In First Out).
Malgré un fonctionnement proche de celui des piles, la bibliothèque de gestion des files va être plus complexe, en effet, il faut se déplacer au début ou à la fin de la liste suivant que nous ajoutons ou retirons un élément.
III. En Pratique▲
III-A. La structure d'un élément▲
Pour représenter un élément de la pile, il nous suffit de reprendre la structure d'un élément d'une liste doublement chaînée.
typedef struct queue
{
struct queue *prev;
struct queue *next;
void *data;
} queue_s;III-B. Initialisation▲
On initialise le pointeur qui servira de file :
queue_s *queue_new (void)
{
return (NULL);
}III-C. Ajouter un élément▲
Les éléments doivent être ajoutés au début, il faut donc insérer le nouvel élément avant le premier de la liste.
- Voici l'état de la file avant l'appel de la fonction ;
- On se positionne au début de la file grâce au pointeur p_l, c'est donc avant qu'il faut ajouter un élément ;
- Création d'un nouvel élément pointé par p_p ;
- On fait pointer le nouvel élément sur le premier maillon de la file : p_p et inversement ;
- État de la liste après l'appel de la fonction.
Et maintenant la même chose, mais en C :
void queue_post (queue_s ** pp_queue, void *data)
{
if (pp_queue != NULL)
{
queue_s *p_l = NULL;
queue_s *p_p = NULL;
queue_first (pp_queue);
/* (2) */
p_l = *pp_queue;
/* (3) */
p_p = malloc (sizeof (*p_p));
if (p_p != NULL)
{
p_p->data = data;
/* (4) */
p_p->next = p_l;
p_p->prev = NULL;
if (p_l != NULL)
p_l->prev = p_p;
/* (5) */
*pp_queue = p_p;
}
else
{
fprintf (stderr, "Memoire insuffisante\n");
exit (EXIT_FAILURE);
}
}
return;
}Voici le détail de la fonction queue_first qui permet de se déplacer au début de la file :
static void queue_first (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
{
while ((*pp_queue)->prev != NULL)
queue_prev (pp_queue);
}
return;
}
static void queue_prev (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
*pp_queue = (*pp_queue)->prev;
return;
}Ces fonctions sont déclarées comme static puisqu'elles n'ont plus à être utilisées hors de la bibliothèque.
III-D. Extraire un élément▲
- Voici l'état de la file avant l'appel de la fonction ;
- On se positionne à la fin de la file grâce au pointeur p_l, c'est l'élément à supprimer ;
- On sauvegarde le futur dernier élément de la file grâce au pointeur p_p ;
- Libération de la mémoire ;
- On met le pointeur next de p_p à NULL pour marquer la fin de la file.
void *queue_get (queue_s ** pp_queue)
{
void *ret = NULL;
if (pp_queue != NULL && *pp_queue != NULL)
{
queue_s *p_l = NULL;
queue_s *p_p = NULL;
/* (2) */
queue_last (pp_queue);
p_l = *pp_queue;
/* (3) */
if (p_l != NULL)
p_p = p_l->prev;
ret = p_l->data;
/* (4) */
free (p_l);
p_l = NULL;
/* (5) */
if (p_p != NULL)
p_p->next = NULL;
*pp_queue = p_p;
}
return (ret);
}Et bien sûr le code de la fonction queue_last :
static void queue_last (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
{
while ((*pp_queue)->next != NULL)
queue_next (pp_queue);
}
return;
}
static void queue_next (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
*pp_queue = (*pp_queue)->next;
return;
}III-E. Suppression de la file▲
Pour supprimer la liste, il suffit de retirer tous ses éléments.
void queue_delete (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
{
while (*pp_queue != NULL)
queue_get (pp_queue);
}
return;
}IV. Conclusion▲
Cet article termine le premier chapitre de cette série. Avant de passer à la seconde grosse partie (les arbres), nous allons faire une petite pause avec l'étude des tables de hachages.
V. Remerciements▲
Merci à Maximilian pour la relecture attentive de cet article.
VI. Code source complet▲
Téléchargez l'archive zippée.
#ifndef H_FILE
#define H_FILE
typedef struct queue queue_s;
queue_s *queue_new (void);
void queue_post (queue_s **, void *);
void *queue_get (queue_s **);
void queue_delete (queue_s **);
#endif /* not H_FILE */#include <stdio.h>
#include <stdlib.h>
#include "file.h"
struct queue
{
struct queue *prev;
struct queue *next;
void *data;
};
static void queue_first (queue_s **);
static void queue_prev (queue_s **);
static void queue_last (queue_s **);
static void queue_next (queue_s **);
queue_s *queue_new (void)
{
return (NULL);
}
void queue_post (queue_s ** pp_queue, void *data)
{
if (pp_queue != NULL)
{
queue_s *p_l = NULL;
queue_s *p_p = NULL;
queue_first (pp_queue);
p_l = *pp_queue;
p_p = malloc (sizeof (*p_p));
if (p_p != NULL)
{
p_p->data = data;
p_p->next = p_l;
p_p->prev = NULL;
if (p_l != NULL)
p_l->prev = p_p;
*pp_queue = p_p;
}
else
{
fprintf (stderr, "Memoire insuffisante\n");
exit (EXIT_FAILURE);
}
}
return;
}
void *queue_get (queue_s ** pp_queue)
{
void *ret = NULL;
if (pp_queue != NULL && *pp_queue != NULL)
{
queue_s *p_l = NULL;
queue_s *p_p = NULL;
queue_last (pp_queue);
p_l = *pp_queue;
if (p_l != NULL)
p_p = p_l->prev;
ret = p_l->data;
free (p_l);
p_l = NULL;
if (p_p != NULL)
p_p->next = NULL;
*pp_queue = p_p;
}
return (ret);
}
void queue_delete (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
{
while (*pp_queue != NULL)
queue_get (pp_queue);
}
return;
}
static void queue_first (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
{
while ((*pp_queue)->prev != NULL)
queue_prev (pp_queue);
}
return;
}
static void queue_prev (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
*pp_queue = (*pp_queue)->prev;
return;
}
static void queue_last (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
{
while ((*pp_queue)->next != NULL)
queue_next (pp_queue);
}
return;
}
static void queue_next (queue_s ** pp_queue)
{
if (pp_queue != NULL && *pp_queue != NULL)
*pp_queue = (*pp_queue)->next;
return;
}






