定义平衡树节点:

class TreeNode {

        /**
* 树节点的值
*/
private int val; /**
* 树的高度
*/
private int height; /**
* 左子节点
*/
private TreeNode left; /**
* 右子节点
*/
private TreeNode right; public TreeNode(int val) {
this.val = val;
} }

辅助的方法:

1.用于计算节点的高度:

/**
* 获取节点的高度
*
* @param node
* @return
*/
private int height(TreeNode node) {
return node == null ? -1 : max(height(node.left), height(node.right)) + 1;
} /**
* 获取二者中较大的
*
* @param a
* @param b
* @return
*/
private int max(int a, int b) {
return a >= b ? a : b;
}

2.获取节点的平衡因子(即左子树与右子树的高度差):

    /**
* 获取节点的平衡因子
*
* @param node
* @return
*/
private int getBalanceFactor(TreeNode node) {
return node == null ? -1 : height(node.left) - height(node.right);
}

AVL树插入数据的四种结构:

第一种:

只需要实现单次右旋:

    /**
* 右旋
* 返回旋转后新的节点
* @param tree 待旋转的节点
*/
private TreeNode rightRotate(TreeNode tree) {
//拷贝源节点的左节点
TreeNode node = tree.left;
tree.left = node.right;
node.right = tree;
//重新计算节点的高度
node.height = height(node);
// tree.height = height(tree);
tree = null; //help gc
return node;
}

第二种:

先左旋节点的左子节点,再右旋节点:

//先左旋左节点,再右旋节点
node.left = leftRotate(node.left);
return rightRotate(node);

第三种:

只需要实现单次左旋:

   /**
* 左旋
*
* @param tree 待旋转的节点
*/
private TreeNode leftRotate(TreeNode tree) {
TreeNode node = tree.right;
tree.right = node.left;
node.left = tree;
//重新计算节点的高度
node.height = height(node);
// tree.height = height(tree);
tree = null; //help gc
return node;
}

第四种:

先右旋右子节点,再左旋:

//先右旋右节点,再左旋节点
node.right = rightRotate(node.right);
return leftRotate(node);

出入数据的完整实现:

public class AvlTree {

    static class TreeNode {

        /**
* 树节点的值
*/
private int val; /**
* 树的高度
*/
private int height; /**
* 左子节点
*/
private TreeNode left; /**
* 右子节点
*/
private TreeNode right; public TreeNode(int val) {
this.val = val;
} } /**
* 插入节点key到以node为根的树中
*
* @param node
* @param key
* @return
*/
public TreeNode add(TreeNode node, int key) {
//1.插入节点:
if (node == null)
return new TreeNode(key);
if (key < node.val) {
//查找左树
node.left = add(node.left, key);
} else if (key > node.val) {
//查找右树
node.right = add(node.right, key);
} else {
//do noting
return node;
}
//2.插入后更新节点的高度
node.height = max(height(node.left), height(node.right));
//3.获取平衡因子,如有失衡者,则平衡树节点
int factor = getBalanceFactor(node);
if (factor > 1) {
//左高
if (key < node.left.val) {
//只右旋转一次
return rightRotate(node);
} else {
//先左旋左节点,再右旋节点
node.left = leftRotate(node.left);
return rightRotate(node);
}
} else if (factor < -1) {
//右高
if (key > node.right.val) {
//只右旋转一次
return leftRotate(node);
} else {
//先右旋右节点,再左旋节点
node.right = rightRotate(node.right);
return leftRotate(node);
}
}
return node;
} /**
* 获取节点的平衡因子
*
* @param node
* @return
*/
private int getBalanceFactor(TreeNode node) {
return node == null ? -1 : height(node.left) - height(node.right);
} public static void main(String[] args) {
AvlTree tree = new AvlTree();
TreeNode node = null;
int[] a = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8};
for (int b : a) {
node = tree.add(node, b);
}
//遍历node
inOrder(node);
preOrder(node);
//layerOrder(node);
} /**
* 获取节点的高度
*
* @param node
* @return
*/
private int height(TreeNode node) {
return node == null ? -1 : max(height(node.left), height(node.right)) + 1;
} /**
* 获取二者中较大的
*
* @param a
* @param b
* @return
*/
private int max(int a, int b) {
return a >= b ? a : b;
} /**
* 右旋
*
* @param tree 待旋转的节点
*/
private TreeNode rightRotate(TreeNode tree) {
//拷贝源节点的左节点
TreeNode node = tree.left;
tree.left = node.right;
node.right = tree;
//重新计算节点的高度
node.height = height(node);
// tree.height = height(tree);
tree = null; //help gc
return node;
} /**
* 左旋
*
* @param tree 待旋转的节点
*/
private TreeNode leftRotate(TreeNode tree) {
TreeNode node = tree.right;
tree.right = node.left;
node.left = tree;
//重新计算节点的高度
node.height = height(node);
// tree.height = height(tree);
tree = null; //help gc
return node;
} /**
* 中序遍历测试
*
* @param node
*/
private static void inOrder(TreeNode node) {
if (node != null) {
inOrder(node.left);
System.err.println(node.val);
inOrder(node.right);
}
} /**
* 前序遍历测试
*
* @param node
*/
private static void preOrder(TreeNode node) {
if (node != null) {
System.err.println(node.val + " - height:" + node.height);
preOrder(node.left);
preOrder(node.right);
}
}
  
