数据结构-Java-二叉树

package tree;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author zhw
 * Version 1.0
 * @Description BinaryTree
 * Date 2021/8/16 18:13
 **/
public class BinaryTree<Key extends Comparable<Key>, Value> {
    /**
     * @Description: 记录根节点
     */
    private Node root;
    /**
     * @Description:记录树中元素的个数
     */
    private int N;

    /**
     * @Description: 内部节点类
     */
    private class Node {
        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;
        }
    }

    /**
     * @Description: 获取树中元素的个数
     * @return: int
     */
    public int size() {
        return N;
    }

    /**
     * @param key   key
     * @param value value
     * @Description: 向树中加入元素key-value
     * @return: void
     */
    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    /**
     * @param x     x
     * @param key   key
     * @param value value
     * @Description: 向指定的树x中添加key-value,并返回添加元素后新的树
     * @return: tree.BinaryTree<Key, Value>.Node
     */
    private Node put(Node x, Key key, Value value) {
        //如果x子树为空
        if (null == x) {
            N++;
            return new Node(key, value, null, null);
        }
        //如果x子树不为空
        //比较x节点的键和key的大小
        int result = key.compareTo(x.key);
        if (result > 0) {
            //如果key大于x节点的键,则继续找x节点的右子树
            x.right = put(x.right, key, value);

        } else if (result < 0) {
            //如果key小于x节点的键,则继续找x节点的左子树
            x.left = put(x.left, key, value);
        } else {
            //如果key等于x节点的值,则替换x节点的值为value即可
            x.value = value;
        }
        return x;
    }

    /**
     * @param key key
     * @Description: 查询树中指定key对应的value
     * @return: Value
     */
    public Value get(Key key) {
        return get(root, key);
    }

    /**
     * @param x   x
     * @param key key
     * @Description: 从指定的树x中,查找对应key的值
     * @return: Value
     */
    private Value get(Node x, Key key) {
        //x树为null
        if (null == x) {
            return null;
        }
        //x树不为null
        //比较key和x节点的键的大小
        int result = key.compareTo(x.key);
        if (result > 0) {
            //如果key大于x节点的键,则继续找x节点的右子树
            return get(x.right, key);
        } else if (result < 0) {
            //如果key小于x节点的键,则继续找x节点的左子树
            return get(x.left, key);
        } else {
            //如果key等于x节点的键,就找到了键为key的节点,只需要返回value即可
            return x.value;
        }
    }

    /**
     * @param key key
     * @Description: 删除树中key对应的value
     * @return: void
     */
    public void delete(Key key) {
        delete(root, key);
    }

    /**
     * @param x   x
     * @param key key
     * @Description: 删除指定树中key对应的value,并返回删除后的新树
     * @return: tree.BinaryTree<Key, Value>.Node
     */
    private Node delete(Node x, Key key) {
        //x树为null
        if (null == x) {
            return null;
        }
        //x树不为null
        int result = key.compareTo(x.key);
        if (result > 0) {
            //如果key大于x节点的键,则继续找x节点的右子树
            x.right = delete(x.right, key);
        } else if (result < 0) {
            //如果key小于x节点的键,则继续找x节点的左子树
            x.left = delete(x.left, key);
        } else {
            //如果key等于x节点的键,完成真正的删除结点动作,要删除的结点就是x;
            //元素个数-1
            N--;
            //找到右子树中最小的节点
            if (x.right == null) {
                return x.left;
            }
            if (x.left == null) {
                return x.right;
            }
            Node minNode = x.right;
            while (minNode.left != null) {
                minNode = minNode.left;
            }
            //删除右子树中最小的节点
            Node node = x.right;
            while (node.left != null) {
                if (node.left.left == null) {
                    node.left = null;
                } else {
                    //变换n节点即可
                    node = node.left;
                }
            }
            //让x节点的左子树成为minNode的左子树
            minNode.left = x.left;
            //让x节点的右子树成为minNode的右子树
            minNode.right = x.right;
            //让x节点的父节点指向minNode
            x = minNode;
        }
        return x;
    }

    /**
     * @Description: 查找整个树中最小的键
     * @return: Key
     */
    public Key getMinKey() {
        return getMinKey(root).key;
    }

    /**
     * @param x x
     * @Description: 在指定树中找出最小键所在的节点
     * @return: tree.BinaryTree<Key, Value>.Node
     */
    private Node getMinKey(Node x) {
        //判断x还有没有左子节点,如果有,则继续项向左找
        if (null != x.left) {
            return getMinKey(x.left);
        } else {
            //如果没有,则x就是最小键所在的结点
            return x;
        }
    }

    /**
     * @Description: 查找整个树的最大的键
     * @return: Key
     */
    public Key getMaxKey() {
        return getMaxKey(root).key;
    }

    /**
     * @param x x
     * @Description: 在指定树中找出最大键所在的节点
     * @return: tree.BinaryTree<Key, Value>.Node
     */
    private Node getMaxKey(Node x) {
        //判断x还有没有右子节点,如果有,则继续向右找
        if (null != x.right) {
            return getMaxKey(x.right);
        } else {
            //如果没有,则x键就是最大键所在的节点
            return x;
        }
    }

    /**
     * @Description: 先序遍历获取整个树中所有的键
     * @return: java.util.List<Key>
     */
    public List<Key> preErgodic() {
        List<Key> keys = new LinkedList<>();
        preErgodic(root, keys);
        return keys;
    }

    /**
     * @param x    x
     * @param keys keys
     * @Description: 先序遍历获取指定树x的所有键,并放到keys队列中
     * @return: void
     */
    private void preErgodic(Node x, List<Key> keys) {
        if (null == x) {
            return;
        }
        //把x节点的key放入到keys中
        keys.add(x.key);
        //递归遍历x节点的左子树
        if (x.left != null) {
            preErgodic(x.left, keys);
        }
        //递归遍历x节点的右子树
        if (x.right != null) {
            preErgodic(x.right, keys);
        }
    }

    /**
     * @Description: 中序遍历获取整个树中所有的键
     * @return: java.util.List<Key>
     */
    public List<Key> midErgodic() {
        List<Key> keys = new LinkedList<>();
        midErgodic(root, keys);
        return keys;
    }

    /**
     * @param x    x
     * @param keys keys
     * @Description: 中序遍历获取指定树x的所有键,并放到keys队列中
     * @return: void
     */
    private void midErgodic(Node x, List<Key> keys) {
        if (null == x) {
            return;
        }
        //递归遍历x节点的左子树
        if (x.left != null) {
            midErgodic(x.left, keys);
        }
        //把x节点的key放入到keys中
        keys.add(x.key);
        //递归遍历x节点的右子树
        if (x.right != null) {
            midErgodic(x.right, keys);
        }
    }

    /**
     * @Description: 后序遍历获取整个树中所有的键
     * @return: java.util.List<Key>
     */
    public List<Key> afterErgodic() {
        List<Key> keys = new LinkedList<>();
        afterErgodic(root, keys);
        return keys;
    }

    /**
     * @param x    x
     * @param keys keys
     * @Description: 后序遍历获取指定树x的所有键,并放到keys队列中
     * @return: void
     */
    private void afterErgodic(Node x, List<Key> keys) {
        if (null == x) {
            return;
        }
        //递归遍历x节点的左子树
        if (x.left != null) {
            afterErgodic(x.left, keys);
        }
        //递归遍历x节点的右子树
        if (x.right != null) {
            afterErgodic(x.right, keys);
        }
        //把x节点的key放入到keys中
        keys.add(x.key);
    }

    /**
     * @Description: 宽度优先遍历,使用层序遍历获取整个树中的所有键
     * @return: java.util.List<Key>
     */
    public List<Key> layerErgodic() {
        //定义两个集合,分别存储树中的键和树中的节点
        List<Key> keys = new LinkedList<>();
        List<Node> nodes = new ArrayList<>();
        //默认往集合中存入根节点
        nodes.add(root);
        while (!nodes.isEmpty()) {
            //从队列中弹出一个节点,把key放入到集合中
            Node node = nodes.get(0);
            keys.add(node.key);
            if (node.left != null) {
                //判断当前结点还有没有左子结点,如果有,则放入到nodes中
                nodes.add(node.left);
            }
            if (node.right != null) {
                //判断当前结点还有没有右子结点,如果有,则放入到nodes中
                nodes.add(node.right);
            }
        }
        return keys;
    }

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

    /**
     * @param x x
     * @Description: 获取指定树的最大深度
     * @return: int
     */
    private int maxDepth(Node x) {
        if (null == x) {
            return 0;
        }
        //左子树的最大深度
        int maxL = 0;
        //右子树的最大深度
        int maxR = 0;
        //计算x节点左子树的最大深度
        if (x.left != null) {
            maxL = maxDepth(x.left);
        }
        //计算x节点右子树的最大深度
        if (x.right != null) {
            maxR = maxDepth(x.right);
        }
        return maxL > maxR ? maxL + 1 : maxR + 1;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值