链表与递归
链表元素删除问题的解答
问题描述:在链表[1, 2, 6, 3, 4, 5, 6] 中删除值为 6 的元素
-
ListNode.java结构说明public class ListNode { int val; ListNode next; ListNode(int x) {val = x;} /** * 链表节点构造函数,自定义 * @param arr */ ListNode(int[] arr) { if (arr == null || arr.length == 0) { throw new IllegalArgumentException("arr can not be empty"); } this.val = arr[0]; ListNode cur = this; for (int i = 1; i < arr.length; i++) { cur.next = new ListNode(arr[i]); cur = cur.next; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); ListNode cur = this; while (cur != null) { sb.append(cur.val).append(" -> "); cur = cur.next; } sb.append("NULL"); return sb.toString(); } } -
常规方式,对链表的三个部分[头、中、尾]进行分别处理
public ListNode removeElement(ListNode head, int val) { // 链表头部节点删除 while (head != null && head.val == val) head = head.next; // 链表尾部节点删除 if (head == null) { return null; } // 链表中间部分节点删除 ListNode prev = head; while (prev.next != null) { if (prev.next.val == val) prev.next = prev.next.next; else prev = prev.next; } return head; } } -
虚拟头结点方式,使得每个链表节点均含有前置节点,改进代码
public ListNode removeElement(ListNode head, int val) { // 建立虚拟头结点,保证链表中每一个节点前面均有节点 ListNode dummyHead = new ListNode(-1); dummyHead.next = head; // 链表节点删除 ListNode prev = dummyHead; while (prev.next != null) { if (prev.next.val == val) prev.next = prev.next.next; else prev = prev.next; } return dummyHead.next; } -
测试一下!
public static void main(String[] args) { int[] arr = {1, 2, 6, 3, 4, 5, 6}; ListNode res = new ListNode(arr); System.out.println(res); new Solution2().removeElement(res, 6); System.out.println(res); } ------------------------------------------ 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> NULL 1 -> 2 -> 3 -> 4 -> 5 -> NULL
递归:计算机中的很重要的组件逻辑机制
-
本质上,将原来的问题,转化为更小的同一问题,比如数组求和!
SUM(arr[0...n-1]) = arr[0] + SUM(arr[1...n-1])SUM(arr[1...n-1]) = arr[1] + SUM(arr[2...n-1])SUM(arr[n-1...n-1]) = arr[n-1] + SUM(arr[]) = arr[n-1] + 0 -
递归算法的组成
求解最基本的问题把原问题转化成更小的问题
-
链表具有递归性质
- 链表可以理解为多个节点的连接体,也可以看做
一个节点和一个链表的连接体。 - 而
NULL也是是一个最基本的链表。 - 为了方便理解,画了一张图!

- 根据图,我们可以改写代码!
public ListNode removeElementNew(ListNode head, int val) { // 基础问题 one if (head == null) { return null; } // 处理子链表,分解问题 two head.next = removeElementNew(head.next, val); // 处理结果,若当前返回子链表满足条件,便跳过节点 three return head.val == val ? head.next : head; }- 举个栗子,现在有链表
1, 2, 3,想要删除元素2上述方法是怎么执行的呢?step1入参【1, 2, 3】 以 1 为头结点的链表onehead != nulltwohead.next = ? ,进入第一次递归,step2
step2入参【2, 3】 以 2 为头结点的链表onehead != nulltwohead.next = ?,进入第二次递归,step3
step3入参【3】以3 为头结点的链表onehead != nulltwohead.next = ? ,进入第三次递归,step4
step4入参【NULL】,NULL 链表onehead == null,返回null,基本问题出现了!!!
step5回到step3 twotwohead.next = 【null】threehead.val == 2? head.next : head- return head ,此时链表为【3】,回到
step2 two
step6回到step2 twotwohead.next = 【3】threehead.val == 2? head.next : head,此时条件满足,为true- return head.next,此时链表为【3】,回到
step1 two
step7回到step1 twotwohead.next = 【3】threehead.val == 2? head.next : head- return head,此时链表为【1, 3】,回到
step1,已经执行完了one、two、three,方法返回,结束。
- 链表可以理解为多个节点的连接体,也可以看做
-
递归调用时有代价的:函数调用 + 系统栈空间(记录当前执行位置、变量状态、时间消耗),若不处理基础问题,即没有递归出口,方法执行一直占内存,直到内存占满,或溢出,导致系统over了。一个算法必须总是在有限次的执行后结束,且每一步都能在有限时间内完成。
本文深入解析链表删除操作的实现,包括常规方法与虚拟头结点优化,同时探讨递归在链表处理中的应用,通过实例展示递归算法的逻辑与执行流程。
1298

被折叠的 条评论
为什么被折叠?



