ds查找—二叉树平衡因子_面试官让我手写一个平衡二叉树,我当时就笑了
平衡二叉树对于初学者一直是一个比较复杂的知识点,因为其里面涉及到了大量的旋转操作。把大量的同学都给转晕了。这篇文章最主要的特点就是通过动画的形式演示。确保大家都能看懂。最后是手写一个平衡二叉树。
一、概念
平衡二叉树是外国的两个大爷发明的。一开始发明的是二叉查找树。后来觉得不给力演化成了平衡二叉树。那什么是二叉查找树呢?我们给出一张图来看看:
看到这张图我们就会发现如下的特征。从每个节点出发,左边的节点一定小于右边的。但是你会发现这可以高低不平,看起来很不美观。于是慢慢的演化成了平衡二叉树。(当然不是因为美观演化的)。也就是说平衡二叉树的前提就是一颗二叉查找树
平衡二叉树定义(AVL):(1)它的左子树和右子树的深度之差(平衡因子)的绝对值不超过1,(2)它的左子树和右子树都是一颗平衡二叉树。
也就是说以上两条规则,只要破坏了一个就不是平衡二叉树了。比如说下面这张图。
上面这张图就是破坏了二叉查找树这一条规则。当然了还有一条规则。也就是他的高度只差不能超过1.
现在相信我们已经明白了什么是平衡二叉树。下面我们就来看看平衡二叉树的增删改查操作是怎么样的。
二、平衡二叉树的插入操作
我们先从最简单的入手,一步一步来。
1、右旋
首先我们插入几个数字,50,45,44。通过动画我们来演示一遍
(1)插入50根节点不会出现任何操作
(2)插入45,往左边插入即可
(3)插入44,破坏了平衡,于是右旋。
2、左旋
我们插入几个数字,50,60,70。通过动画我们来演示一遍
(1)插入50根节点不会出现旋转
(2)插入60,往右边插入即可
(3)插入70,破坏了平衡,于是左旋。
3、先右旋再左旋
我们依次插入50,60,55.通过动画我们演示一遍
(1)插入55,根节点,不会出现旋转
(2)插入60,往右边插入
(3)插入55,破坏了平衡,于是先把55和60右旋,然后整体左旋。
4、先左旋后右旋
我们依次插入50,40,45.通过动画我们演示一遍。
(1)插入55,根节点,不会出现旋转
(2)插入40,往左边插入
(3)插入45,破坏了平衡,于是先把45和40左旋,然后整体右旋。
现在我们基本上已经把插入的几种情况罗列出来了。现在我们画一张图,来一个总结。
上图对于每一种情况,从上往下看就好了。对于平衡二叉树的删除操作,其实也是同样的道理,找到相应的元素之后,对其进行删除,删除之后如果破坏了平衡,只需要按照上面的这几种情况进行调整即可。下面我们来分析一下平衡二叉树的查找操作。
三、平衡二叉树的查找
平衡二叉树的查找很简单,只需要按照二叉查找树的顺序执行就好。我们使用一张动画演示一下:
现在平衡二叉树的操作相信你已经能够理解。下面我们就来关注最后一个问题,那就是如何手写一颗平衡二叉树呢?
四、手写一颗平衡二叉树
平衡二叉树的代码操作,难点在于旋转。只要把旋转弄清楚基本上整个树就能完成了,根据上面旋转的特点我们从零开始定义一颗。
第一步:定义节点
public class AVLNode {public int data;//保存节点数据public int depth;//保存节点深度public int balance;//是否平衡public AVLNode parent;//指向父节点public AVLNode left;//指向左子树public AVLNode right;//指向右子树
public AVLNode(int data){this.data = data;depth = 1;balance = 0;left = null;right = null;}}
第二步:插入数据
public void insert(AVLNode root, int data){//如果说插入的数据小于根节点,往左边递归插入if (data < root.data){if (root.left != null){insert(root.left, data);}else {root.left = new AVLNode(data);root.left.parent = root;}}//如果说插入的数据小于根节点,往左边递归插入else {if (root.right != null){insert(root.right, data);}else {root.right = new AVLNode(data);root.right.parent = root;}}//插入之后,计算平衡银子root.balance = calcBalance(root);// 左子树高,应该右旋if (root.balance >= 2){// 右孙高,先左旋if (root.left.balance == -1){left_rotate(root.left);}right_rotate(root);}// 右子树高,左旋if (root.balance <= -2){// 左孙高,先右旋if (root.right.balance == 1){right_rotate(root.right);}left_rotate(root);}//调整之后,重新计算平衡因子和树的深度root.balance = calcBalance(root);root.depth = calcDepth(root);
}
第三步:左旋和右旋的调整
1、右旋
// 右旋private void right_rotate(AVLNode p){// 一次旋转涉及到的结点包括祖父,父亲,右儿子AVLNode pParent = p.parent;AVLNode pLeftSon = p.left;AVLNode pRightGrandSon = pLeftSon.right;// 左子变父pLeftSon.parent = pParent;if (pParent != null){if (p == pParent.left){pParent.left = pLeftSon;}else if (p == pParent.right){pParent.right = pLeftSon;}}pLeftSon.right = p;p.parent = pLeftSon;// 右孙变左孙p.left = pRightGrandSon;if (pRightGrandSon != null){pRightGrandSon.parent = p;}p.depth = calcDepth(p);p.balance = calcBalance(p);pLeftSon.depth = calcDepth(pLeftSon);pLeftSon.balance = calcBalance(pLeftSon);}
2、左旋
private void left_rotate(AVLNode p){// 一次选择涉及到的结点包括祖父,父亲,左儿子AVLNode pParent = p.parent;AVLNode pRightSon = p.right;AVLNode pLeftGrandSon = pRightSon.left;// 右子变父pRightSon.parent = pParent;if (pParent != null){if (p == pParent.right){pParent.right = pRightSon;}else if (p == pParent.left){pParent.left = pRightSon;}}pRightSon.left = p;p.parent = pRightSon;// 左孙变右孙p.right = pLeftGrandSon;if (pLeftGrandSon != null){pLeftGrandSon.parent = p;}p.depth = calcDepth(p);p.balance = calcBalance(p);pRightSon.depth = calcDepth(pRightSon);pRightSon.balance = calcBalance(pRightSon);}
第四步:计算平衡和深度
1、计算平衡
public int calcBalance(AVLNode p){int left_depth;int right_depth;//左子树深度if (p.left != null){left_depth = p.left.depth;}else {left_depth = 0;}//右子树深度if (p.right != null){right_depth = p.right.depth;}else {right_depth = 0;}return left_depth - right_depth;}
2、计算深度
public int calcDepth(AVLNode p){int depth = 0;if (p.left != null){depth = p.left.depth;}if (p.right != null && depth < p.right.depth){depth = p.right.depth;}depth++;return depth;}
看起来代码有些多,其实梳理一下就不多了。
(1)首先定义一个节点,里面有get和set方法,构造函数等等做准备工作
(2)直接写业务流程,比如说这里的insert操作,里面涉及到的旋转操作先用方法代替
(3)对主业务流程的操作,缺哪一个方法,写哪一个方法即可
ds查找—二叉树平衡因子_面试官让我手写一个平衡二叉树,我当时就笑了相关推荐
- 面试官让我手写一个生产者消费者模式?
不知道你是否遇到过面试官让你手写生产者消费者代码.别说,前段时间有小伙伴还真的遇到了这种情况,当时是一脸懵逼. 但是,俗话说,从哪里跌倒就要从哪里爬起来.既然这次被问到了,那就回去好好研究一下,争取下 ...
- DS查找—二叉树平衡因子
题目描述 二叉树用数组存储,将二叉树的结点数据依次自上而下,自左至右存储到数组中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点在数组中用0来表示. 计算二叉树每个结点的平衡因子,并按后序遍历的顺 ...
- 面试官让我手写一个RPC框架
如今,分布式系统大行其道,RPC 有着举足轻重的地位.Dubbo.Thrift.gRpc 等框架各领风骚,学习RPC是新手也是老鸟的必修课.本文带你手撸一个rpc-spring-starter,深入学 ...
- 面试官:请手写一个带取消功能的延迟函数,axios 取消功能的原理是什么
大家好,我是若川.最近组织了源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列> ...
- 面试官系统精讲Java源码及大厂真题 - 26 惊叹面试官:由浅入深手写队列
26 惊叹面试官:由浅入深手写队列 人生的价值,并不是用时间,而是用深度去衡量的. 引导语 现在不少大厂面试的时候会要求手写代码,我曾经看过一个大厂面试时,要求在线写代码,题目就是:在不使用 Java ...
- 当面试官让你手写防抖、节流时,是在考察什么
防抖.节流,都是用于节省函数调用次数的方案,达到优化程序.提升性能甚至是避免bug的目的.作为一个经典的主题,也是面试常考项,部分面试官会让你手写,这时, 他是在考察什么?你能轻易地写出比较好的防抖. ...
- 当面试官让你手写flat,是在考察什么
在面试者中,偶尔会遇到手写flat实现的面试题,如果基础不牢,或者没有准备,就容易挂.那么,这道典型的手写题,主要考察了些什么呢?本文一层层地剖析,让你豁然开朗. 考察点1: 熟不熟悉这个api 要想 ...
- 二叉树的创建_大多数人都不会手写创建并遍历二叉树,一航这里帮你终结了
创建二叉树.遍历二叉树.二叉树的最近公共祖先任何疑问.意见.建议请公众号留言或联系qq474356284先序.后序创建二叉树先中后层序遍历二叉树二叉树的最近公共祖先 输入格式: 创建二叉树时的输入: ...
- 面试官让我手写队列,差点没写出来,回来后赶忙把重点记下来
微信搜一搜[bigsai]更多精彩 点赞的帅哥美女祝你们越学越猛 目录 前言 队列介绍 普通队列 循环队列(数组实现) 循环队列(链表实现) 双向队列(加餐) 总结 前言 栈和队列是一对好兄弟,前面我 ...
最新文章
- 博士Nature发文:研究生阶段,4点经验助你学术“独立”!
- [原创]一种自动地将继承自NSObject的自定义类序列化成JSON的方法
- MyBatis框架学习:<select>节点中的resultType和resultMap属性
- rhel5.1 vncserver
- python读取excel一列-python读取excel(xlrd)
- 深入理解计算机系统 视频教程,深入理解计算机系统1
- 腾讯视频下载电脑_腾讯视频如何设置允许腾讯视频驻留功能
- 记录linux历史命令,如何将Linux系统的历史操作命令删除,并不再记录
- FFMPEG结构体分析:AVStream
- SQL Server 透视与逆透视转换解析
- php radio用法,JavaScript_JQuery radio(单选按钮)操作方法汇总,随着Jquery的作用越来越大,使 - phpStudy...
- 启用文件系统缓存,提高Tuxera NTFS运作性能
- python3 下载网络图片
- html中在线取色器,在线取色器(ColorPicker)的制造方式
- U盘PE安装原版Win10系统
- SPSS时序全局主成分分析方法
- java jxls导出excel
- SOPCAST所有频道的地址
- 学计算机拼音不好怎么办,孩子拼音基础差怎么办?告诉你学拼音技巧!
- 组装台式计算机需要哪些硬件,电脑硬件有哪些?组装一台电脑需要哪些配件详解...
热门文章
- 1.12 foreach循环遍历Collection集合
- Dubbo服务调用失败
- Synchronize读脏解决
- Java集合LinkedHashMap
- MySQL为表的所有字段添加数据
- CSS设置图片的重复
- docker tag 删除images_深入浅出 Docker (二) —— Docker的基本概念和架构原理
- anaconda+python3.6利用命令安装BeautifulSoup4-4.6.0
- emulator: ERROR: x86 emulation currently requires hardware acceleration!
- UI组件之 ProgressBar及其子类(一)ProgressBar进度条的使用