平衡二叉树

有些情况下我们的二叉排序树更像单链表,什么情况呢?

如果有一个数列为1,2,3,4,5,6,那么他的二叉排序树是不是就不怎么好看了

虽然不怎么影响添加删除的速度,但是可能会影响我们的查询速度的

存在的问题

左子树全部为空,从形式.上看,更像一个单链表.

插入速度没有影响,查询速度明显降低(因为需要依次比较),不能发挥BST的优势,因为每次还需要比较左子树,其查询速度比单链表还慢

基本介绍

平衡二叉树也叫平衡二叉搜索树(Self- balancing binary search tree)又被称为AVL树,可以保证查询效率较高

具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,,并且左右两个子树都是一颗平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、 伸展树等。

举例:说说下面那个是平衡二叉树

第一个第二个都是平衡二叉树,第三个不是平衡二叉树

注意:二叉排序树的前提是满足二叉排序树

创建平衡二叉树

要求:给你一一个数列,创建出对应的平衡二叉树数列{4,3,6,5,7,8}

本例采用视频教学的左旋转

思路:

简单代码

package 平衡二叉树;public class avl {public static void main(String[] args) {int[] arr = {4,3,6,5,7,8};AVLTree avlTree = new AVLTree();//添加节点for(int i = 0;i<arr.length;i++){avlTree.addNode(new Node(arr[i]));}//遍历System.out.println("中序遍历");avlTree.infixOrder();System.out.println("在做平衡旋转后");System.out.println(avlTree.getRoot().height());//4System.out.println("左子树的高度"+avlTree.getRoot().leftHeight());//1System.out.println("右子树的高度"+avlTree.getRoot().rightHeight());//3//因此需要右子树左旋转}}//创建avl树
class AVLTree{private Node root;public Node getRoot() {return root;}public void setRoot(Node root) {this.root = root;}//添加节点的方法public void addNode(Node node){if(root == null){root = node;}else{root.addNode(node);}}//中序遍历public void infixOrder(){if(root != null){root.infixOrder();}else{System.out.println("空树");}}//查找要删除的节点public Node search(int value){if(root == null){return null;}else{return root.search(value);}}//查找待删除节点的父节点public Node searchParent(int value){if(root == null){return null;}else{return root.searchParent(value);}}//编写方法/*** 返回最小节点值,并且删除以node为根节点的二叉排序树的最小节点* @param node   当做一颗二叉排序树的根节点* @return     返回的以node为根节点的二叉排序树的最小节点的值*/public int delRightTreeMin(Node node){Node target = node;//循环查找左子节点,就会找到最小值while(target.left != null){target = target.left;}//这是target就指向了最小节点//删除最小节点delNode(target.value);return target.value;}//删除叶子结点的方法public void delNode(int value){if(root == null){return;}else{//1.需要先去找到待删除节点Node targetNode = search(value);//如果没有找到if(targetNode == null){return;}//如果当前这课二叉排序树只有一个节点if(root.left == null&& root.right == null){root = null;return;}//去查找targetNode的父节点Node parent = searchParent(value);//如果待删除的节点是叶子结点if(targetNode.left == null && targetNode.right == null){//如果targetNode是parent的左子节点if(parent.left != null && parent.left.value == targetNode.value){parent.left = null;}else if(parent.right != null && parent.right.value == targetNode.value){parent.right = null;}}else if(targetNode.left!=null && targetNode.right != null){int minValue = delRightTreeMin(targetNode.right);targetNode.value = minValue;}else{//删除只有一个子树的节点//如果删除的节点有左子节点if(targetNode.left != null){if(parent.left.value == targetNode.value){parent.left = targetNode.left;}else{parent.right = targetNode.left;}}else{//要删除的节点有右子节点if(parent.left.value == targetNode.value){parent.left = targetNode.right;}else{parent.right = targetNode.right;}}}}}
}class Node{int value;Node left;Node right;public Node(int value) {super();this.value = value;}@Overridepublic String toString() {return "Node [value=" + value + "]";}//返回当前节点的高度=以根节点为树的高度public int height(){return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height())+1;}//返回左子树的高度public int leftHeight(){if(left == null){return 0;}return left.height();}//返回右子树的高度public int rightHeight(){if(right == null){return 0;}return right.height();}//左旋转方法private void leftRotate(){//创建新节点,是当前的根节点的值Node node = new Node(value);//把新的节点的左子树,指向当前节点的左子树node.left = left;//把新的节点的右子树设置成当前节点的右子树的左子树node.right = right.left;//把当前节点的值,替换成右子节点的值value = right.value;//把当前节点的右子树设置成右子树的右子树right = right.right;//把当前节点的左子树,设置成我们新加的那个节点left = node;}/*** 查找待删除的节点* @param value 待删除节点的值* @return*/public Node search(int value){if(value == this.value){return this;}else if(value < this.value){//应该向左子树递归查找if(this.left != null){return this.left.search(value);}else{return null;}}else{if(this.right == null){return null;}else{return this.right.search(value);}}}/*** 查找待删除节点的父节点* @param value     待删除节点的值* @return     返回待删除节点的父节点*/public Node searchParent(int value){if((this.left !=null && this.left.value == value) || (this.right != null && this.right.value == value)){//当前节点就是待删除节点的父节点return this;}else{//如果查找的值,小于当前节点的值,且当前节点的左子节点不为空if(value < this.value && this.left != null){return this.left.searchParent(value);}else if(value >= this.value && this.right != null){return this.right.searchParent(value);}else{return null;//没有找到父节点}}}//添加节点的方法//递归的形式添加节点,需要满足二叉排序树public void addNode(Node node){if(node == null){return;}//判断传入的节点值,跟当前子树根节点值的关系if(node.value < this.value){//如果当前节点的左子节点为空if(this.left == null){this.left = node;}else{this.left.addNode(node);//递归添加}}else{if(this.right == null){this.right = node;}else{this.right.addNode(node);}}//当添加完一个节点后,如果右子树的高度-左子树的高度>1,左旋转if(rightHeight() - leftHeight() > 1){leftRotate();//左旋转}}//中序遍历public void infixOrder(){if(this.left != null){this.left.infixOrder();}System.out.println(this);if(this.right != null){this.right.infixOrder();}}
}

上面我们是把问题想成最简单的情况,只有右子树左旋,

那如果有其他情况呢?

右旋转

同理只需要写出对应的右旋转方法即可,这个地方我就专贴方法代码了

 //右旋转private void rightRotate(){Node newNode = new Node(value);newNode.right = right;newNode.left = left.right;value = left.value;left = left.left;right = newNode;}

问题

如果我们的数组换成10,11,7,6,8,9我们就会发现,即使我们进行了平衡处理,但是依然不是一个平很二叉树

这是为什么呢?

根据这个图,我们不难看出,右旋转就是把8,9旋转过去,但是这个数正好很特别,导致,即使旋转过去还是不平衡的

1.当符合右旋转的条件时
2.如果它的左子树的右子树高度大于它的左子树的高度
3.先对当前这个结点的左节点进行左旋转
4.对当前结点进行右旋转的操作即可

代码修改

主要是在我们的添加节点的时候,加上一些逻辑判断

 //添加节点的方法//递归的形式添加节点,需要满足二叉排序树public void addNode(Node node){if(node == null){return;}//判断传入的节点值,跟当前子树根节点值的关系if(node.value < this.value){//如果当前节点的左子节点为空if(this.left == null){this.left = node;}else{this.left.addNode(node);//递归添加}}else{if(this.right == null){this.right = node;}else{this.right.addNode(node);}}//当添加完一个节点后,如果右子树的高度-左子树的高度>1,左旋转if(rightHeight() - leftHeight() > 1){//如果它的右子树的左子树高度大于它的右子树的高度if(right != null && right.leftHeight() > right.rightHeight()){//先对右子树进行右旋转right.rightRotate();//然后对当前节点左旋转leftRotate();//左旋转}else{leftRotate();}return;}if(leftHeight() - rightHeight() > 1){//如果它的左子树的右子树高度大于它的左子树的高度if(left != null && left.rightHeight() > left.leftHeight()){//先对当前节点的左节点(左子树)进行左旋转left.leftRotate();//在对当前节点进行右旋转rightRotate();}else{rightRotate();}}}

数据结构-----平衡二叉树相关推荐

  1. 数据结构---平衡二叉树

    数据结构-平衡二叉树 原理:参考趣学数据结构 代码: #include<stdio.h> #include<stdlib.h> typedef struct avlTree { ...

  2. 用c语言编译二叉树,C语言 数据结构平衡二叉树实例详解

    数据结构平衡二叉树 参考代码如下: /* 名称:平衡二叉树 语言:数据结构C语言版 编译环境:VC++ 6.0 日期: 2014-3-26 */ #include #include #include ...

  3. 数据结构——平衡二叉树的的旋转问题

    在学习有关数据结构平衡二叉树的时候,我就特别困惑在二叉查找树中是如何将树旋转和交换孩子的.这里,我将自己的总结写下来,喜欢大家一起交流进步!        这个需要旋转的情况大体可以·分为4种情况.分 ...

  4. 数据结构-平衡二叉树(AVL树)

    目录 1,平衡二叉树的介绍 1.1,二叉排序树存在的问题 1.2,平衡二叉树 1.3,平衡二叉树的创建 1.4,平衡二叉树的查找 2,代码实现 2.1,平衡二叉树的节点类型 2.2,LL旋转(单右旋转 ...

  5. 数据结构 — 平衡二叉树

    目录 文章目录 目录 平衡二叉树 平衡二叉树 平衡二叉查找树具有如下性质: 若左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值: ...

  6. 数据结构 - 平衡二叉树

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 平衡二叉 ...

  7. 浅谈数据结构-平衡二叉树

    平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树.1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵 ...

  8. 数据结构——平衡二叉树

    一.平衡二叉树的定义 平衡二叉树(AVL 树)仍然是一棵二叉查找树,只是在其基础上增加了"平衡"的要求.所谓平衡是指,对 AVL 树的任意结点来说,其左子树与右子树的高度之差的绝对 ...

  9. 数据结构 平衡二叉树avl c++

    平衡二叉树:一颗空树,或者是具有以下性质的二叉树 左子树和右子树都是平衡二叉树 左子树和右子树的深度只差不超过1 把二叉树节点的平衡因子BF(Balance Factor)定义为该节点的左子树深度减去 ...

  10. [ 数据结构 ] 平衡二叉树(AVL)--------左旋、右旋、双旋

    0 引出 数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在 回顾:二叉搜索树 左子树全部为空,从形式上看,更像一个单链表. 插入速度没有影响 查询速度明显降低(因为需 ...

最新文章

  1. 关于Docker目录挂载的总结(转)
  2. LeetCode 464 Can I Win(min-max博弈算法)
  3. SCII码表 键盘常用ASCII码
  4. django mysql搜索_Django--数据库查询操作
  5. chatbot2 RNN语言模型
  6. Docker+Nginx部署Angular
  7. Java对象使用的重要细节
  8. matlab安装前有兼容性问题,matlab安装及问题解决
  9. 数字图像处理与分析---指纹图像增强(Python)
  10. 手机安装php7,php7.3编译安装时报错system libzip must be upgraded to version = 0.11
  11. MaxCompute SQL
  12. 腾讯优图实现人脸对比
  13. 为什么电脑浏览器显示时钟快了_打开网站提示您的时钟快了_网页显示您的时钟慢了,解决方法...
  14. SCI-EI-收录-检索-出版商 之间的关系
  15. Unity3D 射击游戏练习实例
  16. C++虚函数实现机制
  17. 火狐浏览器主页被篡改的解决办法!
  18. 李宏毅机器学习(22)
  19. 用计算机完成的计算方法电脑,计算机的计算器在哪_自己的电脑上的计算器在哪里找-win7之家...
  20. c语言停车场的收费管理系统,c语言停车场管理系统

热门文章

  1. vue 封装dialog_GitHub - 1014156094/vue-mobile-dialog: Vue移动端基础组件 - 对话框
  2. Node:根据开发环境配置axios默认路径
  3. Go语言:基础数据类型
  4. 热流体动压润滑matlab_仿真加快摩擦润滑研究进程
  5. 存储过程别忘了写最后一句话,别忘了类型转换
  6. 随手记_重建的五花八门的点云地图效果(供娱乐)
  7. Facebook最新研究:全局一致的视频深度估计
  8. 论文阅读-目标检测(2019)-CenterNet:目标检测转化为关键点检测及其属性回归
  9. opencv图像分析与处理(11)- 频率域滤波消除周期噪声
  10. 吴恩达教授机器学习课程笔记【九】- k均值聚类算法