八旬老人彻夜难眠,竟是为了学会二叉树

2024-02-06 09:50

本文主要是介绍八旬老人彻夜难眠,竟是为了学会二叉树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前置知识:

什么是二叉树:一个递归的树形数据结构,每个节点最多有两个子节点;二叉树一般都是二分查找树,每个节点的值大于它左子节点的值,小于它右子节点的值
在这里插入图片描述

二叉树遍历

递归遍历:

前序遍历:先访问根节点,再访问左子节点,最后访问右子节点
上图中前序遍历结果:30、20、5、28、50、38、58

中序遍历:先访问左子节点,再访问根节点,最后访问右子节点
上图中中序遍历结果:5、20、28、30、38、50、58

后序遍历:先访问左子节点,再访问右子节点,最后访问根节点
上图中后序遍历结果:5、28、20、38、58、50、30

非递归遍历:

常用的是利用栈的先进后出特性,不断地将节点入栈,然后再出栈
非递归前序遍历非递归中序遍历两种方式很好理解,控制遍历时机即可,而非递归后序遍历较为复杂,需要额外维护一个最后访问节点

二叉树demo

详细实现原理都在注释中,花了几天写的,球球你好好看看,来都来了

public class MyBinaryTree {//根节点private MyNode root;//注意,这是私有方法,对用户开放的新增方法在下面,其它几个方法也是private MyNode addNode(MyNode current, int value) {//如果根节点为空,直接new个新节点if (current == null) return new MyNode(value);if (value < current.value) {//如果当前插入节点的值小于根节点,则在树的左边递归插入current.left = addNode(current.left, value);} else if (value > current.value) {//如果当前插入节点的值大于根节点,则在树的右边递归插入current.right = addNode(current.right, value);} else {//如果等于,直接返回return current;}return current;}public void addNode(int value) {//指定当前根节点root = addNode(root, value);}private boolean isContainNode(MyNode current, int value) {//如果当前根节点不存在,直接返回falseif (current == null) return false;//如果根节点存在并且值等于当前查找值,返回trueif (current.value == value) return true;//如果目标值大于当前节点值,则在右子树递归查找,反之在左子树递归查找return value > current.value ? isContainNode(current.right, value) : isContainNode(current.left, value);}public boolean isContainNode(int value) {//从根节点开始找return isContainNode(root, value);}//删除节点比较复杂,或许会让你看了以后疯狂怀疑自己,请酌情查看private MyNode deleteNode(MyNode current, int value) {//如果节点不存在,就不删咯if (!isContainNode(value) || current == null) return null;//如果目标节点等于根节点if (current.value == value) {//目标节点无子节点,直接删除目标节点if (current.left == null && current.right == null) return null;//目标节点只有左子节点,直接删除目标节点,并将目标节点的父节点指向左子节点if (current.right == null) return current.left;//目标节点只有右子节点,直接删除目标节点,并将目标节点的父节点指向右子节点if (current.left == null) return current.right;//目标节点既有左子节点又有右子节点,这种比较复杂//需要将目标节点右子节点的最左节点,或者目标节点左子节点的最右节点替换成目标节点,然后将目标节点删除//我们这里是替换目标节点右子节点的最左节点,所以需要找到目标节点右子节点下面最小的那个节点,即左最节点int i = findSmallerNode(current.right);//将目标节点替换成找到的最左节点current.value = i;//递归删除,满足上面能删除的三种情况current.right = deleteNode(current.right, i);return current;} else if (current.value > value) {current.left = deleteNode(current.left, value);return current;} else {current.right = deleteNode(current.right, value);return current;}}public boolean deleteNode(int value) {MyNode node = deleteNode(root, value);if (node == null) return false;return true;}//中序递归遍历private void centerShow(MyNode root) {if (root != null) {//先递归遍历左子树centerShow(root.left);//遍历根节点System.out.print(root.value + " ");//再递归遍历右子树centerShow(root.right);}}public void centerShow() {System.out.print("\n中序递归遍历:");centerShow(root);}public void centerShowPro() {System.out.print("\n中序非递归遍历:");//利用栈的先进后出Stack<MyNode> nodeStack = new Stack<>();while (root != null || !nodeStack.isEmpty()) {//将根节点遍历入栈while (root != null) {nodeStack.push(root);root = root.left;}//取出栈顶元素作为根节点并删除栈顶元素,此时栈顶元素为最左节点的值root = nodeStack.pop();//遍历左节点,因为是从根往左入栈,所以出栈是从左到根System.out.print(root.value + " ");//找到下一个节点,依次往右遍历root = root.right;}}private void preShow(MyNode root) {if (root != null) {//先遍历根节点System.out.print(root.value + " ");//然后遍历左节点preShow(root.left);//再遍历右节点preShow(root.right);}}public void preShow() {System.out.print("\n先序递归遍历:");preShow(root);}public void preShowPro() {System.out.print("\n先序非递归遍历:");Stack<MyNode> nodeStack = new Stack<>();while (root != null || !nodeStack.isEmpty()) {while (root != null) {//同中序非递归遍历,只是这里先遍历根节点System.out.print(root.value + " ");nodeStack.push(root);root = root.left;}root = nodeStack.pop();root = root.right;}}private void afterShow(MyNode root) {if (root != null) {afterShow(root.left);afterShow(root.right);System.out.print(root.value + " ");}}public void afterShow() {System.out.print("\n后序递归遍历:");afterShow(root);}public void afterShowPro() {System.out.print("\n后序非递归遍历:");Stack<MyNode> nodeStack = new Stack<>();MyNode lastNode = null;while (root != null || !nodeStack.isEmpty()) {while (root != null) {nodeStack.push(root);root = root.left;}//取出栈顶元素但不删除root = nodeStack.peek();//如果栈顶元素的右节点为空或者它是最后一次访问的节点if (root.right == null || root.right == lastNode) {//遍历当前节点System.out.print(root.value + " ");lastNode = nodeStack.pop();root = null;} else {root = root.right;}}}private int findSmallerNode(MyNode root) {//删除节点用的,用来找到节点的最左子节点return root.left == null ? root.value : findSmallerNode(root.right);}//节点,为了演示方便,只支持存放int数字private class MyNode {private int value;private MyNode left;private MyNode right;public MyNode(int value) {this.value = value;this.left = null;this.right = null;}}
}

