递归算法学习(数据结构中的二叉树)

递归算法的学习:

递归算法的学习:

递归的终止条件和递归的过程

二叉树的增删改查的算法

二叉树的四种遍历

递归算法的leetcode练习题目:



递归的终止条件和递归的过程

二叉树的增删改查的算法

/**
 * Copyright (C), 2018-2020
 * FileName: BinaryTree
 * Author:   xjl
 * Date:     2020/3/25 17:10
 * Description: 二叉树
 */
package Tree;

import Queue.QueueLink;

public class BinaryTree<Key extends Comparable<Key>, Value> {
    //成员变量
    //记录的是更根节点
    private Node root;//这里是表示的根节点
    //节点的个数
    private int N;

    //表示二叉树中的一个节点
    private class Node<Key, Value> {
        //存储键
        public Key key;
        //存储的值
        public Value value;
        //左节点
        public Node left;
        //右节点
        public Node right;

        public Node(Key key, Value value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }

    //构造函数
    public BinaryTree() {
        this.N = 0;
    }

    //成员函数
    public int size() {
        return N;
    }

    //向树中的插入键值对
    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    //给指定的数中添加键值对key-value 并返回添加后的新树    传递给的插上是当前的额这个节点 和需要插入的键值
    // 要插入的是key-value
    public Node put(Node x, Key key, Value value) {
        //子树为空 新建这个节点并返回这个节点作为树的根节点
        if (x == null) {
            N++;
            return new Node(key, value, null, null);
        }
        //子树不为空
        //比较节点的键值和插入的key的大小
        int crp = (int) key.compareTo((Key) x.key);// key的大于节点的值
        if (crp > 0) {
            //key>x.key x表示的是节点 插入的值比节点值大 那就应该是放置在右边的这个地方
            //x.right=put(x.right,key,value) 表示的是去插入到想 x的右节点?
            x.right = put(x.right, key, value);
        } else if (crp < 0) {
            //如果key<x的节点的值 x 是表示节点的值 则方式在左节点的地方.则继续找左子树
            //x.left=put(x.left,key,value) 表示的是插入到x的左节点
            x.left = put(x.left, key, value);
        } else {
            //如果key=x的节点的值 替换原理的值便 这里其实这是没有改变的。
            x.value = value;
        }
        return x;
    }

    //在树中查询的key值
    public Value get(Key key) {
        return get(root, key);
    }

    //在指定的数中的查询方法
    public Value get(Node x, Key key) {
        //分x为null
        if (x == null) {
            return null;
        }
        //分为x不为null
        //比较key的值
        int crp = key.compareTo((Key) x.key);
        if (crp > 0) {
            //如果是key大于节点的key 这找到右子树 x.right 表示的x的整个右边的节点
            return (Value) get(x.right, key);
        } else if (crp < 0) {
            //如果是key小于节点的key 这找到左子树
            return (Value) get(x.left, key);
        } else {
            //如果等于key的的返回这个value
            return (Value) x.value;
        }
    }

    //删除该树中的key的value的值
    public void delete(Key key) {
        delete(root, key);
    }

    //删除指定树中的key的value的值 并返回这个删除后的树 那应该是返回的是根节点的值
    public Node delete(Node x, Key key) {
        //x树为null
        if (x == null) {
            return null;
        }
        //x树不为null
        int cmp = key.compareTo((Key) x.key);
        if (cmp > 0) {
            //如果是key大于节点的key 这找到右子树 x.right 表示的x的整个右边的节点
            x.right = delete(x.right, key);
        } else if (cmp < 0) {
            //如果是key小于节点的key 这找到左子树
            x.left = delete(x.left, key);
        } else {
            //让元素个数减少
            N--;
            //如果等于key的的x的键的时候,那么就需要完成是的是删除这个节点的操作
            //找到右子树中的小的节点
            if (x.right == null) {
                return x.left;
            }
            if (x.right == null) {
                return x.right;
            }
            //找到右子树的最小的节点
            Node minnode = x.right;
            while (minnode.left != null) {
                minnode = minnode.left;
            }
            //删除右子树的最小的点
            Node n = x.right;
            while (n.left != null) {
                if (n.left.left != null) {
                    //断开节点
                    n.left = null;
                } else {
                    //变换节点为下一个就可以
                    n = n.left;
                }
            }
            //让x的节点的左子树minnode的左子树
            minnode.left = x.left;
            //让x的节点的右子树minnode的右子树
            minnode.right = x.right;
            //让x的节点的父节点指向minnode
            x = minnode;
        }
        return x;
    }

    //查找树的最小的键 就会一直找到左边的值 然后在这个节点 并返回这个
    public Key minkey() {
        return (Key) minNode(root).key;
    }

    //查找树的最小的键对应的值 就会一直找到左边的值 然后在这个节点 并返回这个
    public Value minValue() {
        return (Value) minNode(root).value;
    }

    //找到最小的键在节点
    public Node minNode(Node x) {
        if (x.left != null) {
            return minNode(x.left);
        } else {
            return x;
        }
    }

