首页 > 其他分享 >图文示例二叉树的编码实现过程

图文示例二叉树的编码实现过程

时间:2023-06-26 09:47:45浏览次数:51  
标签:结点 遍历 示例 数值 二叉 查找 二叉树 root 图文

前言

在上一篇文章中,带大家一起学习认识了树型数据结构的定义和特点,并特别介绍了二叉树的遍历操作,分别有:前序遍历、中序遍历、后序遍历。前中后的核心区别是根据根节点在遍历过程中的位置决定的,即:根节点在最前面的称之为中序遍历,根节点在中间的称之为中序遍历,根节点在最后的称之为后序遍历。需要大家掌握根据树形结构写出对应的遍历序列结果的能力。


全文大约【3700】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考...

一. 二叉树的编码实现

接下来=就带大家,通过代码来进行二叉树的编码实现。

1. 定义二叉树的结点

对于树型数据结构中的结点,最多可以包含三部分:结点数据、左孩子子树、右孩子子树。我们使用Java对结点结构可以进行如下定义:

public class Node {
    //结点中存储的数据
    Object data;
    //结点的左子树
    Node left;
    //结点的右子树
    Node right;
    //结点的高度
    int height;
	
    //构造方法
    Node(Object data){
        this.data = data;
    }

    Node(Object data,Node left,Node right){
        this.data = data;
        this.left = left;
        this.right = right;
        this.height = 0;
    }
    
}

2. 二叉树的遍历实现

image.png

如上图所示,二叉树的根节点为A,向下第二层为B结点、C结点,依次类推。根据上图,我们很容易知道,若我们要对二叉树进行遍历,只需要从A结点出发,按照对应的前、中、后等不同的逻辑顺序进行遍历即可。因此,我们需要明确:在遍历二叉树时,只需要知道二叉树根节点即可

2.1 前序遍历

public void prevOrderTraversal(Node root){
    //若根节点为null,直接返回
    if(root == null){
        return;
    }
	//先序遍历,表示先访问根节点,故先输出传入的结点中的数据
	System.out.printf("%s",root.data);

	//遍历当前结点的左孩子结点
	prevOrderTraversal(root.left);
	//遍历当前结点的右孩子结点
	prevOrderTraversal(root.right);
}

根据上述代码,若要执行前序遍历,只需要调用prevOrderTraversal时将A结点作为参数传入,即可得到打印的二叉树的前序遍历的结果:A B D C E G F H J。

2.2 中序遍历

public void inOrderTraversal(Node root){
    if(root == null){
        return;
    }
	//1、首先遍历当前root结点的左子树
	inOrderTraversal(root.left);

	//2、遍历当前结点root中的数据,并进行输出
	System.out.printf("%s ",root.data);

	//3、遍历当前结点root的右子树
	inOrderTraversal(root.right);
}

中序遍历的代码编程如上,先遍历当前结点root的左子树,接着将当前结点root中元素输出,最后遍历当前结点root的右子树。调用上述inOrderTraversal函数,将A结点作为参数传入。可以得到中序二叉树中序遍历的结果为:B D A G E C H F I。

2.3 后序遍历

public void postOrderTraversal(Node root){
    if(root == null){
        return;
    }
	//1、先遍历当前结点的左子树
	postOrderTraversal(root.left);
	//2、先遍历当前结点的右子树
	postOrderTraversal(root.right);
	//3、最后当前结点的数据data
	System.out.printf("%s ",root.data);
}

如上所示的后序遍历操作,在调用postOrderTraversal函数时,将树的根结点A作为参数传入。可以得到后序遍历的序列为:D B G E H I F C A。

2.4 层序遍历(广度遍历)

前面三种遍历方式前序、中序、后序均属于深度遍历,前文我们曾经提到,层序遍历又称广度遍历。主要是按层对树进行结点的遍历。在编程实现上,层序遍历与深度遍历的操作稍有不同,具体实现如下:

public void levelOrderTraversal(Node root){
    if(root == null){
        return;
    }

	Queue<Node> queue = new LinkedList<Node>();
	//首先访问第1层的根节点
	queue.add(root);

	while(!queue.isEmpty()){
        //从队列中取出一个结点,并输出该结点,意味着已经访问过该结点
        Node node = queue.poll();
        System.out.printf("%s ", node.data);

        //判断并将该结点的左子树存入到队列中
        if(node.left != null){
            queue.add(node.left);
        }

        //判断并将该结点的右子树存入到队列中
        if(node.right != null){
            queue.add(node.right);
        }
    }
}

如上述代码所示,在进行层序遍历(广度遍历)时,我们借用了前面已经学习过的数据结构队列Queue,将每次访问的结点输出后,同时将结点的左右子树存入到队列中。因为我们知道队列的特点是,元素输入的顺序与输出的顺序会保持一致,因此在每次取数据时,总是先取出之前存入的数据;同时,又会把下一层数据(左右子树)存入队列中。最终,上述代码对树的层序遍历结果是:A B C D E F G H I。

二. 二叉查找树

1. 二叉查找树概念

