其他分享
首页 > 其他分享> > 浅入浅出二叉树

浅入浅出二叉树

作者:互联网


树的概述

树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。形同下图。

树有如下基本概念:


二叉树的概述

任何子结点的数量都不超过 2,就是一颗二叉树。比如之前举例的图,明显就不是二叉树。二叉树的子结点分左结点和右结点,不能随意颠倒位置。

二叉树也有分类:


链式存储的二叉树

顾名思义,用链表的方式去实现二叉树结构。用代码去实现,首先我们要创建一个结点类。

public class TreeNode {
    // 节点的权
    private int value;
    // 左子结点
    private TreeNode leftNode;
    // 右子结点
    private TreeNode rightNode;

    public TreeNode(int value) {
        this.value = value;
    }
	// 剩下的都是 set/get 方法了
    ...
}

其次,和链表有头结点一样,二叉树也需要有根结点辅助操作,作为创建二叉树的基础。

public class BinaryTree {

    private TreeNode root;

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }
}

万事具备,向根结点添加左右子结点即可。

public class TestBinaryTree {

    public static void main(String[] args) {
        // 创建二叉树
        BinaryTree binaryTree = new BinaryTree();
        // 创建根结点
        TreeNode root = new TreeNode(1);
        // 设置根结点
        binaryTree.setRoot(root);
        // 创建一个左结点
        TreeNode rootL = new TreeNode(2);
        // 把新创建的结点设置为根结点的左子结点
        root.setLeftNode(rootL);
        // 创建一个右结点
        TreeNode rootR = new TreeNode(3);
        // 把新创建的结点设置为根结点的右子结点
        root.setRightNode(rootR);
        // 为第二层的左结点创建两个子结点
        rootL.setLeftNode(new TreeNode(4));
        rootL.setRightNode(new TreeNode(5));
        // 为第二层的右结点创建两个子结点
        rootR.setLeftNode(new TreeNode(6));
        rootR.setRightNode(new TreeNode(7));
    }
}

遍历二叉树

二叉树的遍历方式有三种,分别是:前序遍历、中序遍历、后序遍历。

以上图为例,记住一点,所谓的前序、中序、后序都是参考当前结点的位置。前序遍历,即是先取当前结点的权,然后是它的左子结点,最后是右子结点。从根结点开始,遍历过程中每一个结点都要遵守这个规矩。

因此上图前序遍历得到的结果是:1、2、4、5、3、6、7;中序遍历得到的结果是:4、2、5、1、6、3、7;后序遍历得到的结果是:4、5、2、6、3、7、1。代码实现用到递归的思想。

public class TestBinaryTree {

    public static void main(String[] args) {
        // 之前创建二叉树的代码,这里就省略不写了
        ...
        // 前序遍历树
        binaryTree.frontShow();
        System.out.println("-----------------");
        // 中序遍历树
        binaryTree.midShow();
        System.out.println("-----------------");
        // 后序遍历树
        binaryTree.afterShow();
    }
}
public class BinaryTree {

    private TreeNode root;

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }

    // 前序遍历
    public void frontShow() {
        if (root != null) {
        	root.frontShow();
        }
    }

    // 中序遍历
    public void midShow() {
        if (root != null) {
        	root.midShow();
        }
    }

    // 后序遍历
    public void afterShow() {
        if (root != null) {
        	root.afterShow();
        }
    }
}
public class TreeNode {

    // 节点的权
    private int value;
    // 左子结点
    private TreeNode leftNode;
    // 右子结点
    private TreeNode rightNode;

    public TreeNode(int value) {
        this.value = value;
    }

    // set/get 方法
	...

    // 前序遍历
    public void frontShow() {
        // 先输出当前结点内容
        System.out.println(value);
        // 输出左结点内容
        if (leftNode != null) {
            leftNode.frontShow();
        }
        // 输出右结点内容
        if (rightNode != null) {
            rightNode.frontShow();
        }
    }

    // 中序遍历
    public void midShow() {
        // 输出左结点内容
        if (leftNode != null) {
            leftNode.midShow();
        }
        // 输出当前结点内容
        System.out.println(value);
        // 输出右结点内容
        if (rightNode != null) {
            rightNode.midShow();
        }
    }

    // 后序遍历
    public void afterShow() {
        // 输出左结点内容
        if (leftNode != null) {
            leftNode.afterShow();
        }
        // 输出右结点内容
        if (rightNode != null) {
            rightNode.afterShow();
        }
        // 输出当前结点内容
        System.out.println(value);
    }
}

二叉树中结点的查找

查找结点,实际就是把整颗二叉树遍历一次,依次比对,找出结果并返回。这里以前序查找为例,其余的大同小异。

public class TestBinaryTree {

