在单向链表中插入节点——C语言基础

向单向链表插入节点

前言:链表的插入过程就是把新建的节点插入到已有的链表中,鉴于此种理解,也可以把链表的创建看做是一种特殊的插入节点过程,但是具体来说,链表的插入较于链表的创建来说稍复杂一些。

一、问题描述

    编写函数,将一个节点插入到一个已有学生链表中,设已有链表按学号有小到大顺序已经排列。

二、算法描述

(1) 输入数据
(2) 生成新节点
(3) 将数据存入新节点
(4) 在链表中寻找第一个大于新节点的学号

注意:该算法的难点是第四步——在链表中寻找第一个大于新节点的学号
    凡事查找类问题均存在可查找和不可查找两种情况,不可查找的原因只有一个,那就是链表是空的,可查找也分为两种情况,一是找到了,二是没找到,前者说明找到了第一个比新节点学号大的节点,至于那个结点的位置另当别论,后者说明不存在比新节点学号大的节点,具体可以罗列如下:
在这里插入图片描述

三、代码部分
1. structure.h
// Structure
// Created by Lanyan on 20/07/2021.
// JiaoZuo

#ifndef _structure_h
#define _structure_h
#include "stdio.h"

struct stu{          //定义一个包含学号和成绩的结构体
    int num;         //数据域
    float score;     //数据域
    struct stu *next;//指针域
};

#endif
2. insert.h
// insert a note into a singly linked list
// Created by Lanyan on 20/07/2021.
// JiaoZuo

#ifndef _insert_h
#define _insert_h
#include "structure.h"

struct stu *insert(struct stu *head, struct stu *stud){
    //head: the linked list
    //stud: the new note
    struct stu *p0;     //point to the new note
    struct stu *p1;     //point to the first note gather than to the student number of the new note
    struct stu *p2;     //point to the previous note of p1

    p0 = stud;      //initialization
    p1 = head;

    if(head == NULL){       //attention_1, head or p1?
        //solve situation 1
        head = p0;      //attention_2, head or p1?
        p0->next = NULL;
    }else{
        while((p1 != NULL) && (p0->num >= p1->num)){        //attention_3 p1 or head? sequence?
            //search
            //the positions of the two conditions can not be reversed
            p2 = p1;
            p1 = p1->next;
        }
        if(p1 != NULL){     //attention_4,it can be replace with p0->num < p0->num
            if(head == p1) head = p0;       //solve situation 2
            else p2->next = p0;     //solve situation 3
            p0->next = p1;
        }else{      //solve situation 4
            p2->next = p0;
            p0->next = NULL;
        }
    }
    return head;
}

#endif _insert_h
四、代码解析
1. 对于单向链表来说,插入为什么需要引入两个工具指针?

在这里插入图片描述
(1)插入的话不得不考虑插在哪里的问题,这就必须要精准查找;
(2)考虑到链表的单向性,查找过程只能从前往后,如果只用一个工具指针,即使这个指针找到了对应的节点或指向了NULL,是没法再往回退一步插入新节点的;
(3)这个代码中两个工具指针分别是p1和p2,他们的相对关系是p2始终跟在p1的后边,即p2始终指向p1前边的节点,这样就解决了无法插入新节点的问题,为了方便记忆,可以把p2看作是p1的影子。

2. 指针变量的初始化在这里插入图片描述

(1)初始化过程使p0指向要插入的节点stud,这里当然可以直接使用stud参与后续的过程,并没有什么影响,但stud是个形参,直接使用形参还是找个替代者是个人习惯问题,但我建议使用替代者,可以有效使函数的耦合性与外界降到最低;
(2)p1初始化指向head,这是因为p1要头开始查找。

3. 链表为空情况的解决(situation 1)

在这里插入图片描述

(1)开头第一句:这个链表能不能进行查找??!head == NULL 意味着这个链表是空的,无法进行查找,于是就直接把新节点作为链表的头结点,新节点的下一个结点作为NULL,这一步解决了情况1——链表为空;
(2)注释attention1:head能换成p1吗?能,只是不够直观;
(3)注释attention2:head能换成p1吗?不能,首先因为我们最终返回的是head而不是p1, 其次p1只是一个工具指针,在查找过程中会移动,p1移动后,与head没有任何关系。

4. 如果可查找,如何进行定位?在这里插入图片描述

1. 注释attention_3:p1能换成head吗?不能,p1是不断进行定位移动的,换成head就没法对移动的情况进行判断;
2. while中的两个情况判定顺序能颠倒吗?不能,先判断p1此时是不是空,非空的话再比较p1此时指定节点的学号大小,这样才有意义;
3. 如果一轮没有找到,则p1向后移动一个节点,p2也后移动一个节点,移动后的p2刚好指在p1刚才指定的节点上。

5. 从while循环跳出来的原因有哪些?

在这里插入图片描述
1.因为p0->num >= p1->num(相当于p1 != NULL)跳出循环,这说明在链表中找到了符合的节点,直接把节点插在链表中;
2. 既然找到了节点,那这个结点是头结点还是中间节点?毕竟插入方法不一样,所以要区别对待;所以代码中就分别出现了solve situation 2和solve situation 3,分别代表新节点插入作表头,新节点插入作节点;
4. 因为p1为空跳出循环,这说明p1一下子找到了链表尾也没有找到符合的节点,因此需要把节点插在链表尾,也就解决了situation 4。


以上是本次的全部内容,如果有其他部分不明白的可以参考一下我的

编译预处理——文件包含
C语言基础——单向链表的创建
顺序访问链表中的节点——C语言基础
当然,也可以在评论区留言,我一定回复。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值