zoukankan      html  css  js  c++  java
  • 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);      //输出新增后链表的结点
    }

  • 相关阅读:
    记录:将图片数据生成 tfrecords 文件并在训练使用时读取
    记录:EM 算法估计混合高斯模型参数
    记录:Ubuntu 18.04 安装 tensorflow-gpu 版本
    记录:tf.saved_model 模块的简单使用(TensorFlow 模型存储与恢复)
    记录:TensorFlow 中的 padding 方式
    mybatis list映射
    idea使用插件mybatis-generator-plus生成mapper文件(mysql亲测可用)
    Element-UI树形表格
    Mysql5.7版本ERROR 1055问题
    为DISTINCT、GROUP BY和ORDER BY效率问题提提速
  • 原文地址:https://www.cnblogs.com/httpcc/p/15559025.html
Copyright © 2011-2022 走看看