private static void layerOrder(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
if (root != null) queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.println(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
}

二叉查找树之AVL树的更多相关文章

  1. 数据结构——二叉查找树、AVL树

    二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...

  2. 深入浅出数据结构C语言版(12)——平衡二叉查找树之AVL树

    在上一篇博文中我们提到了,如果对普通二叉查找树进行随机的插入.删除,很可能导致树的严重不平衡 所以这一次,我们就来介绍一种最老的.可以实现左右子树"平衡效果"的树(或者说算法),即 ...

  3. 二叉查找树,AVL树,伸展树【CH4601普通平衡树】

    最近数据结构刚好看到了伸展树,在想这个东西有什么应用,于是顺便学习一下. 二叉查找树(BST),对于树上的任意一个节点,节点的左子树上的关键字都小于这个节点的关键字,节点的右子树上的关键字都大于这个节 ...

  4. 算法学习 - 平衡二叉查找树实现(AVL树)

    平衡二叉查找树 平衡二叉查找树是非常早出现的平衡树,由于全部子树的高度差不超过1,所以操作平均为O(logN). 平衡二叉查找树和BS树非常像,插入和删除操作也基本一样.可是每一个节点多了一个高度的信 ...

  5. 常见基本数据结构——树,二叉树,二叉查找树,AVL树

    常见数据结构——树 处理大量的数据时,链表的线性时间太慢了,不宜使用.在树的数据结构中,其大部分的运行时间平均为O(logN).并且通过对树结构的修改,我们能够保证它的最坏情形下上述的时间界. 树的定 ...

  6. AVL树(平衡二叉查找树)

    首先要说AVL树,我们就必须先说二叉查找树,先介绍二叉查找树的一些特性,然后我们再来说平衡树的一些特性,结合这些特性,然后来介绍AVL树. 一.二叉查找树 1.二叉树查找树的相关特征定义 二叉树查找树 ...

  7. 006-数据结构-树形结构-二叉树、二叉查找树、平衡二叉查找树-AVL树

    一.概述 树其实就是不包含回路的连通无向图.树其实是范畴更广的图的特例. 树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合. 1.1.树的特性: 每个结点有零个或多个子 ...

  8. 数据结构与算法分析-AVL树

    1.AVL树是带有平衡条件的二叉查找树. 2.AVL树的每个节点高度最多相差1. 3.AVL树实现的难点在于插入或删除操作.由于插入和删除都有可能破坏AVL树高度最多相差1的特性,所以当特性被破坏时需 ...

  9. 二叉树,AVL树和红黑树

    为了接下来能更好的学习TreeMap和TreeSet,讲解一下二叉树,AVL树和红黑树. 1. 二叉查找树 2. AVL树 2.1. 树旋转 2.1.1. 左旋和右旋 2.1.2. 左左,右右,左右, ...

随机推荐

  1. C语言教学杂记——字母排序

    一个人在被告诉一个问题应该怎么被解决后,而且亲身试验效果OK后,一旦遇到类似的问题,就会条件反射般直接拿这个方法来用了.很少会去想为什么要用这个方法,会不会有什么隐患,还有没有别的方法呢,等等这些问题 ...

  2. mpvue微信小程序分包

    ## 微信小程序分包(mpvue) 使用mpvue分包示例:1.下载vue脚手架(先有node环境,v8.12.0) npm install -g vue-cli 2.先用vue初始化一个mpvue小 ...

  3. object_test.py

    #方法,属性,私有化加双下划线 ''' __a 从外部无法访问,但是类的内部可以访问.实际上还是能在类外访问这些私有方法,尽管不应该这么做:s._A__a 如果不需要使用这种方法但是又不行让其他对象不 ...

  4. java虚拟机内存溢出和泄漏实例

    测试参数设置: 1.循环调用new A()实现堆溢出,java.lang.OutOfMemoryError: Java heap space, 虚拟机参数:-Xms1M -Xmx1M -XX:+Hea ...

  5. [SPOJ1557] Can you answer these queries II

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2482 [算法] 线段树维护历史最值 时间复杂度 : O(NlogN) [代码] #i ...

  6. 单次目标检测器-SSD简介

    SSD 是使用 VGG19 网络作为特征提取器(和 Faster R-CNN 中使用的 CNN 一样)的单次检测器.我们在该网络之后添加自定义卷积层(蓝色),并使用卷积核(绿色)执行预测. 同时对类别 ...

  7. AtCoder Regular Contest 063 E:Integers on a Tree

    题目传送门:https://arc063.contest.atcoder.jp/tasks/arc063_c 题目翻译 给你一个树,上面有\(k\)个点有权值,问你是否能把剩下的\(n-k\)个点全部 ...

  8. 获取access_token时却报出下列错误信息:{"errcode":40164,"errmsg":"invalid ip 61.172.68.219, not in whitelist hint: [KJZfAa0644e575]"},以及一些其他报错

    获取access_token时却报出下列错误信息:{"errcode":40164,"errmsg":"invalid ip 61.172.68.21 ...

  9. 1.5 Hive初步使用和安装MySQL

    一.HQL初步试用 1.创建一个student表 #创建一个student表 hive> create table student(id int, name string) ROW FORMAT ...

  10. JavaScript 对象字面量

    JavaScript 对象字面量   JavaScript 对象字面量 在编程语言中,字面量是一种表示值的记法.例如,"Hello, World!" 在许多语言中都表示一个字符串字 ...