二叉树入门

Posted BLACK CAT JAVA

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树入门相关的知识,希望对你有一定的参考价值。

二叉树入门

1.1 基本概念

二叉树:二叉树就是度不超过2的树(每个节点最多两个子节点)

满二叉树:一个二叉树,如果每一层的节点都达到最大值,则这个二叉树就叫满二叉树(2^n-1)

完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树,即如果树不满则要求左满右不满,是为完全二叉树


1.2 二叉查找树的创建

1.2.1 二叉树的属性

节点类

 class Node {
        //存储key
        private Key key;
        //存储value
        private Value value;
        //左子节点
        private Node left;
        //右子节点
        private 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 class BinaryTree<< span="">Key extends Comparable<< span="">Key>, Value> {

    //元素个数
    private int size;
    //根节点
    private Node root;
}


1.2.2 插入

 public void put(K key,V value) 向树中插入一个键值对
private Node put(Node,K key,V value) 向树中指定结点处插入键值对

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

    //给指定树x上,添加键一个键值对,并返回添加后的新树
    private Node put(Node node, Key key, Value value) {
        //如果当前树中没有任何一个结点,则直接返回新结点
        if (node == null) {
            //节点数+1
            size++;
            return new Node(key, value, null, null);
        }

        int cmp = key.compareTo(node.key);
        if (cmp > 0) {
            //如果新结点的key大于当前结点的key,则继续找当前结点的右子结点
            node.right = put(node.right, key, value);
        } else if (cmp < 0) {
            //如果新结点的key小于当前结点的key,则继续找当前结点的左子结点
            node.left = put(node.left, key, value);
        } else {
            //如果新结点的key等于当前结点的key,则树中已经存在这样的结点,替换该结点的value值即可
            node.value = value;
        }
        return node;
    }


1.2.3 获取

 public Value get(Key key) //根据key,从树中找出对应的值

 private Value get(Node node, Key key //从指定的树x中,找出key对应的值

    //根据key,从树中找出对应的值
    public Value get(Key key) {
        return get(root, key);
    }

    //从指定的树x中,找出key对应的值
    private Value get(Node node, Key key) {
        if (node == null) {
            return null;
        }
        int cmp = key.compareTo(node.key);
        if (cmp > 0) {
            //如果新结点的key大于当前结点的key,则继续找当前结点的右子结点
            return get(node.right, key);
        } else if (cmp < 0) {
            //如果新结点的key小于当前结点的key,则继续找当前结点的左子结点
            return get(node.left, key);
        } else {
            //如果新结点的key等于当前结点的key,则直接返回
            return node.value;
        }
    }


1.2.4 删除

 public void delete(K key) 根据key删除键值对
private Node delete(Node x,K key) 根据key删除树中指定结点处的键值对

     //根据key,删除树中对应的键值对
    public void delete(Key key) {
        root = delete(root, key);
    }

    //删除指定树x上的键为key的键值对,并返回删除后的新树
    private Node delete(Node node, Key key) {
        if (node == null) {
            return null;
        }
        //找到被删除结点
        int cmp = key.compareTo(node.key);
        if (cmp > 0) {
            //新结点的key大于当前结点的key,继续找当前结点的右子结点
            node.right = delete(node.right, key);
        } else if (cmp < 0) {
            //新结点的key大于当前结点的key,继续找当前结点的左子结点
            node.left = delete(node.left, key);
        } else {
            //1.如果当前结点的右子树不存在,则直接返回当前结点的左子结点
            if (node.right == null) {
                return node.left;
            }
            //2.如果当前结点的左子树不存在,则直接返回当前结点的右子结点
            if (node.left == null) {
                return node.right;
            }

            //3.当前结点的左右子树都存在
            //3.1找到右子树中最小的结点
            Node minNode = node.right;
            while (minNode.left != null) {
                minNode = minNode.left;
            }
            //3.2删除右子树中最小的结点
            Node delNode = node.right;
            while (delNode.left != null) {
                if (delNode.left.left == null) {
                    delNode.left = null;
                    break;
                }
                delNode = delNode.left;
            }
            //3.3.让被删除结点的左子树称为最小结点minNode的左子树,
            //让被删除结点的右子树称为最小结点minNode的右子树
            minNode.left = node.left;
            minNode.right = node.right;
            //3.4.让被删除结点的父节点指向最小结点minNode
            node = minNode;
            //4.个数减1
            size--;
        }
        return node;
    }


1.2.5 获取size

 public int size() 获取树中元素个数

   public int size() {
        return size;
   }


1.2.6 查找二叉树中最小的键

    //找出整个树中最小的键
    public Key min() {
        return min(root).key;
    }

    //找出指定树x中最小的键所在的结点
    private Node min(Node x) {
        if (x.left != null) {
            return min(x.left);
        } else {
            return x;
        }
    }


1.2.7查找二叉树中最大的键

    //找出整个树中最大的键
    public Key max() {
        return max(root).key;
    }

    //找出指定树x中最大的键所在的结点
    private Node max(Node x) {
        if (x.right != null) {
            return max(x.right);
        } else {
            return x;
        }
    }


1.3 二叉树的基础遍历

1.3.1 前序遍历

二叉树前序遍历: 先遍历根结点,再遍历左子树,最后遍历右子树

    //前序遍历
    public Queue<< span="">Key> pre() {
        Queue<< span="">Key> keys = new LinkedList<>();
        pre(root, keys);
        return keys;
    }

    private void pre(Node node, Queue<< span="">Key> keys) {
        if (node == null) {
            return;
        }
        keys.add(node.key);
        if (node.left != null) {
            pre(node.left, keys);
        }
        if (node.right != null) {
            pre(node.right, keys);
        }
    }


1.3.2 中序遍历

二叉树中序遍历: 先遍历左子树,再遍历根结点,最后遍历右子树

//中序遍历
    public Queue<< span="">Key> mid() {
        Queue<< span="">Key> keys = new LinkedList<>();
        mid(root, keys);
        return keys;
    }

    private void mid(Node node, Queue<< span="">Key> keys) {
        if (node == null) {
            return;
        }
        if (node.left != null) {
            mid(node.left, keys);
        }
        keys.add(node.key);

        if (node.right != null) {
            mid(node.right, keys);
        }
    }


1.3.3 后序遍历

二叉树后序遍历: 先遍历左子树,再遍历右子树,最后遍历根结点

 //后序遍历
    public Queue<< span="">Key> after() {
        Queue<< span="">Key> keys = new LinkedList<>();
        after(root, keys);
        return keys;
    }

    private void after(Node node, Queue<< span="">Key> keys) {
        if (node == null) {
            return;
        }
        if (node.left != null) {
            after(node.left, keys);
        }
        if (node.right != null) {
            after(node.right, keys);
        }
        keys.add(node.key);
    }


1.4 二叉树的层序遍历

 //层序遍历
    //1.创建队列,存储每一层的结点;
    //2.使用循环从队列中弹出一个结点:
    // 2.1获取当前结点的key;
    // 2.2如果当前结点的左子结点不为空,则把左子结点放入到队列中
    // 2.3如果当前结点的右子结点不为空,则把右子结点放入到队列中
    public Queue<< span="">Key> layer() {
        Queue<< span="">Key> keys = new LinkedList<>();
        Queue<< span="">Node> nodes = new LinkedList();
        nodes.offer(root);
        while (!nodes.isEmpty()) {
            Node node = nodes.poll();
            keys.add(node.key);
            if (node.right != null) {
                nodes.offer(node.right);
            }
            if (node.left != null) {
                nodes.offer(node.left);
            }
        }
        return keys;
    }


1.5 二叉树的最大深度问题

   //最大深度
    public int maxDepth() {
        return maxDepth(root);
    }

    //1.如果根结点为空,则最大深度为0;
    //2.计算左子树的最大深度;
    //3.计算右子树的最大深度;
    //4.当前树的最大深度=左子树的最大深度和右子树的最大深度中的较大者+1
    private int maxDepth(Node node) {
        if (node == null) {
            return 0;
        }
        int leftDepth = 0;
        if (node.left != null) {
            leftDepth = maxDepth(node.left);
        }
        int rightDepth = 0;
        if (node.right != null) {
            rightDepth = maxDepth(node.right);
        }

        return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
    }


以上是关于二叉树入门的主要内容,如果未能解决你的问题,请参考以下文章

Java二叉树入门详解(包含二叉树0J练习解析)

Java二叉树入门详解(包含二叉树0J练习解析)

万字长文!二叉树入门和刷题看这篇就够了!

⭐算法入门⭐《二叉树 - 平衡二叉树》简单01 —— LeetCode 110. 平衡二叉树

树の讲解-----二叉树入门(遍历)

算法入门14二叉树的镜像