二叉树的基本操作实现

简介: 后面我们会讲到很多种类的二叉树,它们都是为了弥补原有二叉树结构的缺陷或者解决一些实际问题而演变而来的,所以掌握好二叉树的基本操作对后面的学习是非常重要的。上一章已经讲到二叉树的三种存储结构:顺序存储、二叉链表存储和三叉链表存储,这里选择使用二叉链表存储来实现关于二叉树的基本操作。


一、概述



后面我们会讲到很多种类的二叉树,它们都是为了弥补原有二叉树结构的缺陷或者解决一些实际问题而演变而来的,所以掌握好二叉树的基本操作对后面的学习是非常重要的。上一章已经讲到二叉树的三种存储结构:顺序存储、二叉链表存储和三叉链表存储,这里选择使用二叉链表存储来实现关于二叉树的基本操作。

private class Node {
    private T data;
    private Node left;
    private Node right;
}


二、二叉树基本操作分析



根据二叉树本身的节点和层次的特点,所以二叉树的大部分操作都可以使用递归来实现,后面讲到的基本操作会包含构建二叉树、计算节点和深度、遍历二叉树等方面。


1. 二叉树的构建


二叉树的构建方法有很多,这里选择比较简单的一种,基于一个数组来构建一棵二叉树,上一章中提到了在二叉树的顺序存储中,节点的相对位置可以表示节点之间的关系,例如一个节点的位置为 i,那么它的左孩子位置为 2i+1,右孩子为 2i+2,根据这一特点,我们可以使用数组来实现构建一棵二叉树。

微信图片1.png

基于数组构建二叉树代码实现如下:

public void init(T[] arr) {
    if (arr == null || arr.length == 0) {
        return;
    }
    List<Node> list = new ArrayList<>();
    for (T t : arr) {
        list.add(new Node(t, null, null));
    }
    root = list.get(0);
    for (int i = 0; i < list.size() / 2; i++) {
        if ((i * 2 + 1) < list.size()) {
            list.get(i).left = list.get(i * 2 + 1);
        }
        if ((i * 2 + 2) < list.size()) {
            list.get(i).right = list.get(i * 2 + 2);
        }
    }
}


2. 计算节点个数


2.1 计算所有节点个数


计算二叉树的节点个数,通过递归遍历所有节点进行计数,你可以想象成每次递归都是把当前节点的孩子节点拆分成左右两个子树进行操作。

private int nodeCount(Node node) {
    if (node == null) {
        return 0;
    }
    return nodeCount(node.left) + nodeCount(node.right) + 1;
}


2.2 计算叶子节点个数


计算二叉树的叶子节点个数,在基于前面计算所有节点上,增加一个判断为叶子节点的条件,然后只针对符合该条件的节点进行计数。

private int leafNodeCount(Node node) {
    if (node == null) {
        return 0;
    }
    if (node.left == null && node.right == null) {
        return 1;
    }
    return leafNodeCount(node.left) + leafNodeCount(node.right);
}


3. 计算深度

计算二叉树的深度看上去和计算节点个数的方法一样,只是递归方法一样,计数的逻辑不一样。因为孩子节点的深度等于父亲节点的深度加1,基于这一推论,可以实现计算二叉树深度的递归算法。

private int depth(Node node) {
    if (node == null) {
        return 0;
    }
    return Math.max(depth(node.left), depth(node.right)) + 1;
}


4. 深度遍历


基于深度优先遍历,沿着树的深度来遍历节点,尽可能深的搜索树的分支。它按照访问节点的顺序不同可以分为:先序遍历、中序遍历和后序遍历。


4.1 先序遍历

先序遍历是先访问节点数据,再遍历左子树,然后遍历右子树,节点访问顺序可以简写为DLR(Data->Left->Right),可以使用递归来简单地实现。

微信图片2.png

先序遍历代码实现如下:

private void preOrderTraverse(Node node) {
    if (node == null) {
        return;
    }
    operate(node);
    preOrderTraverse(node.left);
    preOrderTraverse(node.right);
}
ope

operate(node) 是对当前遍历节点的操作方法,具体对节点的操作逻辑可以自定义实现,比如在控制台打印节点数据。