    public Key maxkey() {
        return (Key) minNode(root).key;
    }

    //查找树的最大的键对应的值 就会一直找到左边的值 然后在这个节点 并返回这个
    public Value maxValue() {
        return (Value) minNode(root).value;
    }

    //找到最大的键在节点
    public Node maxNode(Node x) {
        if (x.right != null) {
            return maxNode(x.right);
        } else {
            return x;
        }
    }

    /**
     * //二叉树的遍历的方式
     * @return
     */
    //前序遍历
    //获取整个树的键
    public QueueLink<Key> preErgodic() {
        QueueLink<Key> keys = new QueueLink<>();
        preErgodic(root, keys);
        return keys;
    }

    //获取指定的数x的所有的键,并放置在keys中
    private void preErgodic(Node x, QueueLink<Key> keys) {
        //如果树为空的话
        if (x == null) {
            return;
        }
        //如果树不为空的话 将节点的key记性入队的操作
        keys.push((Key) x.key);
        if (x.left != null) {
            //如果左子树不为空则 将递归左子树
            preErgodic(x.left, keys);
        }
        if (x.right != null) {
            //如果右子树不为空则 将递归右子树
            preErgodic(x.right, keys);
        }
    }

    //中序遍历
    //获取整个树的键
    public QueueLink<Key> midErgodic() {
        QueueLink<Key> keys = new QueueLink<>();
        midErgodic(root, keys);
        return keys;
    }

    //获取指定的数x的所有的键,并放置在keys中
    private void midErgodic(Node x, QueueLink<Key> keys) {
        //如果树为空的话
        if (x == null) {
            return;
        }
        //将左子树的放置
        if (x.left != null) {
            midErgodic(x.left, keys);
        }
        //将当前子树的放置
        keys.push((Key) x.value);
        //将右子树的放置
        if (x.right != null) {
            midErgodic(x.right, keys);
        }
    }

    //后序遍历
    //获取整个树的键
    public QueueLink<Key> afterErgodic() {
        QueueLink<Key> keys = new QueueLink<>();
        afterErgodic(root, keys);
        return keys;
    }

    private void afterErgodic(Node x, QueueLink<Key> keys) {
        //如果树为空的话
        if (x == null) {
            return;
        }
        //将左子树的放置
        if (x.left != null) {
            afterErgodic(x.left, keys);
        }
        //将右子树的放置
        if (x.right != null) {
            afterErgodic(x.right, keys);
        }
        //将当前子树的放置
        keys.push((Key) x.value);
    }

    //层序遍历的方法
    public QueueLink<Key> layerErgodic() {
        //定义两个队列
        QueueLink<Key> keys = new QueueLink<>();
        QueueLink<Node> nodes = new QueueLink<>();
        nodes.push(root);
        while (!nodes.isEmpty()) {
            //从队列中的弹出节点 把节点中的key放置keys中
            Node node = nodes.pop();
            keys.push((Key) node.key);
            //判断当前节点有没有左边的节点 如果有 则放入到nodes中
            if (node.left != null) {
                nodes.push(node.left);
            }
            //判断当前的节点有没有右节点  如果有 则放入到nodes中
            if (node.right != null) {
                nodes.push(node.right);
            }
        }
        return keys;
    }

    //获取整个树的最大深度
    public int maxDepth() {
        return maxDepth(root);
    }

    //获取指定树的深度
    private int maxDepth(Node x) {
        if (x == null) {
            return 0;
        }
        //x的最大深度
        int max = 0;
        //左子树的最大深度
        int maxl = 0;
        //右子树的最大深度
        int maxr = 0;
        //计算左子树的最大深度
        if (x.left != null) {
            maxl = maxDepth(x.left);
        }
        //计算右子树的最大深度
        if (x.right != null) {
            maxr = maxDepth(x.right);
        }
        //比较左字树和右子树的最大的深度 在加1就可以满足既可以
        max = maxl > maxr ? maxl + 1 : maxr + 1;
        return max;
    }

}

二叉树的四种遍历

//前序遍历
    //获取整个树的键
    public QueueLink<Key> preErgodic() {
        QueueLink<Key> keys = new QueueLink<>();
        preErgodic(root, keys);
        return keys;
    }

    //获取指定的数x的所有的键,并放置在keys中
    private void preErgodic(Node x, QueueLink<Key> keys) {
        //如果树为空的话
        if (x == null) {
            return;
        }
        //如果树不为空的话 将节点的key记性入队的操作
        keys.push((Key) x.key);
        if (x.left != null) {
            //如果左子树不为空则 将递归左子树
            preErgodic(x.left, keys);
        }
        if (x.right != null) {
            //如果右子树不为空则 将递归右子树
            preErgodic(x.right, keys);
        }
    }

    //中序遍历
    //获取整个树的键
    public QueueLink<Key> midErgodic() {
        QueueLink<Key> keys = new QueueLink<>();
        midErgodic(root, keys);
        return keys;
    }

