• Java 算法篇-链表的经典算法:根据值删除节点、删除倒数第 n 个节点


    🔥博客主页: 小扳_-CSDN博客
    ❤感谢大家点赞👍收藏⭐评论✍
      

     

     

     

    文章目录

            1.0 链表的创建

            2.0 链表的经典算法 - 根据值来删除节点

            2.1 根据值来删除节点 - 遍历链表来实现

            2.2 根据值来删除节点 - 递归实现

            3.0 链表的经典算法 - 删除倒数第 n 个节点

            3.1 删除倒数第 n 个节点 - 使用递归来实现

            3.2 删除倒数第 n 个节点 - 快慢指针来实现

            4.0 本篇链表的经典算法的完整实现代码


            1.0 链表的创建

            为了更好的讲解算法的具体内容,先创建好链表,实现一个带哨兵的单链表

    代码如下:

    1. import java.util.Iterator;
    2. public class List implements Iterable{
    3. private Node hand;
    4. static class Node {
    5. public int value;
    6. public Node next;
    7. public Node() {
    8. }
    9. public Node(int value, Node next) {
    10. this.value = value;
    11. this.next = next;
    12. }
    13. }
    14. public List() {
    15. hand = new Node(0,null);
    16. }
    17. @Override
    18. public Iterator iterator() {
    19. return new Iterator() {
    20. Node p = hand.next;
    21. @Override
    22. public boolean hasNext() {
    23. return p != null;
    24. }
    25. @Override
    26. public Integer next() {
    27. int value = p.value;
    28. p = p.next;
    29. return value;
    30. }
    31. };
    32. }
    33. }

            之前的篇章都有讲解过以上的每一个方法及其作用,需要了解的点击一下链接:

    Java 算法篇-深入了解单链表的反转(实现:用 5 种方式来具体实现)-CSDN博客

            2.0 链表的经典算法 - 根据值来删除节点

            介绍两种方式来实现该算法:

            一、遍历链表来实现

            二、使用递归来实现

            2.1 根据值来删除节点 - 遍历链表来实现

            实现思路为:设置两个节点分别为: o1, 一开始指向哨兵节点。o2,一开始指向头节点(也就是 哨兵节点指向的节点),想让 o2 节点往后走一步,来判断当前 o2 的节点的值是否为需要的节点,若是,则让 o1 指向 o2.next 节点,然后 o2 = o1.next  接着往后走;若不是,则让 o1 = o2 完成赋值(意味着 o1 永远跟着 o2 节点后面,o2 永远比 o1 走前一步),接着 o2 = o2.next 往后走。循环终止的条件为,当 o2 == null 就该停止了

    代码如下:

    1. //根据值来删除节点
    2. public void removeValue( List list, int value) {
    3. Node o1 = list.hand;
    4. Node o2 = list.hand.next;
    5. while (o2 != null) {
    6. if (o2.value == value) {
    7. o1.next = o2.next;
    8. o2 = o1.next;
    9. }else {
    10. o1 = o2;
    11. o2 = o2.next;
    12. }
    13. }
    14. }

            再讲个好理解的思路:把 o1 比作战场上的大部队,把 o2 比作地雷兵,每一次往前走的时候,都需要让地雷兵先去排雷,若前方没雷时,这时候 o1 紧跟着 o2 走过的路径;若前方发现雷时,需要排除掉,以此类推,直到走完。

            2.2 根据值来删除节点 - 递归实现

            实现的思路:先把需要删除节点的链表进行递归到底进行展示出来,也就是一直递归到底,然后在回归的时候,当 p == null 说明了已经到了链表的底部了,直接返回 null 就好了。需要来判断该节点的值是否需要删除:若不需要删除的节点,在回归的时候需要返回自己的节点,然后需要更新该节点的指向。若需要删除的节点,在回归的时候直接返回 下一个节点

    代码如下:

    1. private Node recursion1(Node p, int value) {
    2. if (p == null) {
    3. return null;
    4. }
    5. if (p.value == value) {
    6. return recursion1(p.next, value);
    7. }else {
    8. p.next = recursion1(p.next, value);
    9. return p;
    10. }
    11. }

    结合代码来具体的实现流程:

            

            3.0 链表的经典算法 - 删除倒数第 n 个节点

            介绍两种方式来实现该算法:

            一、使用递归来实现

            二、使用快慢指针来实现

            3.1 删除倒数第 n 个节点 - 使用递归来实现

            实现思路:先递出到底 p == null 返回 0 ,接着然后每一次回归都对当前的 i 进行 i++,再来判断是否 i == n,但是我们细想一下,我们得到了 i == n 这个要删除的节点是不是没有什么用,因此,我们实际需要找的节点是 n + 1,当 i == n + 1 时,就可以删除倒数第 n 个节点了 p.next = p.next.next 这样就删除了节点了。

    代码如下:

    1. //删除倒数第 n 个节点(递归法)
    2. public List deleteCount(List list, int n) {
    3. recursion(list.hand,n);
    4. return list;
    5. }
    6. private int recursion(Node p, int n) {
    7. if (p == null) {
    8. return 0;
    9. }
    10. int i = recursion(p.next, n);
    11. i++;
    12. if (i == n + 1) {
    13. p.next = p.next.next;
    14. }
    15. return i;
    16. }

            需要注意的是,这里一定要用带上哨兵的链表,原因是:当我要删除的节点是第一个的时候,没哨兵是完成不了这个操作的。

            3.2 删除倒数第 n 个节点 - 快慢指针来实现

            思路:先定义两个 fast、slow 快慢指针,一开的时候都指向哨兵节点,然后让 slow 先跑 n+1个节点,然后就两个指针 一起跑,循环的结束条件为: slow == null ,因为当 slow == null是,fast.next 刚好指向了要删除的节点,那么直接就用 fast.next = fast.next.next 这就把第 n 个节点删除掉了。

    代码如下:

    1. //删除倒数第n个节点(快慢指针)
    2. public List removeFastSlowPointers(List list, int n) {
    3. list.hand = fastSlowPointers(list.hand,n);
    4. return list;
    5. }
    6. private Node fastSlowPointers(Node hand, int n) {
    7. Node temp = hand;
    8. Node fast = hand;
    9. Node slow = hand;
    10. for (int i = 0; i < n + 1; i++) {
    11. slow = slow.next;
    12. }
    13. while (slow != null) {
    14. slow = slow.next;
    15. fast = fast.next;
    16. }
    17. fast.next = fast.next.next;
    18. return temp;
    19. }

            这里需要注意的是,当要删除第 1 个节点的时候,若没有哨兵节点的时候,是完成不了这个操作的。还有需要注意的是,关于要删除第 n 个节点,实际要找到第 n+1 个节点才能对第 n 个节点进行删除。

            4.0 本篇链表的经典算法的完整实现代码

    1. import java.util.Iterator;
    2. public class List implements Iterable{
    3. private Node hand;
    4. static class Node {
    5. public int value;
    6. public Node next;
    7. public Node() {
    8. }
    9. public Node(int value, Node next) {
    10. this.value = value;
    11. this.next = next;
    12. }
    13. }
    14. public List() {
    15. hand = new Node(0,null);
    16. }
    17. @Override
    18. public Iterator iterator() {
    19. return new Iterator() {
    20. Node p = hand.next;
    21. @Override
    22. public boolean hasNext() {
    23. return p != null;
    24. }
    25. @Override
    26. public Integer next() {
    27. int value = p.value;
    28. p = p.next;
    29. return value;
    30. }
    31. };
    32. }
    33. //头插节点
    34. public void addFirst(int value) {
    35. hand.next = new Node(value,hand.next);
    36. }
    37. //尾插节点
    38. public void addLst(int value) {
    39. Node p = hand;
    40. while (p.next != null) {
    41. p = p.next;
    42. }
    43. p.next = new Node(value,null);
    44. }
    45. //根据值来删除节点
    46. public void removeValue( List list, int value) {
    47. Node o1 = list.hand;
    48. Node o2 = list.hand.next;
    49. while (o2 != null) {
    50. if (o2.value == value) {
    51. o1.next = o2.next;
    52. o2 = o1.next;
    53. }else {
    54. o1 = o2;
    55. o2 = o2.next;
    56. }
    57. }
    58. }
    59. //根据值来删除节点(递归实现)
    60. public List removeRecursion(List list ,int value) {
    61. Node p = list.hand.next;
    62. Node tp = recursion1(p,value);
    63. list.hand.next = tp;
    64. return list;
    65. }
    66. private Node recursion1(Node p, int value) {
    67. if (p == null) {
    68. return null;
    69. }
    70. if (p.value == value) {
    71. return recursion1(p.next, value);
    72. }else {
    73. p.next = recursion1(p.next, value);
    74. return p;
    75. }
    76. }
    77. //删除倒数第n个节点(递归法)
    78. public List deleteCount(List list, int n) {
    79. recursion(list.hand,n);
    80. return list;
    81. }
    82. private int recursion(Node p, int n) {
    83. if (p == null) {
    84. return 0;
    85. }
    86. int i = recursion(p.next, n);
    87. i++;
    88. if (i == n + 1) {
    89. p.next = p.next.next;
    90. }
    91. return i;
    92. }
    93. //删除倒数第n个节点(快慢指针)
    94. public List removeFastSlowPointers(List list, int n) {
    95. list.hand = fastSlowPointers(list.hand,n);
    96. return list;
    97. }
    98. private Node fastSlowPointers(Node hand, int n) {
    99. Node temp = hand;
    100. Node fast = hand;
    101. Node slow = hand;
    102. for (int i = 0; i < n + 1; i++) {
    103. slow = slow.next;
    104. }
    105. while (slow != null) {
    106. slow = slow.next;
    107. fast = fast.next;
    108. }
    109. fast.next = fast.next.next;
    110. return temp;
    111. }
    112. }

  • 相关阅读:
    航迹管理软件——SPx Track Manager
    可以从以下几点着手选择期货开户公司
    Servlet1和postman的使用
    解决在选项卡中,只有默认选项里的vue-seamless-scroll可以滚动的问题
    认识matlab
    STM32G070RBT6-MCU温度测量(ADC)
    Stm32_点灯
    单例模式详解
    在cesuim上展示二维模型
    Linux三剑客命令---grep
  • 原文地址:https://blog.csdn.net/Tingfeng__/article/details/134415598