定义平衡树节点:

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. 配置JDK和Tomcat环境变量(转)

    1.安装JDK 安装好JDK后,再配置JDK的环境变量:在“我的电脑”上点右键—>“属性”—>“高级”—> “环境变量(N)”. 新建系统变量JAVA_HOME:C:/Program ...

  2. Gym101161:ACM Tax (主席树)(占位)

    题意:给定一个带权树,Q次询问,每次回答某简单路径上的权值中位数. 思路:记录根到节点的主席树,主席树可以找到路径的第K大权值.(记住,这里是可以不用二分的,不要想多了.) 奇数条边直接找中位数,偶数 ...

  3. Can't locate Log/Dispatch.pm in @INC /Makefile out-of-date with respect to Makefile.PL

    mha check的时候报错问题解决:   # masterha_check_ssh --conf=/data/mha/app1.cnf Can't locate Log/Dispatch.pm in ...

  4. C++之输入输出流和文件传输流

    1.流的控制 iomanip          在使用格式化I/O时应包含此头文件.    stdiostream   用于混合使用C和C + +的I/O机制时,例如想将C程序转变为C++程序 2.类 ...

  5. DLL的远程注入技术

    DLL的远程注入技术是目前Win32病毒广泛使用的一种技术.使用这种技术的病毒体通常位于一个DLL中,在系统启动的时候,一个EXE程序会将这个DLL加载至某些系统进程(如Explorer.exe)中运 ...

  6. oracle获取一段时间内所有的小时、天、月

    获取一段时间内所有的小时 ) sdate FROM dual CONNECT ; 获取一段时间内所有的天 sdate FROM dual CONNECT ; from user_objects whe ...

  7. hihoCoder2月29日(字符串模拟)

    时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: ...

  8. HDOJ-2045

    不容易系列之(3)—— LELE的RPG难题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/O ...

  9. opencv MatExpr MatOp

    opencv提供了很多Mat的操作,其中涉及到两个重要的类:MatOp和MatExpr C++: MatExpr abs(const Mat& m) C++: void absdiff(Inp ...

  10. mptcp文献汇总

    1 https://www.blackhat.com/docs/us-14/materials/us-14-Pearce-Multipath-TCP-Breaking-Todays-Networks- ...