IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Apprendre à programmer les listes chaînées en C,
Un tutoriel de CGi

Le , par Community Management

65PARTAGES

0  2 
Chers membres,

Je vous présente ce tutoriel de CGi « Apprendre à programmer les listes chaînées en C » :


Une liste chaînée est un système informatique qui permet la sauvegarde dynamique de données en mémoire tout comme des variables ou tableaux, mais sans se préoccuper de leur nombre et en rendant leur allocation plus transparente.
Dans ce tutoriel, vous allez apprendre à programmer les listes chaînées en C.
Bonne lecture
Vous avez lu gratuitement 191 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de neuneutrinos
Membre actif https://www.developpez.com
Le 04/05/2016 à 16:17
Bon j'ai lu attentivement le contenu de ce tutoriel et certains points m'ont paru un peu étrange voir incomplet.
et ça commence dès la définition...
C'est un système informatique qui permet la sauvegarde dynamique de données en mémoire tout comme des variables ou tableaux, mais sans se préoccuper de leur nombre et en rendant leur allocation plus transparente.
On peut faire la même chose avec un tableau...
exemple simplifié:
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//je zappe les test d'allocations ,etc...

typedef struct TableauSansLimite TableauSansLimite;
struct TableauSansLimite
{
 int* tab;
 int nbCase;
};

void init_TableauSansLimite(TableauSansLimite* tsl)//initialise proprement
{
 tsl->tab=NULL;
 tsl->nbCase=0;
}

void free_TableauSansLimite(TableauSansLimite* tsl)//vide proprement
{
 free(tsl->tab);
 init_TableauSansLimite(tsl);
}


void needRealloc_TableauSansLimite(TableauSansLimite* tsl,int newSize)//ré-alloue si nécessaire
{
 if(newSize>=tsl->nbCase)
 {
  tsl->tab=realloc (tsl->tab,newSize*sizeof(int));
  tsl->nbCase=newSize;
 }
}

int getCase_TableauSansLimite(TableauSansLimite* tsl,int indice)
{
 needRealloc_TableauSansLimite(tsl,indice+1);
 return tsl->tab[indice];
}

void setCase_TableauSansLimite(TableauSansLimite* tsl,int indice,int valeur)
{
 needRealloc_TableauSansLimite(tsl,indice+1);
 tsl->tab[indice]=valeur;
}

//utilisation

TableauSansLimite tab;
init_TableauSansLimite(&tab);
setCase_TableauSansLimite(&tsl,42,123);
printf("%d\n",getCase_TableauSansLimite(&tsl,42));//affichera 123
D'après la définition, cette structure est une liste chaînée...

Le tableau correspond à une architecture mémoire.
La liste chaînée en est une autre.
C'est sans tenir compte d'un nombre ou d'allocation mémoire...

un tableau
  • Les éléments DOIVENT être contiguë en mémoire.
  • Accès à n'importe quel élement avec un temps constant ( O(1) )
  • insersion ou suppression de case aléatoire "longue" (peut demander de décaler les éléments pour garder un tableau) ( O(n) )

une liste
  • Les éléments peuvent ne pas être contiguë en mémoire
  • Insertion avec un temps constant ( O(1) )
  • Accès séquentiel pour accéder aux éléments ( O(n) )



On dit liste chaînée, car les données sont chaînées les unes avec les autres. On accède aux données à l'aide d'un ou deux points d'entrée qui se situent la plupart du temps aux extrémités de la liste.

Dans la pratique ces points d'entrée seront des pointeurs soit sur le premier ou le dernier élément de la liste, voire sur les deux ou même mobile.

Les éléments de la liste sont chaînés entre eux à l'aide de pointeurs sur leur élément suivant ou précédent, voire sur les deux. Ces pointeurs doivent donc faire partie de l'élément. Ce qui nous orientera vers l'utilisation d'une structure du langage C (struct). Cette structure aura donc la particularité d'avoir au moins un pointeur sur des variables du même type qu'elle. Ce pointeur servira à relier les éléments de la liste entre eux. La structure contiendra bien sûr aussi les données que l'on veut mémoriser.
Très mal dit ou trop confus...
Cette parti peut être reformuler plus simplement (je propose "à froid" )

"
On dit chaînée car chaque élément possède au moins un lien vers un autre élément.
  • On parle de liste simplement chaînée lorsqu'un élément ne possède qu'un lien vers l'élément suivant.
  • On parle de liste doublement chaînée lorsqu'un élément possède un lien vers l'élément suivant ET précédant.


Dans la pratique, un élément sera représenté par une structure contenant la donnée ainsi qu'un pointeur vers l'élément suivant
et dans le cas d'une liste doublement chaînée, un pointeur vers l'élément précédant.

On mettra à NULL lorsque qu'u élément n'a plus de suivant (ou précédant).
[code exemple]

"


La pile n'est pas le meilleur exemple car elle ne fait pas intervenir LA propriété des listes à savoir l'insertion rapide.
Et se représente très bien avec un tableau ( exemple : la stack )
Un exemple visuel serait,par exemple, un maillon par ligne et faire une insertion et suppression de ligne.

Et pourquoi commencer de 0 à présenter les listes sans faire un comparatif avec les tableau ?

la "liste triée" aurait été un très bon endroit pour !
(comparaison avec le tri par insertion par exemple !)

Ensuite, pour donner le meilleur exemple, les "const" c'est pas pour les chiens
int Length(const pile *p)
void View(const pile *p)
//...
Là ou l'information serait utile au niveau des insertions/suppressions
pas un commentaire...

et au niveau des listes doublement chaînées, au moins un schémas de plus ne serait pas de trop ...

