前提须知:
顺序表的简单介绍_明 日 香的博客-CSDN博客
顺序表的缺点:
- 从之前的博客中,我们得知,顺序表的本质实际上是一种数组。
- 而数组的最大特征就是连续的空间。
- 也因此,在线性表中,顺序表是一种物理上和逻辑上都连续的直线。
但是因为物理意义上的连续,顺序表有着众多的不便之处:
- 空间的浪费和多余
- 开辟空间时,所在空间的结余不多,会出现重新开辟和拷贝数据的操作,具体参考realloc函数调整空间的操作,realloc-CSDN博客
链表:
- 因为顺序表的不足之处,从而产生了链表。
- 链表在线性表中,是一个逻辑上连续,但是物理上并不连续的结构。
- 链表实质上是由多个节点,依次链接构成的一个类火车车厢的结构类型,每一个节点都是独立存在的。
图例:
- 如图所示,plist就如同火车的车头,车头连接着车厢,这个链接点是靠车头内的地址来进行指引的。
- 同样,车厢和车厢之间也是靠着地址进行联系。
- 而地址,是需要存储在指针中才会起到链接作用。
- 所以,每一个节点分为了两个部分,一个是需要进行存储的数据,一个是指向下一个节点的指针,这个指针中存储的是下一个节点的地址!
单链表的创建:
- 与其说是单链表的创建,不如说是单链表的节点的创建。
- 如图,data是存储节点的数据,next是节点结构体类型,指向的是下一个节点,存储是下一个节点的地址。
- 同时注意,因为我们为了之后的方便,对节点结构体进行了重命名操作,但是在节点结构体成员中,指向下一个节点的指针 这个成员的类型,不能使用重命名后的结构体名字作为类型。
创建几个节点组成一个链表,并打印链表
在创建节点和打印节点之前,我们要创造一个 “火车车头”
SLNode*phead就是火车车头,它指向的是第一个节点,所以它是指针,其中SLNode*则是指针的类型,因为节点是结构体类型的。
头文件部分: (打印函数头文件部分)
打印部分:
打印部分的关键在于循环遍历,因此使用循环结构
而循环结构的判定关键在于下一个节点是否存在,这与链表的结构有着密切的关系。
如图我们得知,链表结束的标志其实就是是否存在下一个节点,而判断下一个节点是否存在就是看节点内,指向下一个节点的指针指向的是否是NULL
而同时,循环遍历的关键也是寻找下一个节点是否存在,如若存在,变需要将当前指针变为下一个节点中的指针,指向更后面的节点。
- 因为指针需要进行更变,从指向当前节点的指针,变为指向下一个节点的指针,且为了进行循环,所以这就需要pcur= pcur->next
主函数部分:
数据的插入:
相比于顺序表,链表的每一个节点都是单独存在的,所以直接使用malloc对内存进行空间的申请
指针的插入:
- data是指向节点中的数据
- next是节点中,指向下一个节点的指针
“火车头的安装”和打印函数的调用:
需要对火车头进行存放第一个节点的地址!
打印效果:
前提注意:
操作中的调用函数里面的 最开始的 形参中的指针变量 其实指向的是“火车头”
尾插:
- 本质上,尾插操作就是向内存申请空间,然后存入数据和指向下一个节点的指针,以及将自己的地址交给上一个节点。
- 但是,尾插也分为两种情况。
- 第一种便是当前的链表为空,这时就直接将自己新开辟的空间地址交予火车头即可
- 第二种便是链表不为空,这时我们需要寻找当前链表最后面一个节点内部的指向下一个节点的指针,将其从NULL变为新开辟空间的地址。
但是!无论是第一种情况还是第二种情况,我们都需要向内存申请一个空间,进行存放我们需要插入的数据所以我们再次之前创建一个开辟空间的函数,在尾插函数中进行调用
开辟空间函数:
- x表示插入的数据
- node表示当前空间的地址,或者说是当前空间结构体的变量名
- 将指向下一个空间的指针变为NULL
- 同时最后返回当前空间的地址,以便尾插的操作
注意事项:
- 在进行尾插操作之前,还需要注意一点,别被指针变量迷惑!
- 因为我们要改变的是指针变量内部的 节点内的 指针的地址内容 ,而地址内容被一层指针包裹,所以!这里需要使用的是二级指针!
头文件:
源文件:
- 当为链表空时,直接将新开辟的空间地址交给“火车头” (SLNdoe**PPhead)
- 不为空的时候,需要进行遍历循环操作,找到最后一个节点的指向下一个节点的指针,然后传给这个指针新开辟的地址。