Linked lists and recursion
The answer to the problem of deleting linked list elements
Problem description: Delete the element with value 6 in the linked list [1, 2, 6, 3, 4, 5, 6]
-
ListNode.java
Structure descriptionpublic 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(); } }
-
In the conventional way, the three parts [head, middle, and tail] of the linked list are processed separately
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; } }
-
The virtual head node method makes each linked list node contain a pre-node, improving the code
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; }
-
have a test!
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
Recursion: a very important component logic mechanism in computers
-
Essentially, the original problem is transformed into a smaller same problem, such as the sum of arrays!
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
-
The composition of the recursive algorithm
求解最基本的问题
把原问题转化成更小的问题
-
Linked lists are recursive
- Linked list can be understood as a connection body of multiple nodes, and can also be regarded as
一个节点和一个链表
a connection body. - It is
NULL
also the most basic linked list. - In order to facilitate understanding, I drew a picture!
- According to the picture, we can rewrite the code!
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; }
- For example, now there is a linked list
1, 2, 3
, and I want to delete an element.2
How is the above method performed?step1
Enter [1, 2, 3] a linked list with 1 as the head nodeone
head != nulltwo
head.next =?, enter the first recursion,step2
step2
Enter [2, 3] a linked list with 2 as the head nodeone
head != nulltwo
head.next =?, enter the second recursion,step3
step3
Entry [3] Linked list with 3 as the head nodeone
head != nulltwo
head.next =?, enter the third recursion,step4
step4
Input parameter [NULL], NULL linked listone
head == null , returnnull
, the basic problem has appeared! ! !
step5
Back tostep3 two
two
head.next = 【null】three
head.val == 2? head.next : head- return head , now the linked list is [3], return
step2 two
step6
Back tostep2 two
two
head.next = 【3】three
head.val == 2? head.next : head,此时条件满足,为true
- return head.next , now the linked list is [3], return
step1 two
step7
Back tostep1 two
two
head.next = 【3】three
head.val == 2? head.next : head- head return , this time the list is [1, 3], back
step1
, has been carried overone
, ,two
,three
the method returns, ends.
- Linked list can be understood as a connection body of multiple nodes, and can also be regarded as
-
Recursive calls come at a cost: function call + system stack space (recording the current execution position, variable status, and time consumption). If the basic problem is not dealt with, that is, there is no recursive exit, the method execution will occupy memory until the memory is full or overflow , Causing the system to over. An algorithm must always end after a limited number of executions, and each step can be completed in a limited time.