链表与递归
一、删除链表中的元素
leetCode:删除链表元素
- 不使用虚拟头节点:需要对第一个元素进行判断
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
class Solution {
public ListNode removeElements(ListNode head, int val) {
//可能在头节点就有该元素
while(head != null && head.val == val) { //需要对首元素进行判断
ListNode delNode = head;
head = head.next;
delNode.next = null;
}
if(head == null) {
return null;
}
ListNode prev = head;
while(prev.next != null) {
if(prev.next.val == val) {
ListNode delNode = prev.next;
prev.next = delNode.next;
delNode.next=null;
}
else {
prev = prev.next;
}
}
return head;
}
}
- 使用虚拟头节点:不需要对首元素进行判断
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyhead = new ListNode(-1);
dummyhead.next = head;
ListNode prev = dummyhead;
while(prev.next != null) {
if(prev.next.val == val) {
ListNode delNode = prev.next;
prev.next = delNode.next;
delNode.next=null;
}
else {
prev = prev.next;
}
}
return dummyhead.next;
}
}
- 创建测试用例
package cn.itcast.day4;
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
//使用arr为参数,创建一个链表,当前的ListNode为链表头节点
public ListNode(int[] arr) {
if(arr == null || arr.length ==0) {
throw new IllegalArgumentException("错误");
}
this.val = arr[0];
/* 在一个类的内部,也可以使用this代表自身类的对象,或者换句话说,
每个类内部都有一个隐含的成员变量,该成员变量的类型是该类的类型,
该成员变量的名称是this,实际使用this代表自身类的对象的示例代码如下:*/
ListNode cur = this; // 使用this代表自身类的对象
for(int i=1;i<arr.length;i++) {
cur.next = new ListNode(arr[i]);
cur = cur.next;
}
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
ListNode cur = this;
while(cur!=null) {
res.append(cur.val+"->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
}
二、递归
- 将原问题转化为更小的同一问题
- 利用递归解决链表中删除元素的问题
- 代码实现:
package cn.itcast.day4;
public class Solution3 {
public ListNode removeElements(ListNode head, int val) {
if(head == null) {
return null;
}
ListNode res = removeElements(head.next,val);
if(head.val == val) {
return res;
}else {
head.next = res;
return head;
}
}
public static void main(String[] args) {
int[] nums = new int[] {1,2,6,3,4,5,6};
ListNode head = new ListNode(nums);
System.out.println(head);
ListNode res = (new Solution()).removeElements(head, 6);
System.out.println(res);
}
}
链表删除元素递归操作的逻辑:
- 递归函数的微观解读
- 递归算法的调试 — > 打印输出
package cn.itcast.day4;
public class Solution3 {
public ListNode removeElements(ListNode head, int val,int depth) {
String depthString = generateDepthString(depth);
System.out.print(depthString);
System.out.println("Call:remove "+val +" in " + head);
if(head == null) {
System.out.print(depthString);
System.out.println("Return: "+ head);
return null;
}
ListNode res = removeElements(head.next,val,depth+1);
System.out.print(depthString);
System.out.println("After remove "+ val+":" +res);
ListNode ret;
if(head.val == val) {
ret = res;
}else {
head.next = res;
ret = head;
}
System.out.print(depthString);
System.out.println("Return: "+ret);
return ret;
}
private String generateDepthString(int depth) {
StringBuilder res = new StringBuilder();
for(int i=0;i<depth;i++) {
res.append("--");
}
return res.toString();
}
public static void main(String[] args) {
int[] nums = new int[] {1,2,6,3,4,5,6};
ListNode head = new ListNode(nums);
System.out.println(head);
ListNode res = (new Solution3()).removeElements(head, 6,0);
System.out.println(res);
}
}
// 输出
1->2->6->3->4->5->6->NULL
Call:remove 6 in 1->2->6->3->4->5->6->NULL
--Call:remove 6 in 2->6->3->4->5->6->NULL
----Call:remove 6 in 6->3->4->5->6->NULL
------Call:remove 6 in 3->4->5->6->NULL
--------Call:remove 6 in 4->5->6->NULL
----------Call:remove 6 in 5->6->NULL
------------Call:remove 6 in 6->NULL
--------------Call:remove 6 in null
--------------Return: null
------------After remove 6:null
------------Return: null
----------After remove 6:null
----------Return: 5->NULL
--------After remove 6:5->NULL
--------Return: 4->5->NULL
------After remove 6:4->5->NULL
------Return: 3->4->5->NULL
----After remove 6:3->4->5->NULL
----Return: 3->4->5->NULL
--After remove 6:3->4->5->NULL
--Return: 2->3->4->5->NULL
After remove 6:2->3->4->5->NULL
Return: 1->2->3->4->5->NULL
1->2->3->4->5->NULL
三、其他关于链表的问题
- 双链表
同样也可以使用虚拟头节点来解决。 - 循环链表,同样可以使用虚拟头节点,令尾节点不指向空,而是指向这个虚拟头节点