• 玩转二叉树


    树是计算机编程当中很基础的一种数据结构,二叉树则是树中最基本的一种。虽然很多程序员在日常工作中未必会直接用到二叉树,但是对于这样一种基础的数据结构,熟练掌握其基本概念和操作,有助于关键场合不露怯。毕竟,所有的玩儿法都是由最基本最核心的理念衍生而成。

    基本概念

    二叉树,顾名思义,从根结点开始,每个结点可以分出最多两个子结点,没有子结点的结点叫叶子。

    形态

    满二叉树

    “满”即是“饱满”:一个从根到叶子,每一个非叶子结点都分出两个子结点,看上去是那么的饱满。其总结点个数计算公式为:$2k-1$,$k$为深度;第$n$层结点个数计算公式为:$2{n-1}$。

    完全二叉树

    不饱满也不要紧,只要缺的都是右叶子而不缺左叶子。其深度计算公式为:$\lfloor log_2k\rfloor+1$。

    二叉搜索树/红黑树

    左子结点值小于父结点值,父结点值小于右子结点值,且左子树中所有结点值均小于根结点值,根结点值小于右子树中任一结点值。

    基本操作

    定义

    public class TreeNode {
        private int value;
        private TreeNode leftChildNode;
        private TreeNode rightChildNode;
    
        TreeNode() {
        }
    
        TreeNode(int value) {
            this.value = value;
        }
    
        TreeNode(int value, TreeNode leftChildNode, TreeNode rightChildNode) {
            this.value = value;
            this.leftChildNode = leftChildNode;
            this.rightChildNode = rightChildNode;
        }
    }
    

    遍历

    深度优先

    深度遍历二叉树分为前序、中序和后序遍历,一般采用递归的实现形式比较简洁。无论哪种遍历,左结点一定是在右结点之前遍历,而所谓的前、中、后,则是中间结点在什么时机处理的区别。因此:

    • 前序遍历 = → 左 → 右
    • 中序遍历 = 左 → → 右
    • 后序遍历 = 左 → 右 →
    public void traverseDepthFirst(TreeNode node) {
        if (node == null) {
            return;
        }
    
        System.out.println(node.value); // Preorder.
        traverseDepthFirst(node.leftChildNode);
        // System.out.println(node.value); // Inorder.
        traverseDepthFirst(node.rightChildNode);
        // System.out.println(node.value); // Postorder.
    }
    

    宽度优先

    层序遍历二叉树一般可以用LinkedList或类似的数据类结合迭代来实现:

    public void traverseBreadthFirst(TreeNode rootNode) {
        LinkedList<TreeNode> linkedList = new LinkedList<>();
    
        if (rootNode == null) {
            return;
        }
    
        linkedList.offer(rootNode);
    
        while (!linkedList.isEmpty()) {
            int size = linkedList.size();
    
            for (int index = 0; index < size; index++) {
                TreeNode node = linkedList.pop();
    
                if (node == null) {
                    continue;
                }
    
                System.out.println(node.value);
    
                linkedList.offer(node.leftChildNode);
                linkedList.offer(node.rightChildNode);
            }
        }
    }
    

    聊完遍历来看看构建吧。可以通过两个数组来构建一个二叉树,这两个数组分别对应的是二叉树的前序及中序遍历,或者中序与后序遍历。下面这段代码就是通过递归的方式,用前序和中序遍历数组构建出一个二叉树。而利用中序和后序遍历构建与这种方式雷同,区别在于:前序数组的第一个元素代表父结点,后续数组中对应的是最后一个元素。

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0 || inorder == null || inorder.length == 0
                || preorder.length != inorder.length) {
            return null;
        }
    
        int rootValue = preorder[0];
        TreeNode root = new TreeNode(rootValue);
    
        if (preorder.length == 1) {
            return root;
        }
    
        int delimiterIndex = 0;
    
        for (int number : inorder) {
            if (number == rootValue) {
                break;
            }
    
            delimiterIndex++;
        }
    
        int[] leftInorder = Arrays.copyOfRange(inorder, 0, delimiterIndex);
        int[] rightInorder = Arrays.copyOfRange(inorder, delimiterIndex + 1, inorder.length);
        int[] leftPreorder = Arrays.copyOfRange(preorder, 1, delimiterIndex + 1);
        int[] rightPreorder = Arrays.copyOfRange(preorder, delimiterIndex + 1, preorder.length);
    
        root.leftChildNode = buildTree(leftPreorder, leftInorder);
        root.rightChildNode = buildTree(rightPreorder, rightInorder);
    
        return root;
    }
    

    二叉树最核心的概念和操作基本就是这些,至于其它诸如合并、翻转、搜索、验证、最大……之类的问题,无非就是在遍历或构建的不同阶段实现不同的逻辑需求。所以,与其试图记住所有二叉树问题的答案,倒不如回过头来,找到二叉树概念的根,彻彻底底地吃透,从而任何问题都可以自己推导出解来。

  • 相关阅读:
    js—初始的二维数组是一个,3行4列的数组。将其转换为4行3列的二维数组
    js_求1—10000的完数
    JS——输入一个日期判断该日期为当年的第几天
    JS——打印倒三角和正三角
    Java内存机制和内存地址
    deepin下搭建基于github和hexo的个人博客
    URL and URI 的 比较
    Cannot use this in a static context
    java项目获取文件路径总结
    利用exe4j制作exe文件
  • 原文地址:https://www.cnblogs.com/Autumoon/p/binary_tree_basis.html
Copyright © 2020-2023  润新知