前言:
栗子们,动动你们可爱的小手手,给芳仔点点赞关注一下,后续继续努力给大家分享!
话不多说,我们上高速啦!
链表的概念:
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,但链表在逻辑上是连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。
链表的结构:
链表的结构是由一个一个的节点组成,具体节点样子如图所示:
注意:链表最后一个有效数据的指针指向空指针哦,所以要写成*next=NULL。 链表的结构其实和我们坐的火车一样,每届火车相当于独立申请的空间,我们称之为“节点”,只不过每个节点存储两个内容,一个是我们要存储的数据,一个就是我们要存储的下一个节点的地址,我们需要通过指针来找到下一个节点。链表相比顺序表的优点是:不需要扩容、也不会造成空间的浪费。
链表的分类:
其实在整个学习过程中,链表总共有八种,只不过我们将会深入学习两种链表,分别是:不带头单向不循环链表、带头双向循环链表。
补充说明:1.链式机构在逻辑上是连续的,在物理结构上不一定连续。2.节点一般是从堆上申请的。3.从堆上申请来的空间,是按照一定的策略分配出来的,所以每次申请的空间可能连续也可能不连续的。
链表的实现:
单向不循环链表的具体结构如图所示:
我们先创建头文件和两个源文件,SList.h,是用来定义所用到的数据类型和链表的具体要实现的操作。
而我们在头文件所要 说明链表的操作类型和链表的数据类型,完整代码如下:
注意:我们在链表的数据操作过程中,可能会多次遇到空间申请的问题,我们可以将其封装起来,方便后面使用。
一.链表的打印:
在进行链表的打印时侯,我们先重新写一个新指针pcur,用来遍历整个链表,因为要打印链表,所以呢我们当然要用到循环语句了,那么循环的条件是什么呢?循环的条件就是当我们重新定义的指针pcur不为空指针即可。具体的代码如下所示:
二.链表的尾插:
我们在进行尾插的时候,要先判断链表是否为空,然后申请空间。分为两种情况:链表为空、链表不为空。1.如果链表为空,此时我们将新插入的尾节点就是此链表的头节点。2.如果链表不为空,我们尾插的时候先遍历找到最后一个有效节点,然后将会改变最后一个尾节点指针的指向,此时最后一个尾节点的指向不再是 NULL,而是指向我们尾插的新节点newnode,而新建的尾节点指向NULL。具体代码如下:
三.链表的头插:
在进行链表的头插时,我们同样也是需要进行断言是否为空指针,不过在头插的时候,链表为空和不为空操作方法都是一样的。申请一块空间,然后改变原来的第一个有效节点,并且同时也改变了新链表的头节点。具体代码如下:
四.链表的头删:
链表的头删我们同样最先开始判断是否为空,然后将第一个有效节点释放掉,在释放掉第一个有效节点之前,我们需要先重新写一个新指针指向第一个有效节点的下一个节点,也就是*pphead-》next,这样再释放头节点,同时让第二个节点成为新的头节点。具体代码如下:
五.链表的尾删:
在进行链表的尾删时候,我们同样也是需要判断链式是否为空,接下来我们要考虑链表里面有几个有效节点,可以分为:只有一个有效节点、多个有效节点。如果只有一个有效节点,我们将其释放最后将头节点改为NULL,如果是有多个节点,我们需要先遍历链表来找尾节点,并重新写两个指针,一个记为ptail用来找尾节点,一个记为prev,用来标记尾节点的前一个节点。多个有效节点的循环条件就是ptail->next!=NULL,同时记ptail=prev,直到找到尾节点,此时prev不等于ptail,prev跳出循环,prev->next=NULL。具体代码如下:
六.链表的查找:
栗子们,学习到这我们已经完成单链表的多半路程了,加油!
链表的查找对于我们的小栗子们还是相对简单的,首先我们肯定还是要判断是不是空指针,然后遍历链表寻找我们要找的数据,我们在这重新写一个指针pcur遍历链表。具体代码如下:
七.指定位置插入数据:
在指定位置插入数据前,各位小栗子们千万不要忘记我们也要首先进行判断是否为空。然后我们再继续申请一块空间,重新写一个指针prev,遍历直到在指定位置前一个有效节点,然后将其改为prev->next=newnode,newnode->next=pos。具体代码如下所示:
八.删除指定位置节点:
删除指定位置的节点时,小栗子们不要忘记也要判断一下pos位置是否为空哦。我们将删除指定位置节点分为两种情况:在头节点处、在指定位置。如果是头节点处我们只需要进行头删即可,如果在指定位置,我们则重新写一个指针记为prev,用来遍历找到pos位置处停下,然后改变指针的指向,即prev->next=pos->next,最后释放掉pos空间即可。具体代码如下:
好啦,各位小栗子们,我们的单链表学习到此结束啦!收工咯。