Langage C_(13)_liste chaînée à sens unique (facile à comprendre, il suffit de lire ceci pour comprendre la liste chaînée)

Table des matières

Le concept de liste chaînée

0. La composition de la liste chaînée

1. Créez un pointeur de tête

2. Méthode d'insertion de la tête

3. Imprimer la liste chaînée

4. Déterminez si la liste chaînée est vide

5. Calculez le nombre de nœuds effectifs dans la liste chaînée

6. Méthode de branchement de queue

7. Méthode de suppression de tête

8. Méthode de suppression de queue

9. Supprimer la liste chaînée

10.Code source

résultat de l'opération


Le concept de liste chaînée

La liste chaînée est une structure de stockage non séquentielle et non séquentielle dans la structure de stockage physique.L'ordre logique des éléments de données est réalisé par l'ordre de connexion du pointeur dans la liste chaînée.

Chaque nœud contient son champ de données et son champ de pointeur. Le champ de données est utilisé pour stocker les données de ce nœud, et le champ de pointeur stocke l'adresse du nœud suivant lié par ce nœud. Les nœuds sont reliés entre eux pour former un nœud

Alors comment relier chaque nœud, comment former une structure de stockage non séquentielle et non séquentielle. On peut voir la figure ci-dessous pour comprendre

En partant d'un nœud avec des données vides, générez un nouveau nœud, stockez les données que vous souhaitez stocker dans le champ de données du nouveau nœud et continuez à stocker l'adresse du nœud suivant dans le champ de pointeur du nœud actuel, s'il y a n'est pas le prochain nœud, puis définissez le champ de pointeur du dernier nœud (NULL).

0. La composition de la liste chaînée

La liste chaînée est composée de nœuds.Nous pouvons utiliser une structure pour former chaque nœud, puis nous pouvons créer un type de données de nœud.

//结点
typedef struct NodeName
{
          char *name;//数据域
          struct NodeName *next;//指针域
}namelist;

1. Créez un pointeur de tête

Ici, nous créons d'abord un nœud principal et définissons le champ de données du nœud principal sur 0 (sans signification) et le champ de pointeur sur NULL (pour éviter les pointeurs sauvages).

int main(int argc, char const *argv[])
{
         namelist head = {NULL,NULL};//头结点
         namelist *phead = &head;//头结点的指针
         return 0;
}

2. Méthode d'insertion de la tête

Si je souhaite insérer un nouveau nœud au début de la liste chaînée, cette méthode est appelée insertion de tête. Alors comment insérer ce nœud devant, en supposant qu'il y ait d'autres anciens nœuds derrière, alors comment pouvons-nous insérer ce nouveau nœud sans perdre le contact avec les anciens nœuds derrière.

Nous devons donc faire en sorte que le champ de pointeur du nouveau nœud pointe vers l'ancien nœud (champ de pointeur de phead), insérer le champ de données du nouveau nœud et laisser le champ de pointeur de phead pointer vers le nouveau nœud.

//头插法
int CreatHeadNode(namelist *phead, char *pname)
{
          namelist *NewHeadTmp = NULL;//创建新节点
          NewHeadTmp = malloc(sizeof(namelist));//分配堆空间
          if(NULL == NewHeadTmp)//如果申请空间失败,结束!
          {
                    printf("malloc NewHeadTmp failed\n");
                    return -1;
          }
          NewHeadTmp->next = phead->next;//将旧结点的地址给到新插入结点的地址域
          NewHeadTmp->name = pname;//传入数据
          phead->next = NewHeadTmp;//将新节点的地址给到Phead的地址域

          return 0;
}

3. Imprimer la liste chaînée

Nous avons inséré les données de nom à l'aide de l'insertion d'en-tête, alors comment pouvons-nous voir les données que nous avons insérées.

Ici, nous passons dans phead à la fonction d'impression de la liste chaînée, puis créons un pointeur p pointant vers le champ de pointeur de phead, qui est l'adresse du nœud suivant, puis imprimons le champ de données du nœud, puis let p étape par étape Ensuite, pointez sur chaque nœud, imprimez le champ de données de chaque nœud, jusqu'à ce que le champ de pointeur du dernier nœud soit NULL et terminez l'impression. Nous pouvons utiliser une méthode similaire de parcours de tableau de chaînes pour trouver \0, nous déterminons ici si le champ de pointeur du dernier nœud est NULL ;

//打印链表
void PrintfNode(namelist *phead)
{
          namelist *p = NULL;
          p = phead->next;//让p指向第一个结点
          while (NULL != p)//在p为NULL的时候结束循环
          {
                    printf("%s\n", p->name);
                    p = p->next;//指向下一个结点
          }      
}

résultat de l'opération 