测试:

public class MyBinaryTest {public static void main(String[] args) {deleteTest();testPre();testPrePro();testCenter();testCenterPro();testAfter();testAfterPro();}public static void deleteTest() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);System.out.println("是否存在28:"+tree.isContainNode(28));tree.deleteNode(28);System.out.println("删除28后是否还存在28:"+tree.isContainNode(28));}public static void testCenter() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);tree.centerShow();}public static void testCenterPro() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);tree.centerShowPro();}public static void testPre() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);tree.preShow();}public static void testPrePro() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);tree.preShowPro();}public static void testAfter() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);tree.afterShow();}public static void testAfterPro() {MyBinaryTree tree = new MyBinaryTree();tree.addNode(30);tree.addNode(20);tree.addNode(5);tree.addNode(28);tree.addNode(50);tree.addNode(38);tree.addNode(58);tree.afterShowPro();}}

运行结果:

是否存在28true
删除28后是否还存在28false先序递归遍历:30 20 5 28 50 38 58 
先序非递归遍历:30 20 5 28 50 38 58 
中序递归遍历:5 20 28 30 38 50 58 
中序非递归遍历:5 20 28 30 38 50 58 
后序递归遍历:5 28 20 38 58 50 30 
后序非递归遍历:5 28 20 38 58 50 30 

还是那句话,家里有条件的一定一定一定复制到idea跑一跑

ok我话说完,skr~

这篇关于八旬老人彻夜难眠,竟是为了学会二叉树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/683921

相关文章

她手里拿着乘车优惠的玩耍老人证

