二叉树的基本操作实现

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


一、概述



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

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();
}








目录
相关文章
|
9月前
|
存储 运维 监控
Kubernetes 集群的持续监控与优化策略
【5月更文挑战第3天】在微服务架构和容器化部署日益普及的背景下,Kubernetes 已成为众多企业的首选容器编排平台。然而,随着集群规模的增长和业务复杂度的提升,有效的集群监控和性能优化成为确保系统稳定性和提升资源利用率的关键。本文将深入探讨针对 Kubernetes 集群的监控工具选择、监控指标的重要性解读以及基于数据驱动的性能优化实践,为运维人员提供一套系统的持续监控与优化策略。
183 7
|
SQL 安全 数据库
故障解决:SQL Server数据库附加失败,错误3415、错误5120
本文为大家分享了SQL Server数据库附加失败的具体解决方法,供大家参考,具体内容如下
故障解决:SQL Server数据库附加失败,错误3415、错误5120
|
9月前
|
监控 容灾 定位技术
云服务器的容灾方案
云服务器的容灾方案
|
4月前
|
自然语言处理 关系型数据库 MySQL
免费的CMS系统有哪些?
内容管理系统(Content Management System,简称CMS) 是一种用于创建、编辑、组织和发布内容的软件系统。它提供了一个用户友好的界面,使用户可以轻松管理网站的内容,而无需具备编程或技术知识。 下面给大家介绍几款目前国内比较常用,而且发展历史比较长的免费CMS系统:
322 1
|
9月前
|
SQL 算法 JavaScript
【数据库SQL server】关系型数据库的基本知识
【数据库SQL server】关系型数据库的基本知识
209 0
|
机器学习/深度学习 传感器 算法
【板球仿真】基于simulink的模糊控制板球系统仿真
【板球仿真】基于simulink的模糊控制板球系统仿真
|
8月前
|
Kubernetes Cloud Native 开发者
阿里云网络发布云原生网关 alibaba-load-balancer-controller v1.2.0,持续拥抱开源生态
alibaba-load-balancer-controller开源版本正式推出v1.2.0,能力对齐ALB Ingress Controller商业版v2.10.0。
|
人工智能 Python
多模态 MiniGPT4 正式开源了!
多模态 MiniGPT4 正式开源了!
|
运维 UED 数据挖掘
中台架构的新一代业务支撑体系是如何实现
2018云栖大会南京会场企业级互联网架构专场,中兴软创BBS产品线总经理王超对基于中台架构的新一代支撑的实现进行了讲解。首先对传统架构和未来架构进行了对比;然后介绍了为什么要进行新的架构的建设,以及架构转型需要转化的四部分,这部分主要是对数字化部分进行详细的介绍,以及案例分析;最后进行了总结。
13176 0

热门文章

最新文章