Ici j'ai inséré trois nœuds, l'ordre n'est pas Zhang San, Li Si, Wang Wu. Puisqu’il s’agit de la méthode d’insertion d’en-tête, l’ordre d’impression est inversé.

int main(int argc, char const *argv[])
{
         namelist head = {NULL,NULL};//头结点
         namelist *phead = &head;//头结点的指针

         CreatHeadNode(phead,"张三");
         CreatHeadNode(phead,"李四");
         CreatHeadNode(phead,"王五");
         PrintfNode(phead);
         return 0;
}

4. Déterminez si la liste chaînée est vide

Logique simple, pas d'analyse

//判断链表是否为空
int JudgeNull(namelist *phead)
{
          return (NULL == phead->next);//为空返回1,不为空返回0
}

5. Calculez le nombre de nœuds effectifs dans la liste chaînée

L'idée de calculer le nombre de nœuds est la même que l'idée d'imprimer les nœuds de la liste chaînée ci-dessus. Il suffit de définir une variable count dans la fonction et de l'ajouter jusqu'à ce qu'elle passe à NULL pour obtenir le nombre.

//计算链表结点个数
int CountNode(namelist *phead)
{
          int count = 0;
          namelist *p = NULL;
          p = phead->next;

          while(NULL != p)//遍历
          {
                    count++;//计数
                    p = p->next;
          }
          return count;//返回结点个数
}

résultat de l'opération 

J'ai utilisé la méthode d'interpolation à deux têtes pour imprimer respectivement le champ de données du nœud et le nombre de nœuds dans la liste chaînée.

        code de fonction principale

int main(int argc, char const *argv[])
{
         namelist head = {NULL,NULL};//头结点
         namelist *phead = &head;//头结点的指针

         CreatHeadNode(phead,"张三");
         CreatHeadNode(phead,"李四");
         CreatHeadNode(phead,"王五");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数

         CreatHeadNode(phead,"托马斯");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数

          return 0;
}

6. Méthode de branchement de queue

Nous avons analysé la méthode d'insertion d'en-tête et une série d'impressions, de comptages et de jugements NULL ci-dessus. Parlons ensuite de l’insertion de la queue.

Dans la méthode d'interpolation de queue, les paramètres que nous transmettons aux paramètres de fonction sont les valeurs de Phead et des champs de données.

Sur la base de l'insertion de la queue ,Nous devons juger si la liste chaînée est une liste chaînée vide .S'il s'agit d'une liste chaînée vide, pour quelle queue devrions-nous insérer la queue ?

Nous utilisons donc ce que nous avons mentionné précédemment pour déterminer si la liste chaînée est vide. Si elle est vide, nous utilisons d'abord la méthode d'insertion de tête pour créer un nouveau nœud, puis l'insertion suivante ne sera pas vide. La liste chaînée peut être insérée par la méthode d'insertion de la queue.

En entrant dans la méthode d'insertion de queue, nous utilisons d'abord un pointeur pour accéder à la dernière liste chaînée avant l'insertion de queue, puis donnons l'adresse de la nouvelle liste chaînée au champ de pointeur de la liste chaînée de queue avant l'insertion, puis chargeons les données, puis placez le champ de pointeur de la liste chaînée de queue après l'insertion et définissez NULL ;

//尾插法
int CreatTailNode(namelist *phead, char *pname)
{

          if(JudgeNull(phead))//如果为空链表
          {
                    CreatHeadNode(phead,pname);
          }
          else
          {
                    namelist *NewTailTmp = NULL;
                    NewTailTmp = malloc(sizeof(namelist));
                    if(NULL == NewTailTmp)
                    {
                              printf("malloc NewTailTmp failed!\n");
                              return -1;
                    }
                    namelist *p = phead ->next;
                    while(NULL != p->next)//遍历
                    {
                              p = p->next;
                    }
                    p->next = NewTailTmp;//将新结点的地址,给到插入前最后一个结点的指针域
                    NewTailTmp->name = pname;//插入数据域
                    NewTailTmp->next = NULL;//将尾插结点的指针域置NULL
          }
          return 0;
}

résultat de l'opération 

 J'ai inséré deux données supplémentaires à la fin pour comparer avec une insertion sans fin

int main(int argc, char const *argv[])
{
         namelist head = {NULL,NULL};//头结点
         namelist *phead = &head;//头结点的指针
         CreatHeadNode(phead,"张三");
         CreatHeadNode(phead,"李四");
         CreatHeadNode(phead,"王五");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
         CreatHeadNode(phead,"托马斯");
         CreatTailNode(phead,"詹姆斯");
         CreatTailNode(phead,"约翰逊");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          return 0;
}

7. Méthode de suppression de tête