    //获取指定的数x的所有的键,并放置在keys中
    private void midErgodic(Node x, QueueLink<Key> keys) {
        //如果树为空的话
        if (x == null) {
            return;
        }
        //将左子树的放置
        if (x.left != null) {
            midErgodic(x.left, keys);
        }
        //将当前子树的放置
        keys.push((Key) x.value);
        //将右子树的放置
        if (x.right != null) {
            midErgodic(x.right, keys);
        }
    }

    //后序遍历
    //获取整个树的键
    public QueueLink<Key> afterErgodic() {
        QueueLink<Key> keys = new QueueLink<>();
        afterErgodic(root, keys);
        return keys;
    }

    private void afterErgodic(Node x, QueueLink<Key> keys) {
        //如果树为空的话
        if (x == null) {
            return;
        }
        //将左子树的放置
        if (x.left != null) {
            afterErgodic(x.left, keys);
        }
        //将右子树的放置
        if (x.right != null) {
            afterErgodic(x.right, keys);
        }
        //将当前子树的放置
        keys.push((Key) x.value);
    }

    //层序遍历的方法
    public QueueLink<Key> layerErgodic() {
        //定义两个队列
        QueueLink<Key> keys = new QueueLink<>();
        QueueLink<Node> nodes = new QueueLink<>();
        nodes.push(root);
        while (!nodes.isEmpty()) {
            //从队列中的弹出节点 把节点中的key放置keys中
            Node node = nodes.pop();
            keys.push((Key) node.key);
            //判断当前节点有没有左边的节点 如果有 则放入到nodes中
            if (node.left != null) {
                nodes.push(node.left);
            }
            //判断当前的节点有没有右节点  如果有 则放入到nodes中
            if (node.right != null) {
                nodes.push(node.right);
            }
        }
        return keys;
    }

递归算法的leetcode练习题目:

leetcode104 二叉树的最大深度():

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //分别获取左子树和右子树的最大的深度  然后选择其中最大的加1就可以
    public int maxDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        int leftDepth=maxDepth(root.left);
        int rightDepth=maxDepth(root.right);
        return Math.max(leftDepth,rightDepth)+1;
    }
}

111. 二叉树的最小深度

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
       if(root == null) return 0;
        //这道题递归条件里分为三种情况
        //1.左孩子和有孩子都为空的情况,说明到达了叶子节点,直接返回1即可
        if(root.left == null && root.right == null) return 1;
        //2.分别计算左孩子和右孩子     
        int m1 = minDepth(root.left);
        int m2 = minDepth(root.right);
        //这里其中一个节点为空,说明m1和m2有一个必然为0,所以可以返回m1 + m2 + 1;
        if(root.left == null || root.right == null) return m1 + m2 + 1;
        //3.最后一种情况,也就是左右孩子都不为空,返回最小深度+1即可
        return Math.min(m1,m2) + 1; 
    }
}

226. 翻转二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        //递归终止的条件
        if(root==null){
            return null;
        }
        //递归的过程是
        invertTree(root.left);
        invertTree(root.right);
        TreeNode temp=root.right;
        root.right=root.left;
        root.left=temp;
        //返回这个主节点
        return root;
    }
}

100. 相同的树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
    // p and q are both null
    if (p == null && q == null) return true;
    // one of p and q is null
    if (q == null || p == null) return false;
    if (p.val != q.val) return false;
    return isSameTree(p.right, q.right) &&isSameTree(p.left, q.left);
  }
}

101. 对称二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //或者是采用的stack的数据结构来实现这个 分别是前序遍历和后序遍历的结果是否一样
    public boolean isSymmetric(TreeNode root) {
        return isMirror(root, root);
    }
    public boolean isMirror(TreeNode t1, TreeNode t2) {
        if (t1 == null && t2 == null) return true;
        if (t1 == null || t2 == null) return false;
        return (t1.val == t2.val)&& isMirror(t1.right, t2.left)&& isMirror(t1.left, t2.right);
    }
}

112. 路径总和

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root==null){
            return false;
        }
        //递归的终止条件
        if(root.left==null&&root.right==null){
            return root.val==sum;
        }
        //递归的实现过程
        if(hasPathSum(root.left,sum-root.val)){
            return true;
        }
        if(hasPathSum(root.right,sum-root.val)){
            return true;
        }
        return false;
    }
}

404. 左叶子之和

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int result=0;
    public int sumOfLeftLeaves(TreeNode root) {
        //终止条件
        if(root==null){
            return 0;
        }
        if(root.left==null&&root.right==null){
            return 0;
        }
         //当前节点的左孩子是不是叶子节点(叶子结点:没有左右孩子)
        if(root.left != null && (root.left.left == null && root.left.right == null)){
            result +=root.left.val;
        }
        //递归条件
        sumOfLeftLeaves(root.left);
        sumOfLeftLeaves(root.right);
        return result;
    }
}

257. 二叉树的所有路径

猜你喜欢

转载自blog.csdn.net/weixin_41605937/article/details/105653171