Ensuite classique... aucune optimisation sur les listes.

Parlera-t-on des liste chaînées circulaire ?
Parlera-t-on des liste chaînées avec sentinelle ? (un élément par défaut pour généraliser les insertions/suppressions ! )
Parlera-t-on de l'optimisation mémoire avec un chaînage XOR ? (bon celui là il est un peu à part)

Conclusion :

Bonne initiative à la base, mais incomplet...

(je ne veux pas être méchant, je dit ce que je pense être manquant ou à modifier )

voilà,voilà
2  0 
Avatar de gerald3d
Expert confirmé https://www.developpez.com
Le 07/11/2025 à 10:19
Citation Envoyé par breaker234 Voir le message
Bonjour a tous. Y,a t'il un moyen d'utiliser les listes pour pouvoir stockés des donnés qui ne sont pas necessairement de meme type
Bonjour.

Tout à fait. Il faut cependant que la donnée à stocker soit de type void*, donc que la liste chaînée demande ce type de données. Le problème viendra par la suite lors de la lecture de ces données. Tu vas récupérer naturellement un pointeur générique qu'il faudra "caster" pour pouvoir la manipuler. Comment savoir alors le type réel ?

Le tutoriel donné implémente une donnée de type int. À toi de la modifier pour prendre en compte le type void*.
2  0 
Avatar de breaker234
Nouveau Candidat au Club https://www.developpez.com
Le 07/11/2025 à 9:34
Bonjour a tous. Y,a t'il un moyen d'utiliser les listes pour pouvoir stockés des donnés qui ne sont pas necessairement de meme type
1  0 
Avatar de henderson
Membre chevronné https://www.developpez.com
Le 07/11/2025 à 17:20
A titre perso, je préfère utiliser une pile pour y stocker un ensemble d'objets prêts à servir et une liste pour y stocker les objets en cours d'utilisation.
Dans ce contexte, mes objets sont dotés de pointeurs Prev et Next.
Ici peu importe la manière dont on code l'objet (struct en C ou class en C++, ce qui est mon cas)
La pile est une liste d'objets simplement liés, de Next en Next.

La liste utilise le chaînage double où chaque objet est lié à un précédent et un suivant (selon ...).
C'est utile si on a besoin de supprimer ou ajouter un objet dans la liste, à un emplacement précis.
C'est tout aussi intéressant si on veut insérer le contenu d'une liste à l'intérieur d'une autre liste.

Certes, celà concerne chez moi, un contexte particulier : celui de la M.A.O. (en fait c'est un CUBASE-like donc ...)
Domaine dans lequel, je peux être amené à traiter plusieurs centaines de milliers d'objets ... en tant qu'évènements musicaux.
Donc, je me simplifie la vie en n'ayant plus à solliciter la mémoire à coups de malloc ...
Un simple très gros tableau suffit avec une mise en liste dans la pile des objets du tableau !

Je le conviens, c'est un exemple très spécifique.

CGi a toujours su nous apporter son savoir faire !
1  0 
Avatar de henderson
Membre chevronné https://www.developpez.com
Le 30/11/2025 à 10:11
Le chaînage d'objets n'est pas seulement limité à leur stockage.
On a aussi la possibilité d'élaborer des maillages.
Un circuit routier est un maillage de chemins possibles entre les villes.
Les villes peuvent être stockées dans une liste : A->B->C->D->E->F->G...
mais il pourra exister différents maillages : A->D->E->G->A et D->F->E->A->G ...
Il en va de même pour le graphisme 3D avec les sommets et les arêtes.
En musique on peut modéliser un DX7 à l'aide d'opérateurs de CHOWNING où les algorithmes sont obtenus par maillage : OP2->OP1 + OP4->OP3 + OP5->OP6<->OP6
etc...

Donc le chaînage d'objets c'est tout un monde où la pile et la liste ne sont que deux exemples particuliers qu'il est bon de connaître, quelque soit la manière dont on les code !
1  0 
Avatar de boboss123
Membre éprouvé https://www.developpez.com
Le 19/11/2025 à 10:16
Je n'ai pas bien compris ce que vous faites.
J'aurais créé un pile d’objets contenant chacun un pointeur next/prev et en suite deux listes (une pour les objets utilisés et une pour les objets non utilisés)
0  0 
Avatar de henderson
Membre chevronné https://www.developpez.com
Le 27/11/2025 à 9:53
En principe je code en C++ pour une meilleure lisibilité !
Donc juste pour illustrer un peu :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
typedef struct sEv{
struct sEv *Prev;
struct sEv *Next;
//...
//...
} Event;
//-------------------------
#define nb_ev 1000000 // du temps de CUBASE sur ATARI on en avait beaucoup moins !!!
//-------------------------
typedef struct sStack{
Event Stock[nb_ev];
Event *First;
int Count;
} StackEv;
//-------------------------
StackEv EventStack;
//-------------------------
void InitStackEv(StackEv* S)
{
int j;
int max = nb_ev-1;
for(j=0; j < max; j++)
	{
	S->Stock[j].Next = &S->Stock[j+1];
	}
S->Stock[max].Next = NULL;
S->Count = nb_ev;
}
//-------------------------
Event* PopEv(StackEv *S)
{
Event *N = S->First;
if(N != NULL)
	{
	S->First = N->Next;
	S->Count--;
	}
return N;
}
//-------------------------
void Push(StackEv *S, Event *E)
{
E->Next = S->First;
S->First = E;
S->Count++;
}
//-------------------------
void PushEvents(StackEv *S, Event *AFirst, Event *ALast, int ACount)
{
ALast->Next = S->First;
S->First = AFirst;
S->Count += ACount;
}
//-------------------------
1  1