    public static void main(String[] args) {
		// 创建二叉树
        ...
        // 前序查找
        TreeNode result = binaryTree.frontSearch(5);
        System.out.println(result);
    }
}

public class BinaryTree {

    private TreeNode root;

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }

    /**
     * 前序查找
     * @return 目标结点
     */
    public TreeNode frontSearch(int value) {

        return root.frontSearch(value);
    }
}
public class TreeNode {

    // 节点的权
    private int value;
    // 左子结点
    private TreeNode leftNode;
    // 右子结点
    private TreeNode rightNode;

    public TreeNode(int value) {
        this.value = value;
    }

    /**
     * 前序查找
     * @return 目标结点
     */
    public TreeNode frontSearch(int value) {
        TreeNode target = null;
        // 返回本结点
        if (this.value == value) {
            return this;
        }
        // 向左子结点方向查找
        if (leftNode != null) {
            target = leftNode.frontSearch(value);
        }
        // 如果不为空,证明找到结点,返回
        if (target != null) {
            return target;
        }
        // 向右子结点方向查找
        if (rightNode != null) {
            target = rightNode.frontSearch(value);
        }
        return target;
    }
}

删除二叉树的结点

对于一颗普通的二叉树而言,删除一个结点就等同于把对应的整颗子树一并删掉。之后讲到二叉排序树时,就不是这样操作了。

删除时要区分是根结点还是其他结点。如果是根结点的话,直接置为 null 就好了。但如果不是,则依次比较左右两个子结点,符合就直接置为 null。如果都不符合,那就递归调用左右结点的 delete 方法。

public class TestBinaryTree {

    public static void main(String[] args) {
		// 创建一颗子树
        ...
        // 删除一个结点
        binaryTree.delete(5);
        binaryTree.frontShow();
    }
}
public class BinaryTree {

    private TreeNode root;

	...

    /**
     * 根据权值删除结点
     * @param value 依据权值
     */
    public void delete(int value) {
        // 要删除的是根结点
        if (root.getValue() == value) {
            root = null;
        } else {
            // 要删除的是其他结点
            root.delete(value);
        }
    }
}
public class TreeNode {

    // 节点的权
    private int value;
    // 左子结点
    private TreeNode leftNode;
    // 右子结点
    private TreeNode rightNode;

	...

    /**
     * 根据权值删除结点
     * @param value 依据权值
     */
    public void delete(int value) {
        TreeNode parent = this;
        // 判断左子结点
        if (parent.leftNode != null && parent.leftNode.value == value) {
            parent.leftNode = null;
            return;
        }
        // 判断右子结点
        if (parent.rightNode != null && parent.rightNode.value == value) {
            parent.rightNode = null;
            return;
        }
        parent = leftNode;
        if (parent != null) {
            parent.delete(value);
        }
        parent = rightNode;
        if (parent != null) {
            parent.delete(value);
        }
    }
}

顺序存储的二叉树

二叉树还可以用数组实现,或者说,任意一个数组都可以转化为二叉树。就上图二叉树而言,它对应的数组实现就是 [1,2,3,4,5,6,7]。

并不是每颗二叉树都长得这么规矩,有可能会出现缺胳膊少腿的情况。通常情况下,顺序存储的二叉树只考虑完全二叉树(满二叉树也是完全二叉树),否则没有意义。

顺序存储的二叉树还有其对应的性质公式,常用的有如下三个:


顺序存储的二叉树的遍历

我们把一个数组当成二叉树作前序遍历,剩下的中序和后序遍历也大同小异了。

public class TestBinaryTree {

    public static void main(String[] args) {
		
        int[] data = new int[]{1, 2, 3, 4, 5, 6, 7};
        ArrayBinaryTree arrayBinaryTree = new ArrayBinaryTree(data);
        // 前序遍历
        arrayBinaryTree.frontShow();

    }
}
public class ArrayBinaryTree {

    private int[] data;

    public ArrayBinaryTree(int[] data) {
        this.data = data;
    }

    public int[] getData() {
        return data;
    }

    public void setData(int[] data) {
        this.data = data;
    }

    public void frontShow() {
        frontShow(0);
    }

    public void frontShow(int index) {
        if (data == null || data.length == 0) {
            return;
        }
        // 先遍历当前结点的内容
        System.out.println(data[index]);
        // 遍历左子结点
        if (2 * index + 1 < data.length) {
            frontShow(2 * index + 1);
        }
        // 遍历右子结点
        if (2 * index + 2 < data.length) {
            frontShow(2 * index + 2);
        }
    }
}

标签:结点,TreeNode,浅入,value,二叉树,浅出,root,public
来源: https://www.cnblogs.com/Yee-Q/p/13531146.html