二叉查找树,全称为Binary Search Tree,简称BST。从名字中我们容易理解,二叉查找树是在二叉树的基础上,同时具备了某些特性的一种特殊的二叉树型结构。二叉查找树相较于二叉树,额外满足以下几个条件:

(1). 若左子树不为空,则左子树上的所有结点的值均小于根结点位置上的值;

(2). 若右子树不为空,则右子树上的所有结点的值均大于根结点位置上的值;

(3). 左、右子树也都是二叉查找树。

总结上述几个条件的,我们可以用一居话概括二叉查找树的特点,左子树的数值小于根结点点数值,根结点数值小于右子树结点数值,整个二叉树结点的数值从左至右是有序的

基于以上所总结的二叉查找树的特点,有的资料和教材也把查找树称之为二叉搜索树,以及二叉排序树(Binary Sort Tree,简称BST)。因此,大家要记住以下结论特征:左子树结点数值 < 根结点数值 < 右子树结点数值

如上图所示,就是一棵二叉查找树:在此二叉查找树中,任意的子树都满足左子树结点数值 < 父结点数值 < 右子树结点数值的规律。

2. 二叉查找树的操作

二叉查找树最简单的操作是结点查找,其次,因为整个二叉查找树都满足从左至右是有序的,因此如果二叉查找树的结点数量发生变化,就会引起二叉查找树需要重新调整的操作,所以,我们此处还会讨论二叉查找树新增结点和删除结点的操作,最后二叉查找树与普通二叉树一样,都可以进行最基本的遍历操作。

接下来,我们依次讨论:结点查找、新增结点、删除结点、遍历二叉查找树。

2.1 结点查找

我们通过示例进行说明结点查找的逻辑,如下所示:

上图中是一个二叉查找树,现在我们希望查找数值5所在的结点。其具体的步骤如下:

①. 访问根节点,根结点数值位7;

②. 要查找的数值5 < 7,因此访问结点7的左子树结点,并获得左子树结点数值4;

③. 要查找的数值5 > 4,因此访问结点4的右子树结点,并获得右子树结点数值6;

④. 要查找的数值5 < 6,因此访问结点6的左子树结点,并获得左子树结点数值5;

⑤. 要查找的数值5 == 5,因此表示找到了目标数值5所在的结点。

时间复杂度分析:假设一课二叉查找树结点的个数为n,我们会发现在进行查找时,总是会先判断要查找的数值和当前结点的数值的大小,然后根据判断结果,选择其中一侧进行继续查找;而不符合条件的另外一侧子树,可以直接放弃,因为我们知道二叉查找树从左至右总是有序的。这种从左至右有序的二叉查找树,在进行查找时,可以极大的节省时间。实际上,使用二叉查找树查找某个结点,所需要的时间复杂度为O(log 2 n) ,该时间复杂度与树的深度O(log2n)是一样的。

2.2 新增结点

依然以上述二叉查找树为例,现在要插入数值为3的结点,示意图如下:

如上图,插入数值为3的结点的步骤如下:

①. 访问根结点,获得根结点数值7;

②. 要插入结点的数值3 < 7,因此访问根结点的左子树,并获得左子树结点的数值4;

③. 要插入结点的数值3 < 4,因此访问根结点的左子树,并获得左子树结点的数值2;

④. 要插入结点的数值3 > 2,因此访问根结点的右子树,但右子树为空;

⑤. 右子树为空,即意味着找到了要插入的位置,即将新增的数值位3的结点作为结点2的右子树。

时间复杂度分析:根据插入的步骤,我们可以非常容易的理解插入结点的操作时间复杂度也为O(log2n),与查找结点时间复杂度相同。

2.3 删除结点

删除结点的操作与前面的查找和增加操作不太一样,删除操作需要分不同的情况进行讨论,原因是删除操作会使二叉查找树的结点减少,删除后需要让剩余的结点继续满足二叉查找树的规则和特点,就可能需要做出调整。

具体的,我们可以将删除结点操作分为三种情况:删除叶子结点、删除结点有1个子树、删除结点有2个子树。下面,我们详细进行讨论:

2.3.1 删除叶子结点

删除叶子结点是最简单的操作,因为叶子结点是最底层的结点,因此不需要任何的调整,直接删除即可。删除叶子结点不会对二叉查找树的性质产生影响。

2.3.2 删除结点有1个子树

当要删除的结点有1个子树时(可能是左子树,也可能是右子树)。我们需要将删除结点的子树结点,替换到删除结点的位置。比如,以下图为例:

如上图所示,我们希望删除数值位6的结点。由于结点6有一棵数值位5的左子树。因此,在将结点6删除后,将子结点5放在原来结点6的位置上,如上右图所示。

通过上述案例操作我们可以总结:当删除结点有1个子树结点时,直接将子结点放在删除结点的位置

2.3.3 删除结点有2个子树

当删除结点有2个子树时,可以借助二叉树的中序遍历结果进行操作。具体步骤为:

(1). 找出二叉查找树的中序遍历序列;

(2). 找到要删除结点数值的前驱结点数值;

(3). 使用前驱结点数值替换删除的结点。

以下图为例:要删除二叉查找树的数值9所在的结点

