当前位置:   article > 正文

Java数据结构--二叉树(二叉查找树)_java二叉搜索树

java二叉搜索树

一:二叉树

1.二叉树的定义

二叉树是几个有限无素的集合,该集合或
者为空、或者由一个称为根(root)的元
素及两个不相交的、被分别称为左子树和
右子树的二叉树组成,是有序树。当集合
为空时,称该二叉树为空二叉树。在二叉
树中,一个元素也称作一个节点 。

如图即为一个二叉树(可根据图片理解):

372f452d45714fb0bf2afb420cc80600.jpg

 注:该树并不为一棵二叉搜索树

2.二叉树的遍历(深度优先遍历)

对于二叉树的遍历,可进一步分为三种:

前序遍历(根左右):对于每一棵子树,先访问该节点,然后是左子树,最后是右子树

②中序遍历(左根右):对于每一棵子树,先访问左子树,然后是该节点,最后是右子树

③后序遍历(左右根):对于每一棵子树,先访问左子树,然后是右子树,最后是该节点

二:二叉查找树

1.二叉查找树的定义

二叉查找树,也称二叉搜索树或二叉排序树,是指一棵空树或者具有下列性质的二叉树:
①若任意节点的左子树不空 则左子树上所有结
点的值均小于它的根结点的值;
②若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

如图即为一棵二叉查找树:

(下面的二叉搜索树都以此树为例)

bbc5d079c4b543eab6632f1d67b5fadc.jpg

三:二叉查找树的代码实现

1.节点的创建:

二叉树的节点分位两类:

①树节点:该节点的左右孩子至少存在一个

对于该节点,包含有Value值,leftTreeNode左孩子以及rightTreeNode右孩子

②叶子节点:该节点没有左右孩子

对于该节点,只包含Value值

因此创建节点,我们要包含有两种实参构造,一种只有Value值,另一种均含有

下面我们来创造一个节点的标准Javabean类

adddc081d96b4944aeadce8fa9dc6dd8.png

 我们还需创造一个BinaryTree类,我们需要有root成员变量,在该类中我们将实现遍历,插入,查找,删除等操作。

24ec33902ee94ec497ba22a036dbffc7.jpg

2.层序遍历

在开始写二叉树的三种基本遍历前,我们先了解一下层序遍历。

那什么是层序遍历呢?顾名思义,层序遍历就是对每一层的节点,从左到右以此遍历。下面我们来实现下它的代码。

形式一:

思路:对于每一层的节点,我们输出该点,再将它的左右孩子存起来,等这一层的节点遍历完成后,再对它的孩子节点重复此操作。

这样的输出就是我们要遍历的结果

4997c82390714766b63757b91debf9d4.jpg

对此你想到了用什么来实现该操作吗?(队列(先进先出))

cd0b71c1458945f5bcfed9729c8e18b6.png

 下面我们来填入数据运行爽一下吧。

d076e46b46f84324ae085cc557df74cf.jpg

你们的是不是也是这样的结果呢?

形式二:

层序遍历当然要每一次分开来单独遍历,那我们能不能像下面这样的形式遍历呢?

69484379d0d145c8860bcab7dba4ca45.jpg

下面我们就来实现一下吧!

335f5f2034ed40fcb99d05f38d6399fc.png

思考:为什么队列的长度就是每一层要遍历的节点数呢?

第一次while循环: size等于1,for循环一次,出队一个节点,入队两个节点

第二次while循环: size等于2, for循环两次,出队两个节点,入队三个节点

.....

由此可得出为什么队列的长度会与每一层要遍历的节点数相同

 516a678de86f491ea8327d55a4d31663.jpg

3.前序,中序,后序遍历--递归实现

对于二叉树来说,递归是最常见最简单的解决问题的使用方法

注:二叉搜索树中序遍历后,数据为升序排列

691f85b9b34f4df9b20a9bf316a656c2.jpg

 4.前序,中序,后序遍历--非递归实现

对于二叉树来说,递归实现遍历太简单了,想要提高自己对于二叉树的理解,使用非递归来解决问题是最有效的方法

①前序,中序遍历

思路:从根节点开始一直向左遍历,直到该节点为空,获取前一个节点,开始遍历它的右子树

思考:这里我们要考虑的是,如何才能获取之前所遍历过的节点呢?(栈(先进后出))

a323dcea32a24fc299a37e0e23c13de1.png 

中序遍历同后序遍历一样,只不过是处理Value值的地方不同而已。

09cc625e1aca452ba044bf9f95b63d64.png

②后序遍历

后序遍历同前序 中序遍历一样,都是需要依靠栈来实现的。但不同的是,前中序遍历到左子树为空时,直接出栈获取到前一个节点。而后序遍历需要我们,当左右子树都遍历完成时,再输出该节点的value值(左右根),这样我们就不能直接将左子树为空时的前一个节点出栈。

思路:一直遍历左子树,直到左子树为空时,获取左子树为空时的前一个节点,但不出栈,判断获取的节点的右子树是否遍历完成后,再输出该节点的value值(当该节点的右子树为空或者右子树遍历完成)

思考:我们如何知道右子树是否遍历完成了?再去输出该节点的value值。

当该节点的右子树等于最近一次出栈的节点时,就表示右子树已经遍历完成了。

怎么理解这句话呢?(我们只要知道,节点出栈的话就表示该节点以及它的左右孩子(根左右)已经遍历完成了)

9afdae3c79814247a0742009b8bb2dbc.jpg

5.插入节点insert

思路:①当树为空时,直接插入

       ②当树不为空时,如果所插入的值小于寻找节点的值,则向寻找节点的左子树寻找,大于反之。

9f79798516cf432086d7a013f68ceca8.jpg

6.查找节点find

思路:要插入的值与寻找节点的值比较,小于向左子树寻找,大于向右子树寻找,找到空节点时插入

857dfc16698d4efaadbd2c8f6d55bb4d.jpg

7.删除节点remove

要删除的节点分为三种情况:

①第一种:要删除的节点有左右两个孩子

②第二种:要删除的节点只有一个孩子

③第三种:要删除的节点没有孩子

这里我们先考虑②③种情况:

0f98442605a142c19b2400176bdf5880.jpg

512be71707da4156bb2ab8bc5312dec7.jpg 

如果我们要删除该节点,就需要知道该节点的父亲节点与孩子节点,再将父亲节点的指针指向孩子节点就完成了删除。

针对于③情况:
这里我们要思考:它的父亲节点只能指向一个节点,要删除该节点,它的左右孩子怎么办呢?

这里我们看中序遍历(所遍历的二叉搜索树为升序)

我们先看一组数据:1  2  3  4  6  7

我们要删除3,可以用2或者4代替它原来的位置

删除6,可以用4或者7代替它原来的位置

据此,那我们要删除该节点是不是也可以找一个合适的节点代替它的位置,然后再删除代替节点在树中的位置即可(删除代替节点就转换为③)

caa63338af154497a0d1e1552bdbe0be.jpg 

思路:首先要找到删除节点所在树中的位置

从第③种情况(左右孩子均存在)开始考虑起

记录父亲节点与孩子节点,最后将父亲节点的指针指向孩子节点

0726279c46dd48399faff63a43482d94.jpg

8.结果显示

三种遍历,插入,查找,删除等代码已经写好了,那我们就带入数据运行一下吧!

①遍历

365415f5befc45bc9b6709e7ded26d43.jpg

0cb827d5bc06427d91a90d8d7bcbbea3.jpg 

 ②插入,删除,查找

de05f58fbdc44b0db607d8751c30b00f.jpg

9410471a91b24c43bbe3ec95841f348c.jpg

四:二叉树必刷题目(根据自己情况)

①力扣101对称二叉树
         递归
②力扣104最大深度
   方法一:递归
   方法二:后序遍历栈的最高值就是最大深度
    方法三:层序遍历所遍历的层数就是最大深        度
③力扣111最小深度
    方法一:递归
    方法二:层序遍历到最低叶节点就是最小深度
④力扣226翻转二叉树
       递归

⑤力扣938二叉搜索树范围和

     方法一:中序遍历

      方法二:上下界递归

⑥力扣98二叉搜索树是否合法

     方法一:中序遍历(非递归)

     方法二:中序遍历(递归)

      方法三:上下界递归

注:若存在错误,不足之处,望各位指出修改₍˄·͈༝·͈˄*₎◞ ̑̑


 

 


 

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/416557
推荐阅读
相关标签
  

闽ICP备14008679号