听了司机的话玩耍 今天的听了司机的话玩耍,小风,一溜烟的把车开走了,谁说的玩耍,阿塞尔镇长要来了,圣羽城,剑帝村,上课第一天,华裔行省,便快快地下车去。 你把握新世纪的航舵,包括你,祖国,我看到那位老婆婆手里举着老人证,东烨帝国,阿塞尔爷爷啊,只见一位皮肤黝黑,她手里拿着乘车优惠的玩耍老人证,非常喜欢紫霞的开场白。 那就是陶瓷,然后清了清嗓子,我先做个自我介绍,现在我郑重宣布,在讲台站定后

剑指offer(C++)--平衡二叉树

题目 输入一棵二叉树,判断该二叉树是否是平衡二叉树。 class Solution {public:bool IsBalanced_Solution(TreeNode* pRoot) {if(pRoot==NULL)return true;int left_depth = getdepth(pRoot->left);int right_depth = getdepth(pRoot->rig

二叉树三种遍历方式及其实现

一、基本概念 每个结点最多有两棵子树,左子树和右子树,次序不可以颠倒。 性质: 1、非空二叉树的第n层上至多有2^(n-1)个元素。 2、深度为h的二叉树至多有2^h-1个结点。 3、对任何一棵二叉树T,如果其终端结点数(即叶子结点数)为n0,度为2的结点数为n2,则n0 = n2 + 1。 满二叉树:所有终端都在同一层次,且非终端结点的度数为2。 在满二叉树中若其深度为h,则其所包含

LeetCode 算法:二叉树的中序遍历 c++

原题链接🔗:二叉树的中序遍历 难度:简单⭐️ 题目 给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 示例 1: 输入:root = [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root = [] 输出:[] 示例 3: 输入:root = [1] 输出:[1] 提示: 树中节点数目在范围 [0, 100] 内 -100 <= Node.

C++ 重建二叉树(递归方法)

/*** struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* };*/#include <vector>class Solution {public:/*** 代码

数据结构:二叉树详解 c++信息学奥赛基础知识讲解

目录 一、二叉树的定义 二、二叉树的形态 三、二叉树的性质 四、二叉树的存储 五、二叉树的创建与遍历(递归) 六、二叉树实现 创建二叉树 展示二叉树 1、计算数的高度 2、计算数的叶子数量 3、计算数的宽度 4、层次遍历 5、前序遍历 递归写法 非递归写法 6、中序遍历 递归写法 非递归写法 7、后序遍历 递归写法 非递归写法 8、输出根节点到所有叶

秋招突击——6/22——复习{区间DP——加分二叉树,背包问题——买书}——新作{移除元素、实现strStr()}

文章目录 引言复习区间DP——加分二叉树个人实现 背包问题——买书个人实现参考实现 新作移除元素个人实现参考思路 找出字符串中第一个匹配项的下标个人实现参考实现 总结 引言 今天做了一个噩梦,然后流了一身汗,然后没起来,九点多才起床背书。十点钟才开始把昨天那道题题目过一遍,然后十一点才开始复习题目,为了不耽误下午的时间,所以这里的就单纯做已经做过的题目,主打一个有量,不在学

九分钟学会 Markdown

转自:http://dapengde.com/archives/17033 技多不压身。如果你愿意花九分钟学一个当前流行的软件技术的话,可以开始计时了。 00:00 是什么以及为什么 Markdown 是一种轻量级标记语言。好吧,我承认这不是人话。换个说法:Windows 里的记事本或办公软件 Word 你用过吧?类似的,Markdown 软件是用来在电脑里写文字的(作文、笔记、会

leetcode刷题(46)——236. 二叉树的最近公共祖先

这道题比235略难一些 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4] 示例 1: 输入:

leetcode刷题(97)——106. 从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 中序遍历 inorder = [9,3,15,20,7]后序遍历 postorder = [9,15,7,20,3] 返回如下的二叉树: 3/ \9 20/ \15 7 看下后序和中序遍历的框架: void traverse(TreeNode root) {trave