定义平衡树节点:

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. Chapter3——进入Android Dalvik虚拟机(二)

    Dalvik汇编语言基础 Dalvik虚拟机为自己设计了一套指令集,并制定了自己的指令格式和调用规范. 位描述约定如下: 每16位的字采用空格分隔开来 每个字母表示4位,每个字母按顺序从高字节开始,排 ...

  2. JavaWeb----文件的上传和下载

    一.开发环境搭建 创建一个FileUploadAndDownLoad项目,加入Apache的commons-fileupload文件上传组件的相关Jar包,如下图所示: 二.实现文件上传 2.1.文件 ...

  3. cuda 版本查阅

    查看cuda版本 cat  /usr/local/cuda/version.txt nvcc -V

  4. HDU acm1028 整数划分 递归问题(递推)

    我们用递归+记忆化的方法来解决普通整数划分问题:定义 f(n,m)为将整数n划分为一系列整数之和,其中加数 最大不超过m. 得到下面的递推关系式: 当n==1 || m==1 只有一种划分,即 1 或 ...

  5. 《Kubernetes权威指南第2版》学习(一) Kubernetes是什么

    1.1 Kubernetes是什么? 首先,它是一个全新的基于容器技术的分布式架构领先方案.是谷歌的Borg(大规模集群管理系统)的一个开源版本. 其次,如果系统设计遵循了Kubernetes的设计思 ...

  6. sqlServer:convert()函数

    在oracle中对于时间格式的转换用到的比较多,相对也比较了解,现在换了新的项目组,使用sqlserver数据库,需要对这个数据库的一些常用函数进行重新学习和熟悉,现在根据w3c及网上博文对conve ...

  7. docker三剑客之一docker compose

    compose有两个重要的概念: 服务(service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例 项目(project):由一组关联的应用容器组成的一个完整业务单元,在docker- ...

  8. 1.7 hive基本操作

    一.基本命令和设置 1.命令 [root@hadoop-senior hive-0.13.1]# bin/hive Logging initialized using configuration in ...

  9. EasyUI 启用行内编辑

    创建数据网格(DataGrid) $(function(){ $('#tt').datagrid({ title:'Editable DataGrid', iconCls:'icon-edit', w ...

  10. E20180509-sl

    chronology  n. 年代学; 年表,(按时间排列的)大事记 claim  n. 索赔; 声称; (根据权利而提出的) 要求; 断言;    vt. 声称; 索取; 断言; 需要; count ...