zoukankan      html  css  js  c++  java
  • 二叉树的创建与遍历(递归实现)

    树的基本概念和术语总结一文中介绍了二叉树的基本结构。

    不知道怎样用递归?按步骤来!一文中介绍了如何使用递归。

    二叉树的结构是递归的,所以创建、遍历也可以通过递归实现。

    下面是一颗二叉树:

    在这里插入图片描述

    结点的定义:

    public class Node {
        Integer value;
        Node leftChild;
        Node rightChild;
    
        public Node(Integer value) {
            this.value = value;
        }
    }
    

    创建

    在这里插入图片描述

    各个结点的值用一个ArrayList集合来保存,根据该集合来创建二叉树。

    按照不知道怎样用递归?按步骤来!中的方法分析如何递归地创建一颗二叉树。

    第一步:找到大问题是什么?

    创建一颗二叉树。

    private Node createBinaryTree(ArrayList<Integer> inputList) {
            
    }
    

    第二步:找到最简单问题是什么?满足最简单问题时应该做什么?

    「创建一个空二叉树」是最简单的问题,当满足时,直接返回null

    private Node createBinaryTree(ArrayList<Integer> inputList) {   
        if (inputList == null || inputList.isEmpty()) {//最简单问题
            return null;
        }
    }
    

    第三步:找到重复逻辑是什么?

    因为我们把每个结点的值都放在ArrayList集合中了,所以,每创建一个二叉树结点,都需要从集合中拿值。

    对于每个结点而言,它一定有左孩子和右孩子(上图中结点3的左孩子和右孩子可以看成「值为null的结点」),

    所以要确定每个结点的左孩子和右孩子是谁。

    所以重复逻辑是:

    1. 从集合中拿值,创建结点。
    2. 确定该结点的左孩子和右孩子。
    //大问题
    private Node createBinaryTree(ArrayList<Integer> inputList) {
        if (inputList == null || inputList.isEmpty()) {//最简单问题
            return null;
        }
        Node node = null;//重复逻辑
        Integer value = inputList.remove(0);//重复逻辑
        if (value != null) {
            node = new Node(value);//重复逻辑
            node.leftChild = ?;//重复逻辑
            node.rightChild = ?;//重复逻辑
        }
    
    }
    

    第四步:自己调用自己

    先解释一下上个代码片段中的问号。

    要确定一个结点的左孩子和右孩子是谁,其实就是一个赋值操作,那么就一定要先有一些可选的结点

    比如说,如果我们要确定结点1的左右孩子,那么结点2、结点5就必须已经被创建出来了,这样才能进行赋值操作。

    那么如何在进行赋值操作之前创建结点2、结点5呢?答案是自己调用自己。

    我们可以把结点2、结点5看成另一颗二叉树的根结点,只要我们创建好以结点2或结点5为根结点的二叉树,那么结点2和结点5自然就被创建出来了。

    确定结点2和结点5的左右孩子同理,这样一直分解下去,直到分解成最简单问题,或者从集合中拿到null为止。

    注意:自己调用自己时参数的变小是通过inputList.remove(0)实现的。

    //大问题
    private Node createBinaryTree(ArrayList<Integer> inputList) {
        if (inputList == null || inputList.isEmpty()) {//最简单问题
            return null;
        }
        Node node = null;//重复逻辑
        Integer value = inputList.remove(0);//重复逻辑
        if (value != null) {
            node = new Node(value);//重复逻辑
            node.leftChild = createBinaryTree(inputList);//重复逻辑,自己调用自己
            node.rightChild = createBinaryTree(inputList);//重复逻辑,自己调用自己
        }
    
    }
    

    第五步:返回

    返回的是根结点,该根结点被确定为左孩子或右孩子,从而构成一颗更大的二叉树,直到满足最大问题的那颗二叉树被创建成功,此时返回的根结点是真正的解。

    //大问题
    private Node createBinaryTree(ArrayList<Integer> inputList) {
        if (inputList == null || inputList.isEmpty()) {//最简单问题
            return null;
        }
        Node node = null;//重复逻辑
        Integer value = inputList.remove(0);//重复逻辑
        if (value != null) {
            node = new Node(value);//重复逻辑
            node.leftChild = createBinaryTree(inputList);//重复逻辑,自己调用自己
            node.rightChild = createBinaryTree(inputList);//重复逻辑,自己调用自己
        }
    	return node;//返回
    }
    

    遍历

    先序遍历

    第一步:找到大问题是什么?

    先序遍历一颗二叉树,打印出每个结点的值。

    public void preOrderTraveral(Node node) {
        
    }
    

    第二步:找到最简单问题是什么?满足最简单问题时应该做什么?

    「遍历一颗空二叉树」是最简单问题,此时任何操作都不用做。

    public void preOrderTraveral(Node node) {
        if (node == null) {//最简单问题
            return;
        }
    }
    

    第三步:找到重复逻辑是什么?

    打印每个结点的值

    public void preOrderTraveral(Node node) {
        if (node == null) {//最简单问题
            return;
        }
        System.out.print(node.value);//重复逻辑
    }
    

    第四步:自己调用自己

    先序遍历的过程:

    1. 遍历根结点
    2. 先序遍历左子树
    3. 先序遍历右子树
    public void preOrderTraveral(Node node) {
        if (node == null) {//最简单问题
            return;
        }
        System.out.print(node.value);//重复逻辑
        preOrderTraversal(node.leftChild);//自己调用自己
        preOrderTraversal(node.rightChild);//自己调用自己
    }
    

    自己调用自己时参数通过node.leftChildnode.rightChild不断变小

    第五步:返回

    不需要返回值。

    中序遍历和后序遍历同理

    完整代码

    //二叉树结点
    public class Node {
        Integer value;
        Node leftChild;
        Node rightChild;
    
        public Node(Integer value) {
            this.value = value;
        }
    }
    
    //二叉树
    public class BinaryTree {
    
        private Node root;
    
        public Node getRoot() {
            return root;
        }
    
        public BinaryTree(ArrayList<Integer> inputList) {
            Node root = createBinaryTree(inputList);
            this.root = root;
        }
    
    	//创建二叉树
        private Node createBinaryTree(ArrayList<Integer> inputList) {
            if (inputList == null || inputList.isEmpty()) {
                return null;
            }
            Node node = null;
            Integer value = inputList.remove(0);
            if (value != null) {
                node = new Node(value);
                node.leftChild = createBinaryTree(inputList);
                node.rightChild = createBinaryTree(inputList);
            }
            return node;
        }
    
        //先序遍历
        public void preOrderTraversal(Node node) {
            if (node == null) {
                return;
            }
            System.out.print(node.value);
            preOrderTraversal(node.leftChild);
            preOrderTraversal(node.rightChild);
        }
    	
        //中序遍历
        public void inOrderTraversal(Node node) {
            if (node == null) {
                return;
            }
            inOrderTraversal(node.leftChild);
            System.out.print(node.value);
            inOrderTraversal(node.rightChild);
        }
    
        //后序遍历
        public void postOrderTraversal(Node node) {
            if (node == null) {
                return;
            }
            postOrderTraversal(node.leftChild);
            postOrderTraversal(node.rightChild);
            System.out.print(node.value);
        }
    }
    
    //测试
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(new Integer[]{1, 2, 3, null, null, 4, null, null, 5, null, 6});
        ArrayList inputList = new ArrayList(list);
    
        BinaryTree binaryTree = new BinaryTree(inputList);
        Node root = binaryTree.getRoot();
        System.out.print("先序遍历:");
        binaryTree.preOrderTraversal(root);
        System.out.print("
    中序遍历:");
        binaryTree.inOrderTraversal(root);
        System.out.print("
    后序遍历:");
        binaryTree.postOrderTraversal(root);
    }
    

    如有错误,还请指正。

    文章首发于微信公众号『行人观学』
    在这里插入图片描述

  • 相关阅读:
    linux系统安装mysql数据库
    laypage分页控件使用方法
    could not get wglGetExtensionsStringARB
    Eclipse -- 自动补齐设置和其他用法
    Android开发--AndroidManifest.xml文件解析
    Java--常识
    课题论文写作时思路---目前存在的不足
    课题论文之调研---已有研究算法概述
    课题论文之调研---脏腑辨证
    Bayesian 网络分类算法
  • 原文地址:https://www.cnblogs.com/xingrenguanxue/p/13163169.html
Copyright © 2011-2022 走看看