目录
- 前言
- 一、移除链表中的元素(多指针法)
- 二、反转链表(多指针法&头插法)
- 三、链表的中间结点(算数法和双指针法)
- 四、链表中的第K个结点(算数法&双指针法)
- 五、合并两个有序链表(尾插法)
- 六、链表分割(尾插法)
- 七、链表的回文结构
- 八、链表相交
- 九、环形链表(一)
- 十、环形链表(二)
- 十一、复杂链表的复制:复制带随机指针的链表
前言
本文主要总结博主平时做过的链表的常见OJ题,持续更新~
一、移除链表中的元素(多指针法)
- 题目
- 提交代码:
- 提交结果:
- 思路分析:
本题主要是使用了三个指针来记录链表中的相邻三个结点,其中使用cur指针从头遍历到尾,使用prev指针随时记录cur的前一个结点,使用next随时记录cur的下一个结点。需要注意:当cur指针指向链表的第一个结点的时候,此时cur没有前一个结点,因此prev刚开始为空。在遍历的过程中,就是在不断比较cur指向的结点的值与题目给定的值是否相等,在这里就会分为两种情况,显然是cur指向的结点的值和题目给定的值是相等的,cur指向的结点的值与题目给定的值不相等。 - 当cur指向的结点的值与题目给定的值不相等的时候,此时只需要让cur指针向后走,prev同步向后走即可,这里有一个细节,在cur向后走之前一定要先将cur的值更新到prev中,否则后续prev就无法更新了。
- 当cur指向的结点的值与题目给定的值相等的时候,此时需要将cur指向的结点删除,这里又分为两种情况:prev是否为空,即删除的结点是否为第一个结点
- 当prev == NULL:此时删除的是链表中的第一个结点,在这里需要做的事情是删除第一个结点,更新头指针指向的结点到下一个结点,同时也让cur走向下一个结点,更新next,再更新next的时候一定需要注意此时cur是否为空,如果cur已经为空了,那么就不需要再更新Next了,这种情况发生在:更新cur前,cur已经指向链表的最后一个结点,那么此时Next指针就已经为空,此时更新cur指针的话,cur就为空了,所以此时不能再更新next指针,如果再更新next指针,就会在代码next - cur->next;中出现cur为空指针的情况继续访问空指针,处理方法就是由于注意到cur可能走向空,所以,再更新next指针之前需要判断cur指针是否为空
- 当prev!=NULL的时候:说明此时删除的结点不是第一个结点,那么此时需要做的事情就是删除cur指向的结点(
free(cur);
),让cur前后指向建立练习(prev->next = next;
),再更新cur和next,再更新next的时候同样需要注意cur为空的情况需要额外进行判断
二、反转链表(多指针法&头插法)
- 题目:
- 多指针法
- 提交代码:
- 提交结果:
- 思路分析:
本题采用三个指针来解决链表的反转问题,使用cur指针从头到尾遍历链表的每一个结点,使用prev指针随时记录cur指向的结点的前一个结点,使用next指针随时记录cur指针指向的结点的下一个结点,刚开始,当cur指向链表的第一个结点的时候,此时cur指向的结点没有前一个结点,此时prev = NULL;
再从头遍历到尾的过程中,我们会发现,我们只需要将cur指向前一个结点,依次到尾,就会发现链表就被反转了,迭代的过程,先保存cur结点的下一个结点,然后先将cur的值更新给prev,再更新cur为next,更新cur的时候同样需要注意cur的值是否为空,当最后依次遍历的时候,也就是遍历链表的最后一个结点的时候,更新cur的时候cur就被更新为空指针了,此时就不需要再更新next了,处理方法同样是在更新next前先判断cur的值是否已经是空指针,若是,则不需要继续更新,若不是,则再继续更新next
- 头插法(构造新链表)
提交代码
- 提交结果
- 思路分析:
本题也可以通过构造一个新链表采用头插法来解决:具体为构造一个新链表的头指针newHead,刚开始为空,使用一个cur指针遍历原来链表,使用next指针随时记录cur指针指向的结点的下一个结点随时准备更新cur,让cur指向新链表的头newHead,这样就可以不断将原链表的结点一个个连接到新链表,从而完成原链表的反转,再更新next的时候同样需要注意cur为空的情况,当遍历到原链表的最后一个结点的时候,此时next指向空,再更新cur,cur也指向了空,此时就不需要继续更新next了。
三、链表的中间结点(算数法和双指针法)
- 题目:
- 算数法
-
提交代码:
-
提交结果:
-
思路分析:
通过先计算出链表中的结点个数,再计算链表的中间结点数,通过对链表的结点个数是奇数还是偶数进行分类讨论,从而确定返回的是哪个结点作为中间结点,注意在计算链表结点个数时,count变量应该从0开始进行计算,而不能从1开始,如果从1开始,就会导致计算出的结点个数多1,因为再遍历的过程中我们是控制遍历到空的,所以上面是一种方法:count从0开始,遍历到空,也可以:count从1开始,遍历到最后一个结点。上面的两种方法的控制就是在遍历中的循环条件不同而已。对链表结点个数进行分类讨论的过程中有两种情况:链表结点个数为奇数,链表结点个数为偶数 -
当链表结点个数为奇数时:此时只有一个中间结点,先求出中间结点数mid,然后使用循环条件–mid进行控制即可,cur从头开始的情况
-
当链表结点个数为偶数时:此时链表存在两个中间结点,根据题目要求,我们需要返回的是第二个中间结点,此时求出中间结点数之后,使用循环条件mid–进行控制即可,cur从头开始的情况
-
- 双指针法
-
提交代码:
-
提交结果:
-
思路分析:
本题采用快慢指针(双指针)的方法来解决求中间结点的问题,通过中间结点大概是总结点数的两倍的关系采用快指针一次走两步,慢指针一次走一步,慢指针最终记录的就是我们所要的中间结点,这个题同样需要对结点的个数进行分类讨论,当结点个数为奇数的时候,快指针走到最后一个结点的时候,此时慢指针记录的就是中间结点,当结点个数为偶数时,链表同样存在两个中间结点,当快指针走到空的时候,此时慢指针记录的就是我们想要的中间结点,需要注意的是while(fast&&fast->next)这个循环条件中fast和fast->next的位置不能颠倒
四、链表中的第K个结点(算数法&双指针法)
题目:
- 算数法
提交代码
提交结果:
VS上测试分析
思路分析:
算数法是通过求出链表总的结点个数,再算倒数第K个结点,比如:cur从头开始,一共有5个结点,倒数第1个结点其实就是第5个结点,倒数第2个结点就是第4个结点,倒数第3个结点就是第3个结点,倒数第4个结点就是第2个结点,倒数第5个结点就是第1个结点,循环的次数,当k = 1时循环4(5-1)次找到第5个结点,当k = 2时,循环3(5-2)次找到第4个结点…,当链表中结点个数为count时,cur从头开始,找倒数第k个结点需要循环(count-k)次
五、合并两个有序链表(尾插法)
题目:
六、链表分割(尾插法)
题目:
七、链表的回文结构
题目:
八、链表相交
题目:
九、环形链表(一)
题目:
十、环形链表(二)
十一、复杂链表的复制:复制带随机指针的链表
题目: