二叉树概念及基本功能实现

article/2023/6/4 15:04:37

目录

一、二叉树概述 

 二、代码实现一棵二叉树:

三、二叉树的遍历

四、二叉树遍历代码实现

1.先序遍历:

2.中序遍历:

3.后序遍历:

4.层次遍历(一层一层遍历):

5.main方法执行

五、二叉树的查询和删除:

1.二叉树的查询:

2.二叉树的删除:

3.main方法执行:

六、二叉树深度的计算

七、线索化二叉树:

八、堆排序概述:

一、二叉树概述 

二叉树是每个节点最多有两个子树的树结构,也就是说树的度是2.

满二叉树:每一层的结点数都达到最大值。

完全二叉树:若设二叉树的深度为k,除第k层外,其他各层(1~k-1)的结点数都达到最大个数,第k层所有的结点都连续集中在最左边,这就是完全二叉树。

 注:完全二叉树的话,所有的结点都连续集中在最左边,也就是如下图所示,右子节点可以没有,但如果右子节点有的话,则左子节点必须存在。下图中如果叶子结点只有4结点,5、6、7结点没有的话,也是完全二叉树。

 二、代码实现一棵二叉树:

1.定义结点        2.创建一棵树,手动创建子节点        3.定义一个根节点

public class BinaryTree {//定义一个根节点Node root;//定义结点类public class Node{//存储数据节点Object item;//左子节点Node left;//右子节点Node right;public Node(Object obj){this.item = obj;}}//创建一棵树public void createTree(){//创建根节点root = new Node(1);//创建左子节点Node leftNode = new Node(2);//创建右子节点Node rightNode = new Node(3);//把左右子节点关联到根节点root.left = leftNode;root.right = rightNode;//创建左子节点的左子节点Node leftLeftNode = new Node(4);//创建左子节点的右子节点Node leftRightNode = new Node(5);//把左节点的左右子节点关联到左节点leftNode.left = leftLeftNode;leftNode.right = leftRightNode;//创建右子节点的左子节点Node rightLeftNode = new Node(6);//创建右子节点的右子节点Node rightRightNode = new Node(7);//把右结点的左右子节点关联到右节点rightNode.left = rightLeftNode;rightNode.right = rightRightNode;}
}

三、二叉树的遍历

 

 注:每次遍历的时候,大化小,也就是把大的树化成一颗颗小的树。

比如先序遍历:根左右,先遍历根“1”,然后左子树“2 4 5”作为整体充当根节点的左子树,再进行先序遍历。最后遍历结果就是 1  245   367

四、二叉树遍历代码实现

1.先序遍历:

//实现先序遍历public void preTrival(Node node){//退出的条件if (node == null){return;}//先遍历根节点System.out.print(node.item+" ");//遍历左子树preTrival(node.left);//遍历右子树preTrival(node.right);}

2.中序遍历:

//实现中序遍历public void midTrival(Node node){//退出的条件if (node == null){return;}//遍历左子树midTrival(node.left);//先遍历根节点System.out.print(node.item+" ");//遍历右子树midTrival(node.right);}

3.后序遍历:

//实现后序遍历public void postTrival(Node node){//退出的条件if (node == null){return;}//遍历左子树postTrival(node.left);//遍历右子树postTrival(node.right);//先遍历根节点System.out.print(node.item+" ");}

注:由上面代码规律可以看出,除了根节点是直接打印其值之外,左节点、右节点都是通过递归遍历的方式遍历到。如:

先序遍历:打印根节点--->递归遍历左节点--->递归遍历右节点

中序遍历:递归遍历左节点--->打印根节点--->递归遍历右节点

后序遍历:递归遍历左节点--->递归遍历右节点--->打印根节点

4.层次遍历(一层一层遍历):

思路:将根节点放入一个队列中,然后每次取出这个节点后,相应地将它的左右子节点依次放入队列中,按照队列的先进先出的特性,依次将元素出队列并打印。(如果觉得抽象,可以画图感受一下。)

//实现层次遍历(就是一层一层遍历)//思路:将根节点放入一个队列中,然后每次取出这个节点后,相应地将它的左右子节点依次放入队列//     中,按照队列的先进先出的特性,依次将元素出队列并打印。public void levelTrival(Node node){//创建一个队列ArrayDeque<Node> queue = new ArrayDeque<Node>(10);//将开始的结点放入到队列中queue.add(node);while (!queue.isEmpty()){//将队列中的结点出列Node n = queue.poll();System.out.print(n.item+" ");//将左子节点放入到队列中if (n.left != null){queue.add(n.left);}//将右子节点放入到队列中if (n.right != null){queue.add(n.right);}}}

5.main方法执行

public class TestBinaryTree {public static void main(String[] args) {BinaryTree bTree = new BinaryTree();//创建二叉树bTree.createTree();//执行前序遍历二叉树bTree.preTrival(bTree.root);System.out.println("--------------------");//执行中序遍历二叉树bTree.midTrival(bTree.root);System.out.println("---------------------");//执行后序遍历二叉树bTree.postTrival(bTree.root);System.out.println("---------------------");//执行层次遍历bTree.levelTrival(bTree.root);}
}

五、二叉树的查询和删除:

1.二叉树的查询:

查询可以选择任意一种遍历方式,在遍历的同时对当前元素的值进行比较判断。 

这里选用先序遍历的方式来实现:

    //实现树的查询,按先序遍历//思路:可以选择任意一种遍历方式,在遍历的同时对当前元素的值进行比较判断即可。public Node preSearch(Node node, Object obj){//先判断树是否为nullif (node == null){return null;}//定义一个target用于接收preSearch的返回值,如果找到则接收当前结点,否则接收nullNode target = null;if (node.item == obj){//找到元素return node;}else {//先遍历左子树target = preSearch(node.left,obj);//判断是否找到元素if (target != null){return target;}//再遍历右子树target = preSearch(node.right,obj);//判断是否找到元素if (target != null){return target;}}return null;}

2.二叉树的删除:

因为二叉树不像平衡树那么复杂,删除元素要考虑到平衡等因素,所以删除二叉树的元素时,如果是叶子结点则直接赋予null,如果是非叶子结点则将整个子树删除,也就是给当前非叶子结点赋予null。

//实现树的删除//思路:遍历树将树的每一个元素与目标值进行比较,找到了就将其设为null,//     如果是叶子结点,则直接设为null,如果是非叶子结点,就将整个子树删除,也就是将此节点设为null即可。public void deleteNode(Node node,Object obj){//先判断树是否为空if (node == null){return;}//判断根节点是否为目标结点if (node == root && root.item == obj){this.root = null;}//判断子节点是否为目标//先判断左子树是否存在目标if (node.left != null){if (node.left.item == obj){//删除左子节点node.left = null;return;}else {//从子树中进行删除deleteNode(node.left,obj);}}//再判断右子树是否存在目标if (node.right != null){if (node.right.item == obj){//删除左子节点node.right = null;return;}else {//从子树中进行删除deleteNode(node.right,obj);}}}

3.main方法执行:

public class TestBinaryTree02 {public static void main(String[] args) {BinaryTree bTree = new BinaryTree();bTree.createTree();//查询结点BinaryTree.Node result = bTree.preSearch(bTree.root, 13);if (result != null){System.out.println("结果:"+result.item);}else {System.out.println("没有此节点");}//删除结点bTree.deleteNode(bTree.root,2);bTree.levelTrival(bTree.root);}
}

六、二叉树深度的计算

//二叉树高度的计算你(深度)//思路:将左子树与右子树进行递归比较,最后返回最深的值。//     比如从根节点开始,比较其左子树、右子树,到了左子树、右子树这边,再比较其对应的左子树右子树,//     以此循环,用递归的方式来判断。public int maxDepth(Node node){//先判断树是否为空if (node == null){return 0;}int leftDepth = 0;int rightDepth = 0;//1.先获取左子树的高度if (node.left != null){leftDepth = maxDepth(node.left);}//2.再获取右子树的高度if (node.right != null){rightDepth = maxDepth(node.right);}//3.判断左右子树谁大if (leftDepth > rightDepth){return leftDepth + 1;}else {return rightDepth + 1;}}

七、线索化二叉树:

在使用前序、中序、后序遍历的时候,都会用到递归,过多的使用递归可能会导致栈内存的溢出,这个时候可能通过将二叉树进行线索化,来避免使用递归进行树的遍历。

 在有N个节点的二叉树中会存在N+1个空指针域。可以利用这些空指针域,存放指向节点在某种遍历(前、中、后)下的前驱或后继节点的指针。

公式:2n(n-1),每个节点有两个指针,如果需要连接其他节点必须要使用n-1个指针,剩下的指针就是空的。

这种加了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。

线索二叉树的应用:

(1)首先将二叉树进行线索化

(2)然后直接通过循环添加的线索遍历树,从而避免使用递归

八、堆排序概述:

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,它是一种选择排序,它的最坏、最好、平均时间复杂度均为O(nlog2^{n}

堆是一棵完全二叉树:

(1)当所有的结点的值都大于或者等于其左右的子节点的值称为大顶堆。

(2)当所有的结点的值都小于或者等于其左右的子节点的值称为小顶堆。

 

 


https://www.dgrt.cn/a/2109915.html

相关文章

h5与APP交互

两端交互安卓&#xff1a;https://github.com/lzyzsd/JsBridge IOS&#xff1a;https://github.com/marcuswestin/WebViewJavascriptBridge 两者一起用的话会起冲突&#xff0c;需要判断一下是什么终端&#xff0c;然后分别调用&#xff0c; var u navigator.userAgent; var i…

ADV-216 5-3日历

问题描述已知2007年1月1日为星期一。设计一函数按照下述格式打印2007年以后&#xff08;含&#xff09;某年某月的日历&#xff0c;2007年以前的拒绝打印。为完成此函数&#xff0c;设计必要的辅助函数也是必要的。样例输入一个满足题目要求的输入范例。例&#xff1a;2050 3样…

openfeign 全局日志打印

文章目录[TOC](文章目录)前言一、openfeign 集成二、配置使用1.全局feign 配置2.yml feign配置总结前言 feign 相对于 resttemplate 来说不仅兼具他的功能,而且比他更强大,所以当项目为springcloud架构之后,无论是服务之间的调用,还是其他的http调用,都应该统一用feign处理; 如…

动态代理和AOP人(面向切面编程)

1.什么是动态代理 1&#xff09;动态代理就是利用JDK的API动态的在内存中构建代理对象&#xff0c;因此&#xff0c;动态代理也叫做JDK代理&#xff0c;或者接口代理&#xff0c;在动态代理中&#xff0c;代理对象不需要实现接口&#xff0c;但是被代理对象还是需要实现对象的…

ADV-231-扑克排序

问题描述扑克牌排序&#xff1a;构造扑克牌数组&#xff0c;对扑克牌进行排序。排序原则如下&#xff1a;数字从小到大是2-10、J、Q、K和A&#xff0c;花色从小到大是方块&#xff08;diamond&#xff09;、梅花&#xff08;club&#xff09;、红桃&#xff08;heart&#xff0…

ADV-230-三角形

问题描述为二维空间中的点设计一个结构体&#xff0c;在此基础上为三角形设计一个结构体。分别设计独立的函数计算三角形的周长、面积、中心和重心。输入三个点&#xff0c;输出这三个点构成的三角形的周长、面积、外心和重心。结果保留小数点后2位数字。样例输出与上面的样例输…

windows通过浏览器访问noVNC(基于web的远程桌面)

目录 一、什么是VNC 和 noVNC&#xff1f; 二、Windows10安装及配置noVNC 2.0、注释 2.1、下载UltraVNC 2.2、下载Node.js 2.3、下载安装git 2.4、创建一个存放文件的文件夹 2.5、安装ws、optimist、mime-types模块&#xff08;执行websockify.js文件所需&#xff09; …

一文读懂Hinton最新Capsules论文

Capsule&#xff1a;实体的视觉数学表征深度学习&#xff0c;其实就是一系列的张量变换。 从图像、视频、音频、文字等等原始数据中&#xff0c;通过一系列张量变换&#xff0c;筛选出特征数据&#xff0c;以便完成识别、分解、翻译等等任务。 譬如原始数据是 28 x 28 的黑白图…