05.递归

递归

本质上,将原来的问题,转换为更小的同一问题

递归非常适合解决树类型的问题

递归:
求解最基本的问题
把原问题转换成更小的问题
注意递归函数的“宏观语义”
递归函数就是一个函数,完成一个功能。

利用递归求数组的和
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);
    }
}

链表的其他变形

  1. Linked List Problems 18个问题的描述

  2. 双向链表+虚拟头节点

class Node {
    E e;
    Node next, prev;
}

  1. 作业!利用递归实现增删改查:
    循环双向链表(双向+虚拟头+尾部指向虚拟头节点====java链表的实现)
public class datastructure.linkedList.CircleNodeList {
    // 递归实现带有虚拟头节点的双向循环链表
    // 内部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 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);
    }
}

提供了增加,删除的功能

  1. 数组链表(记录索引)

你可能感兴趣的:(05.递归)