Nous avons expliqué comment insérer un nœud, et parlons maintenant de comment supprimer un nœud.

Il suffit d'attribuer le champ de pointeur du nœud à supprimer au champ de pointeur de phead, puis d'utiliser la fonction free() pour le libérer.

//删除头结点
void DeleteHeadNode(namelist *phead)
{
          if(!JudgeNull(phead))//如果不为空链表
          {
                    namelist *p = NULL;
                    p = phead->next;//p为删除结点的地址
                    phead->next = p->next;//将删除结点的指针域给到phead的指针域
                    free(p);//删除释放头结点
          }
}

résultat de l'opération

Contenu de la fonction principale

int main(int argc, char const *argv[])
{
         namelist head = {NULL,NULL};//头结点
         namelist *phead = &head;//头结点的指针
         CreatHeadNode(phead,"张三");
         CreatHeadNode(phead,"李四");
         CreatHeadNode(phead,"王五");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
         CreatHeadNode(phead,"托马斯");
         CreatTailNode(phead,"詹姆斯");
         CreatTailNode(phead,"约翰逊");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
         DeleteHeadNode(phead);
         PrintfNode(phead);//打印链表
         printf("=======删除头结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          return 0;
}

8. Méthode de suppression de queue

S’il existe une méthode d’élagage de la tête, il doit y avoir une méthode d’élagage de la queue.

L'idée est de parcourir l'avant-dernier nœud, de libérer et de supprimer le champ de pointeur de l'avant-dernier nœud (c'est-à-dire l'adresse du premier au dernier nœud), puis de définir le champ de pointeur. de l'avant-dernier nœud à NULL pour terminer la suppression, car l'avant-dernier nœud est utilisé, donc si le nombre de nœuds est inférieur à deux, la méthode d'insertion de queue ne sera pas terminée, nous utilisons la méthode d'insertion de tête pour terminer la suppression, nous déterminons donc d'abord le nombre de nœuds valides, puis procédons à la méthode d'insertion de Tail.

//删除尾结点
void DeleteTailNode(namelist *phead)
{
          if(2 <= CountNode(phead))//超过两个结点
          {
                    namelist *p = NULL;
                    p = phead->next;
                    while(NULL != p->next->next)//遍历到倒数第二个结点
                    {
                              p = p->next;
                    }
                    free(p->next);//释放删除尾结点
                    p->next = NULL;//将现在的最后结点的指针域置NULL
          }
          else//不超过两个结点
          {
                    DeleteHeadNode(phead);
          }
}

résultat de l'opération

Contenu de la fonction principale

int main(int argc, char const *argv[])
{
         namelist head = {NULL,NULL};//头结点
         namelist *phead = &head;//头结点的指针
         CreatHeadNode(phead,"张三");
         CreatHeadNode(phead,"李四");
         CreatHeadNode(phead,"王五");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
         CreatHeadNode(phead,"托马斯");
         CreatTailNode(phead,"詹姆斯");
         CreatTailNode(phead,"约翰逊");
         PrintfNode(phead);//打印链表
         printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
         DeleteHeadNode(phead);
         PrintfNode(phead);//打印链表
         printf("=======删除头结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
         DeleteTailNode(phead);
         PrintfNode(phead);//打印链表
         printf("=======删除尾结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数

          return 0;
}

9. Supprimer la liste chaînée

Alors, comment supprimer toute la liste chaînée ? Après avoir appris la suppression de tête et la suppression de queue, il est très facile de supprimer la liste chaînée. Nous écrivons un jugement en boucle. Tant que la liste chaînée est toujours vide, nous appliquerons toujours la méthode de suppression de tête ou de suppression de queue. L'efficacité de la méthode de suppression de la tête est supérieure à celle de la méthode de suppression de la queue, utilisez donc l'en-tête pour la supprimer.

//删除链表
void DeleteList(namelist *phead)
{
          while (!JudgeNull(phead))
          {
                    DeleteHeadNode(phead);
          }
          printf("已清空链表!\n");        
}

 résultat de l'opération

fonction principale

int main(int argc, char const *argv[])
{
          namelist head = {NULL,NULL};//头结点
          namelist *phead = &head;//头结点的指针
          CreatHeadNode(phead,"张三");
          CreatHeadNode(phead,"李四");
          CreatHeadNode(phead,"王五");
          PrintfNode(phead);//打印链表
          printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          CreatHeadNode(phead,"托马斯");
          CreatTailNode(phead,"詹姆斯");
          CreatTailNode(phead,"约翰逊");
          PrintfNode(phead);//打印链表
          printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          DeleteHeadNode(phead);
          PrintfNode(phead);//打印链表
          printf("=======删除头结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          DeleteTailNode(phead);
          PrintfNode(phead);//打印链表
          printf("=======删除尾结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          DeleteList(phead);
          PrintfNode(phead);//打印链表
          printf("=======删除链表后后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          return 0;
}

10.Code source

#include <stdio.h>
#include <stdlib.h>

//结点
typedef struct NodeName
{
          char *name;//数据域
          struct NodeName *next;//指针域
}namelist;

//头插法
int CreatHeadNode(namelist *phead, char *pname)
{
          namelist *NewHeadTmp = NULL;//创建新节点
          NewHeadTmp = malloc(sizeof(namelist));//分配堆空间
          if(NULL == NewHeadTmp)//如果申请空间失败,结束!
          {
                    printf("malloc NewHeadTmp failed\n");
                    return -1;
          }
          NewHeadTmp->next = phead->next;//将旧结点的地址给到新插入结点的地址域
          NewHeadTmp->name = pname;//传入数据
          phead->next = NewHeadTmp;//将新节点的地址给到Phead的地址域

          return 0;
}
//打印链表
void PrintfNode(namelist *phead)
{
          namelist *p = NULL;
          p = phead->next;//让p指向第一个结点
          while (NULL != p)//在p为NULL的时候结束循环
          {
                    printf("%s\n", p->name);
                    p = p->next;//指向下一个结点
          }      
}
//判断链表是否为空
int JudgeNull(namelist *phead)
{
          return (NULL == phead->next);//为空返回1,不为空返回0
}
//计算链表结点个数
int CountNode(namelist *phead)
{
          int count = 0;
          namelist *p = NULL;
          p = phead->next;

          while(NULL != p)//遍历
          {
                    count++;//计数
                    p = p->next;
          }
          return count;//返回结点个数
}
//尾插法
int CreatTailNode(namelist *phead, char *pname)
{

          if(JudgeNull(phead))//如果为空链表
          {
                    CreatHeadNode(phead,pname);
          }
          else
          {
                    namelist *NewTailTmp = NULL;
                    NewTailTmp = malloc(sizeof(namelist));
                    if(NULL == NewTailTmp)
                    {
                              printf("malloc NewTailTmp failed!\n");
                              return -1;
                    }
                    namelist *p = phead ->next;
                    while(NULL != p->next)//遍历
                    {
                              p = p->next;
                    }
                    p->next = NewTailTmp;//将新结点的地址,给到插入前最后一个结点的指针域
                    NewTailTmp->name = pname;//插入数据域
                    NewTailTmp->next = NULL;//将尾插结点的指针域置NULL
          }
          return 0;
}
//删除头结点
void DeleteHeadNode(namelist *phead)
{
          if(!JudgeNull(phead))//如果不为空链表
          {
                    namelist *p = NULL;
                    p = phead->next;//p为删除结点的地址
                    phead->next = p->next;//将删除结点的指针域给到phead的指针域
                    free(p);//删除释放头结点
          }
}
//删除尾结点
void DeleteTailNode(namelist *phead)
{
          if(2 <= CountNode(phead))//超过两个结点
          {
                    namelist *p = NULL;
                    p = phead->next;
                    while(NULL != p->next->next)//遍历到倒数第二个结点
                    {
                              p = p->next;
                    }
                    free(p->next);//释放删除尾结点
                    p->next = NULL;//将现在的最后结点的指针域置NULL
          }
          else//不超过两个结点
          {
                    DeleteHeadNode(phead);
          }
}
//删除链表
void DeleteList(namelist *phead)
{
          while (!JudgeNull(phead))
          {
                    DeleteHeadNode(phead);
          }
          printf("已清空链表!\n");        
}
int main(int argc, char const *argv[])
{
          namelist head = {NULL,NULL};//头结点
          namelist *phead = &head;//头结点的指针
          CreatHeadNode(phead,"张三");
          CreatHeadNode(phead,"李四");
          CreatHeadNode(phead,"王五");
          PrintfNode(phead);//打印链表
          printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          CreatHeadNode(phead,"托马斯");
          CreatTailNode(phead,"詹姆斯");
          CreatTailNode(phead,"约翰逊");
          PrintfNode(phead);//打印链表
          printf("==========结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          DeleteHeadNode(phead);
          PrintfNode(phead);//打印链表
          printf("=======删除头结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          DeleteTailNode(phead);
          PrintfNode(phead);//打印链表
          printf("=======删除尾结点后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          DeleteList(phead);
          PrintfNode(phead);//打印链表
          printf("=======删除链表后后结点个数count=%d==========\n",CountNode(phead));//打印此时结点个数
          return 0;
}

résultat de l'opération

Je suppose que tu aimes

Origine blog.csdn.net/m0_58193842/article/details/128398602
conseillé
Classement