如上图所示,删除步骤如下:

①. 根据图示的二叉查找树,得到中序遍历结果:1 2 4 5 6 7 8 9 10 12;

②. 确定要删除数值9的结点;

③. 在中序遍历结果序列中找到9的前驱8;

④. 使用数值8结点替换结点9,替换后入上右图所示。

2.4 遍历二叉查找树

我们已经知道二叉查找树是具有特殊性质的二叉树,因此二叉查找树的遍历与二叉树的遍历规则完全一致,此处我们就不再赘述。


四. 结语

通过本篇内容,就带大家一起学习了二叉树的Java编程实现,其实,前序遍历、中序遍历、后序遍历的编程实现原理都是相同的,只是遍历的顺序不同而已。 同时,在进行编程实现时,我们发现,无论前序、中序还是后序遍历,都出现了在函数内部继续调用函数本身的现象,在计算机编程中,我们把程序调用自己本身的折中操作称之为递归。各位感兴趣的读者,可以自己查阅资料,了解递归的相关概念和特点。

以上就是我们本篇的全部内容啦,大家get了吗~

没太明白的可以仔细看我们的视频讲解:零基础学Java快速入门

更多干货知识、学习路线图,扫描文末二维码可得↓↓↓

标签:结点,遍历,示例,数值,二叉,查找,二叉树,root,图文
From: https://www.cnblogs.com/qian-fen/p/17504525.html

相关文章

  • 关于二叉树的操作
    树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。在面试环节中,二叉树也是必考的模块。本文主要讲二叉树操作的相关知识,梳理面试常考的内容。一起来复习吧。 本篇针对面试中常见的二叉树操作作个总结:前序遍历,中序遍历,后序遍历;层次遍历;求树的结点数;求树的叶子数;求......
  • 帝国CMS 复制word里面带图文的文章,图片可以直接显示
    ​ 1.编辑器修改(可选)1.1在 ueditor/config.json 中添加代码块    /* 上传word配置 */    "wordActionName":"wordupload",/* 执行上传视频的action名称 */    "wordFieldName":"upfile",/* 提交的视频表单名称 */    "wordPathFormat":"/p......
  • 动易CMS 复制word里面带图文的文章,图片可以直接显示
    ​图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,找到UM.plugins['autoupload'],然后找到autoUploadHandler方法,注释掉其中的代码。加入下面的代码://判断剪贴......
  • 【拼多多商品详情数据】API接口获得宝贝详情数据、商品标题数据等Java调用示例
    ​拼多多商品详情API接口的作用是获取拼多多平台上某个商品的详细信息,包括商品标题、价格、图片、规格、参数、店铺信息等。开发者可以通过该接口获取到商品的原始数据,方便进行数据分析、价格比较、爬取等操作。通过该接口获取到的商品详情数据可以结合其他数据进行深度挖掘,例如......
  • 【淘宝商品详情数据】api接口获得宝贝详情数据、优惠价格数据Java调用示例
    淘宝详情API接口的作用是获取淘宝平台上某个商品的详细信息,包括商品标题、价格、图片、规格、参数、店铺信息等。开发者可以通过该接口获取到商品的原始数据,方便进行数据分析、价格比较、爬取等操作。通过该接口获取到的商品详情数据可以结合其他数据进行深度挖掘,例如可以将商品数......
  • 二叉树-快排-leetcode912
    给你一个整数数组nums,请你将该数组升序排列。示例1:输入:nums=[5,2,3,1]输出:[1,2,3,5]示例2:输入:nums=[5,1,1,2,0,0]输出:[0,0,1,1,2,5]提示:1<=nums.length<=5*104-5*104<=nums[i]<=5*104思路:快排,或者叫前序二叉树,排序后端结果是一个二叉搜索树//lee......
  • 179_自动生成 千万级 Power BI 示例数据
    179_自动生成千万级PowerBI示例数据在早一些是时候,我曾写过一个示例数据《赠送300家门店260亿销售额的零售企业PowerBI实战示例数据》,本次我们对该示例数据做了一些调整。一、更新内容针对有一些朋友不会使用vba模块,我们增加了UI操作。填写几个简单的参数即可生成......
  • 博客 复制word里面带图文的文章,图片可以直接显示
    ​如何做到ueditor批量上传word图片?1、前端引用代码<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>......
  • WPF入门教程系列二十九 ——DataGrid使用示例MVVM模式(7)
    WPF入门教程系列目录WPF入门教程系列二——Application介绍WPF入门教程系列三——Application介绍(续)WPF入门教程系列四——Dispatcher介绍WPF入门教程系列五——Window介绍WPF入门教程系列十一——依赖属性(一)WPF入门教程系列十五——WPF中的数据绑定(一) 接上文WPF......
  • Linux使用HTTP代码示例
    以下是使用Linux命令行发送HTTP请求的示例:1.使用curl命令发送GET请求:```curl ExampleDomain```2.使用curl命令发送POST请求:```curl-XPOST-d"param1=value1&param2=value2" ExampleDomain```3.使用wget命令发送GET请求:```wget ExampleDomain```4.使用wget命令发送POST......