C语言链表实践(高阶篇三十七)

  结构变量地址与成员地址

    下列代码:

      struct student

      {

        char name[9]; /*姓名*/

        int age; /*年龄*/

        struct student *next; /*下一结点指针*/

      };

      main()

      {

        struct student stu,*pstu;

        int *pi;

        pstu=&stu;

        pi=&stu.age;

        pi=&pstu->age;

      }

      pstu只能指向同类型的结构变量地址,pi只能指向同类型的结构成员地址。

  创建链表并添加结点

    链表的代码都比较长,要做到无限制地动态创建,有些难度。在这里,简单地创建4个节点,先删除一些需要判断的因素。

    链表创建流程:

      (1)创建一个链表需要3个指针,头指针(pHead),尾指针(pEnd),新指针(pNew)

      (2)刚开始链表中一个结点都没有,可用malloc申请内存,动态创建1个结点,令pNew指向它

      (3)输入数据后,目前这个新结点又是头结点,也是最后一个结点,所以要令pHead和pEnd也指向它。第一个结点通常需要特殊处理,所以将它放在循环外面建立

      (4)剩下3个结点有相同规律,可用(5)到(7)步的循环进行处理:

      (5)新建结点给pNew,输入数据

      (6)使最后一个结点pEnd的下一结点next指向这个新结点,形成兄弟关系

      (7)将新结点pNew设为最后一个结点pEnd

      (8)循环结束

      (9)不再添加结点,要使最后一个结点pEnd的指针指向NULL

      (10)返回头指针pHead

    程序1:create函数

      创建链表并输入4个结点

  输出链表

    相对其它操作,输出链表结点的操作比较简单,用一个临时指针通过循环不停地指向下一结点即可。

      程序1:print函数

        输出链表所有结点

  删除结点

    删除结点时通常会进行结点查找,找到符合条件的结点再进行删除操作。

    

      在本程序中找到第3个结点为要删除的结点,再令第2个结点的下一结点指针指向第4个结点,第3个结点就完成了自然脱链动作。

        程序1:del函数

          删除指定姓名的结点

  插入结点

    插入的意思是把结点插入至链表中间,插入方法有“前插”和“后插”法,前插就是找到目标结点后,在它前面插入新结点,后插就是在其后面插入。本程序中演示的是前插法。有个例外的是:如果未找到指定结点,会将新结点添加到链表最后。

     

      程序1:insert函数

        插入一个新结点在指定姓名之前

// 37-链表实践.c。
#include <stdio.h>

struct student     //定义学生结构体
{
    char name[9];   //一个汉字两个字结,末尾加 \0
    int age;        //年龄
    struct student *pNext;   //下一结点指针
};


struct student* create()    //创建链表结点函数,返回student类型指针
{
    struct student *pHead, *pEnd, *pNew;     //头指针,未指针,新指针
    
    /*创建链表的头一个结点.*/
    //申请动态内存空间地址。 9+4+4 = 17byte
    pNew = (struct student*) malloc(sizeof(struct student)); 

    //输入头结点姓名,年龄
    scanf("%s%d",pNew->name,&pNew->age);
    pHead = pEnd = pNew;   //一个结点的地址相同的


    //第一个结点已经创建,只需创建三个结点
    for (size_t i = 0; i < 3; i++)    
    {
        //申请新的链表内存,创建结点
        pNew = (struct student*)malloc(sizeof(struct student));

        //输入头结点姓名,年龄
        scanf("%s%d", pNew->name, &pNew->age);

        //将上一个结点的 struct student *pNext 指针指向新结点
        pEnd->pNext = pNew;   
        
        pEnd = pNew;   //将新结点设为最后一个结点
    }

    //循环完成后,将最后一个结点设为空指针
    pEnd->pNext = NULL;

    //将链表第一结地址返回
    return pHead;
}


void print(struct student *pHead)     //输出结点
{
    struct student *p;    //定义指针变量
    p = pHead;    //赋值给第一个结点
    while (p != NULL)   //指针空就是最后一个结点
    {
        printf("姓名:%s,年龄:%d\n", p->name, p->age);
        p = p->pNext;
    }
}


void del(struct student *pHead,char *name)    //删除指定的结点
{
    //无法删除第一个结点
    struct student *pFront, *pBack;   //前结点,后结点
    pBack = pHead;        //后结点指向头结点
    pFront = pBack->pNext; //前结点指向头结点的下一结点
    while (pFront != NULL)  //前结点为空说明指向最后一个结点
    {
        if (strcmp(name, pFront->name) == 0)   //找到对应结点,准备删除
        {
            //将上一个结点的 struct student *pNext 指向当前结点里的 struct student *pNext
            pBack->pNext = pFront->pNext;
            free(pFront);    //释放内存
            return;
        }
        pBack = pFront;         //后结点设为前结点
        pFront = pFront->pNext; //前结点指向下一个结点
    }

    printf("未找到删除的结点\n");
}


void insert(struct student *pHead,char *name)
{
    //无法在第一个结点前插入
    struct student *pFront, *pBack, *pNew;    //前结点,后结点,新结点

    //创建一个新结点
    pNew = (struct student *)malloc(sizeof(struct student));
    printf("输入姓名和年龄:\n");
    scanf("%s%d", pNew->name, &pNew->age);

    pBack = pHead;    //后结点指向头结点
    pFront = pHead->pNext;  //前结点指向头结点的下一结点

    while (pFront != NULL)
    { 
        if (strcmp(name, pFront->name) == 0)   //找打插入的结点
        {
            pBack->pNext = pNew;  //后结点的下一结点指向新结点
            pNew->pNext = pFront; //新结点的下一结点指向前结点
            return;
        }

        pBack = pFront;     //后结点设为前结点
        pFront = pFront->pNext; //前结点指向下一个结点
    }

    //如果未找到插入的结点,那么就把新结点插在最后面
    pBack->pNext = pNew;  //pBack 指向最后一个结点,将新结点pNew设为下一结点
    pNew->pNext = NULL;   //新结点的下一结点指向空NULL
}

void main()
{
    struct student *pHead;   //定义 链表头指针
    pHead = create();       //创建链表结点,返回头指针
    print(pHead);            //输出创建的链表的结点

    printf("删除指定的结点:\n\n\n");
    del(pHead,"cc");   //删除指定的结点
    print(pHead);      //输出删除后链表的结点


    printf("新增指定的结点:\n\n\n");
    insert(pHead,"cc");
    print(pHead);      //输出新增后链表的结点
}

原文地址:https://www.cnblogs.com/httpcc/p/15559025.html