递归
本质上,将原来的问题,转换为更小的同一问题
递归非常适合解决树类型的问题
递归:
求解最基本的问题
把原问题转换成更小的问题
注意递归函数的“宏观语义”
递归函数就是一个函数,完成一个功能。
利用递归求数组的和
datastructure.linkedList.Sum
public class datastructure.linkedList.Sum {
public static int sum(int[] arr){
return sum(arr, 0);
}
private static int sum(int[] arr, int l){
if(l == arr.length){
return 0;
}
return arr[l] + sum(arr, l + 1);
}
public static void main(String[] args){
int[] nums = {1, 2, 3, 4, 5, 6, 7, 8};
System.out.println(sum(nums));
}
}
链表的天然递归特性
datastructure.linkedList.ListNode
public class datastructure.linkedList.ListNode {
// leetcode中提供的节点,不能改变
int val;
datastructure.linkedList.ListNode next;
datastructure.linkedList.ListNode(int x) { val = x;}
public datastructure.linkedList.ListNode(int[] arr){
if(arr.length == 0){
throw new IllegalArgumentException("arr can not be empty!");
}
// 执行了构造函数后,this就是头节点!
this.val = arr[0];
datastructure.linkedList.ListNode cur = this;
for(int i = 1; i < arr.length; i ++){
cur.next = new datastructure.linkedList.ListNode(arr[i]);
cur = cur.next;
}
}
@Override
public String toString(){
StringBuilder str = new StringBuilder();
str.append("head: ");
datastructure.linkedList.ListNode pre = this;
while(pre != null){
str.append(pre.val + "->");
pre = pre.next;
}
str.append("null");
return str.toString();
}
}
datastructure.linkedList.Solution3
public class datastructure.linkedList.Solution3 {
// 利用递归的思路解决链表中删除值的节点。
// 递归将问题分解成很小很小的一个可以重复执行的步骤。抽离出来
public static datastructure.linkedList.ListNode removeElements(datastructure.linkedList.ListNode head, int val){
// 返回当前的头结点
// 最小规模的情况求解
if(head == null){
return null;
}
// 宏观语义上的解决了后续的删除了所有指定了的值
head.next = removeElements(head.next, val);
// 处理当前为head下所有的情况。
return head.val == val? head.next:head;
}
public static void main(String[] args){
int[] nums = {1, 2, 4, 6, 4, 3, 2, 6, 8, 9};
datastructure.linkedList.ListNode head = new datastructure.linkedList.ListNode(nums);
System.out.println(head);
datastructure.linkedList.ListNode res = datastructure.linkedList.Solution3.removeElements(head, 2);
System.out.println(res);
}
}
链表的其他变形
Linked List Problems 18个问题的描述
双向链表+虚拟头节点
class Node {
E e;
Node next, prev;
}
- 作业!利用递归实现增删改查:
循环双向链表(双向+虚拟头+尾部指向虚拟头节点====java链表的实现)
public class datastructure.linkedList.CircleNodeList<E> {
// 递归实现带有虚拟头节点的双向循环链表
// 内部Node节点
private class Node{
public E e;
Node prev, next;
// 创建一个新的节点
public Node(E e, Node prev, Node next){
this.e = e;
this.prev = prev;
this.next = next;
}
// 专门创造一个虚拟头节点
public Node(){
this(null, null, null);
}
}
private Node dommyHead;
private int size;
// 虚拟头节点所在的位置就是0,第一个元素所在的位置就是1,以此类推
// 创建构造函数的时候将引用指向自己
public datastructure.linkedList.CircleNodeList(){
this.dommyHead = new Node();
this.dommyHead.prev = this.dommyHead;
this.dommyHead.next = this.dommyHead;
size = 0;
}
// 添加节点
public void add(E e, int index){
if(index <= 0 || index > size + 1)
throw new IllegalArgumentException("Add failed, index is illegality");
if(index <= size / 2){
// 正向递归
addRecursionForwardDirection(e, index, dommyHead);
} else {
// 反向递归
addRecursionReverseDirection(e, size - index + 1, dommyHead);
}
}
// 添加:正向递归遍历
private void addRecursionForwardDirection(E e, int n, Node pre){
if(n == 1){
Node cur = new Node(e, pre, pre.next);
pre.next = cur;
cur.next.prev = cur;
size++;
} else {
addRecursionForwardDirection(e,n - 1, pre.next);
}
}
// 添加:反向递归遍历,注意,size是将节点添加完之后才+1的
private void addRecursionReverseDirection(E e, int n, Node next){
if(n == 0){
Node cur = new Node(e, next.prev, next);
next.prev.next = cur;
next.prev = cur;
size++;
} else {
addRecursionReverseDirection(e,n - 1, next.prev);
}
}
// 添加头
public void addFirst(E e){
// 调用正向递归
add(e, 1);
}
// 添加到尾部
public void addLast(E e){
// 调用反向递归
add(e, size + 1);
}
// 删除特定节点
public E remove(int index){
if(index <= 0 || index > size)
throw new IllegalArgumentException("Remove failed, Illegality index");
if(index <= size / 2){
// 正向遍历
return removeRecursionForwardDirection(index ,dommyHead);
} else {
// 反向遍历,删除节点的反向逻辑与添加的反向逻辑有点不同。
// 添加是插队!,删除是出队(size - index + 1 与不加1的区别)!
return removeRecursionReverseDirection(size - index, dommyHead);
}
}
// 正向删除
private E removeRecursionForwardDirection(int n, Node pre){
if(n == 1){
Node cur = pre.next;
pre.next = cur.next;
cur.next.prev = pre;
size--;
return cur.e;
} else {
return removeRecursionForwardDirection(n - 1, pre.next);
}
}
// 反向删除
private E removeRecursionReverseDirection(int n, Node next){
if(n == 0){
Node cur = next.prev;
next.prev = cur.prev;
cur.prev.next = next;
size--;
return cur.e;
}
else {
return removeRecursionReverseDirection(n - 1, next.prev);
}
}
// 删除第一个
public E removeFirst(){
return remove(1);
}
// 删除最后一个
public E removeLast(){
return remove(size);
}
// 删除特定值的所有节点,n 代表递归深度
public void removeAll(E e){
removeSpecial(dommyHead.next, e);
}
// 递归删除特定值的所有节点
private void removeSpecial(Node cur, E e){
if(cur != dommyHead){
if(cur.e == e){
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
size--;
}
removeSpecial(cur.next, e);
}
}
@Override
public String toString(){
if(size == 0)
throw new IllegalArgumentException("error , empty");
StringBuilder str = new StringBuilder();
str.append("dommyHead->");
Node pre = dommyHead.next;
for(int i = 0; i < size; i++){
str.append("<-" + pre.e + "->");
pre = pre.next;
}
str.append("<-dommyHead");
return str.toString();
}
public static void main(String[] args){
datastructure.linkedList.CircleNodeList<Integer> circ = new datastructure.linkedList.CircleNodeList<>();
circ.addLast(1);
circ.addFirst(2);
circ.addLast(3);
circ.addFirst(4);
circ.addLast(4);
circ.addFirst(4);
circ.addLast(3);
circ.addFirst(3);
circ.addLast(4);
circ.addFirst(4);
System.out.println(circ);
circ.removeAll(4);
System.out.println(circ);
}
}
提供了增加,删除的功能
- 数组链表(记录索引)