单链表的相关知识
1.指针 == 变量
一个变量int a = 10,如果有该变量的地址指针&a,对其解引用*&a便能得到变量a,所以有指针就相当于有该指针指向的变量,有指针就等于有该变量,我们把指针和变量的关系拉近点,就看成有此指针等于有此变量
2.存储原理
我们定义一个结构体,里面存放数据和指针,如果我们有此结构体的指针(等于有此结构体),就能有它里面存放的数据和存放的指针,有它里面存放的指针(等于有此指针指向的结构体),就能有它里面存放的数据和存放的指针,有了该指针,就又有了它里面的数据和指针,直到某个节点里存放的指针为NULL时,不再有它里面再来的节点再来的数据和指针,一个链表就到尾了,我们看其效果,数据就在一个个节点里参杂着指针数据是连到了一起
3.结构
这样的里面的每一个结构体就是节点,一条链表整体全是节点,由节点组成
链表物理结构不一定连续,它节点开辟的空间可以是东一块西一块零零散散的,但可靠每一个节点里的指针将节点们都连续连到了一起,它的逻辑结构靠指针逻辑是连续的,链表是线性表
在链表的实现中,我们牢记指针==变量的关系,每一个节点指针SLTNode* node可以就把它视为每一个的节点结构体变量,当为节点指针向系统开辟好合法的内存空间给其指向后,结构体节点就等于创建出来了:
现在我们手动创建4个节点,创建好后将它们连接起来,这样我们想要的每个节点里存放的数据就都能连起来了:
单链表的实现:
现在我们设计函数设计对链表各种操作实现的函数
一、链表里存放数据的打印
1.plist:
node1是首节点节点头地址,将首节点节点头的指针地址传过来,就有了头节点结构体,此链表从头开始到尾的节点都能有
2.SLTNode* pcur = phead:
将首节点节点头地址交给pcur指针,让头节点地址在pcur变量里去遍历改变掉,phead里存的头节点地址就保存起来不去变了,就相当于把头节点地址保存有起来了
二、链表尾部插入节点
1.&plist:
传值调用:将变量里的值传过去
传址调用:将变量的地址传过去,变量的地址传过去后,对其解引用得到该变量也可得到该变量里的值,但是它是把变量的空间地址传过去,解引用修改时修改的是实参变量里的值,即传&plist即可以在函数里完成plist放头节点地址变量里值的修改
为什么要传plist的地址呢?
- 因为尾删时如果该链表只有一个节点,删除该节点后该链表头节点地址就为空了,plist里的值就得改为空了,此时传址调用就可以实现在函数里完成对此的修改,将plist里的值改为空,在函数里完成,调用结束后,plist里的值就符合实际地被改为NULL了
- 而如果是传值调用的话,修改时修改的是临时创建来接收值的形参变量里的值,而不是修改传来值的plist变量里的值,函数调用结束后,plist里装的此链表表头的地址函数实现就得把存放此链表表头地址变量改为成此时对应的链表表头地址NULL,而传值调用做不到
2.assert(pphead):
pphead是&plist,创建好的存放头节点地址的指针的地址,plist存在,plist变量是创建好的,对其取地址是不会为空的,这里的防空是防有人恶意传NULL想破坏程序的情况(因为这里后面是一定有对pphead解引用操作的),为的是增强代码的健壮性
3.SLTBuyNode(x):
往链表里插数据时,是将数据放在节点里以节点将数据插入,我们需要开辟空间创建节点,将数据放入节点,将节点插入链表
三、链表头部插入节点
四、查找数据在链表里所在的节点位置
查找某数据在链表中所在节点的位置,通过传数据去遍历链表找到该数据所在的节点并返回该节点指针,得到该数据所在的节点:
五、链表某个节点之前插入节点
1.pos:
我们传给pos的是链表里的那某个节点的指针,即数据1所在的节点指针,我们通过SLTFind来获得的
2.assert(*pphead):
函数设计的使用要求是传要插入哪个节点前的该节点指针,如果链表为空没有节点,是无法完成在那个节点位置之前插入节点的
3.assert(pos):
要在那个节点之前插入,那个节点不能不存在为NULL
六、链表某个节点之后插入节点
七、删除链表最后一个节点尾节点
八、删除链表第一个节点头节点
九、删除链表某个节点
十、删除链表某个节点之后的一个节点
assert(pos->next):
那某个节点之后的要删除的节点要存在