4.2 中序遍历

中序遍历是先遍历左子树,再访问节点数据,然后遍历右子树,节点访问顺序可以简写为LDR。

微信图片3.png

中序遍历代码实现如下:

private void inOrderTraverse(Node node) {
    if (node == null) {
        return;
    }
    inOrderTraverse(node.left);
    operate(node);
    inOrderTraverse(node.right);
}


4.3 后序遍历

后序遍历是先遍历左子树,再遍历右子树,然后访问节点数据 ,节点访问顺序可以简写为LRD。

微信图片4.png后序遍历代码实现如下:

private void postOrderTraverse(Node node) {
    if (node == null) {
        return;
    }
    postOrderTraverse(node.left);
    postOrderTraverse(node.right);
    operate(node);
}

三种基于深度优先的遍历方法逻辑实现一致,只是对节点数据和左右子树的访问顺序不一样。


5. 层次遍历

基于二叉树的层次遍历,又称作广度优先遍历,从根节点开始,沿着树的宽度一层一层向下遍历,这里可以使用队列来实现遍历逻辑。

微信图片5.png广度优先遍历代码实现如下:

public void levelOrderTraverse() {
    Queue<Node> queue = new LinkedList<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        Node node = queue.poll();
        operate(node);
        if (node.left != null) {
            queue.offer(node.left);
        }
        if (node.right != null) {
            queue.offer(node.right);
        }
    }
}


三、二叉树基本操作实现



针对前面讲的基本操作分析,来定义一个二叉树的基本操作接口。


基本操作接口定义


public interface BinaryTree<T> {
    /**
     * 初始化树
     */
    void init(T[] arr);
    /**
     * 计算节点个数
     */
    int nodeCount();
    /**
     * 计算叶子节点个数
     */
    int leafNodeCount();
    /**
     * 计算深度
     */
    int depth();
    /**
     * 先序遍历
     */
    void preOrderTraverse();
    /**
     * 中序遍历
     */
    void inOrderTraverse();
    /**
     * 后序遍历
     */
    void postOrderTraverse();
    /**
     * 层次遍历
     */
    void levelOrderTraverse();
}








目录
相关文章
|
12月前
|
存储 算法
链式二叉树的基本操作实现(建议收藏!!!)(2)
链式二叉树的基本操作实现(建议收藏!!!)
98 0
|
存储 算法
二叉树基本操作实现 && 树和二叉树&& 二叉树进阶oj && 堆的基本概念 && 优先级队列的使用_
二叉树基本操作实现 && 树和二叉树&& 二叉树进阶oj && 堆的基本概念 && 优先级队列的使用_
78 0
|
6月前
|
存储 算法
数据结构实验(四)二叉树的基本操作
数据结构实验(四)二叉树的基本操作
|
6月前
|
存储
二叉树的基本概念以及基本操作
二叉树的基本概念以及基本操作
66 2
|
12月前
链式二叉树的基本操作实现(建议收藏!!!)(3)
链式二叉树的基本操作实现(建议收藏!!!)
37 0
|
12月前
链式二叉树的基本操作实现(建议收藏!!!)(1)
链式二叉树的基本操作实现(建议收藏!!!)
56 0
|
存储 机器学习/深度学习 Java
数据结构(4)树形结构——二叉树(概述、前序、中序、后序、层序遍历JAVA实现)
4.1.树 树,由n(n≥0)个有限节点和边组成一个具有层次关系的数据结构。树需要满足以下条件: 任何结点的子节点不相交。 任何子结点只有一个父节点。 N个结点,N-1条边。 对于一个非空树(结点数≥0),具有以下性质: 起始结点称为“根” 除根结点外可分为m个互不相交的有限集合,其中每个集合本身也是一棵树,称为原来这棵树的“子树”。
141 0
《Java数据结构》二叉树的这些基本操作你真的理解了吗
《Java数据结构》二叉树的这些基本操作你真的理解了吗
【Java数据结构】实现二叉树及其基本操作
【Java数据结构】实现二叉树及其基本操作
【Java数据结构】实现二叉树及其基本操作