基础算法-AVL平衡二叉树(五)
一路学习下来才发现,算法是最难学的东西,其他什么jvm,jdk源码啊,看起来都比较简单。这里写的文章并不好,因为很多分析都是参照网上博客的,没有太多自己的东西,所以只有代码,介绍部分很少,分析部分没有。想要了解更多分析方面的知识请参看下面给出的参考地址。
普通树很容易不平衡,比如随便插入一个1,2,3……10就会发现,全部偏向了右边,就和单链表差不多了,这个时候我们通过一种手段来保证树的平衡。比如,红黑树,B+树,AVL树,都是平衡树。
AVL树的定义
来源:平衡二叉树是G.M. Adelson-Velsky 和 E.M. Landis在1962年在论文中发表的,因此又叫AVL树。
定义:一棵AVL树是其每个结点的左子树和右子树的高度最多相差1的二叉查找树(空树的高度为-1),这个差值也称为平衡因子,所以AVL树每个节点都多了一个参数—高度。
导致AVL树不平衡的原因?
- 在结点X的左孩子结点的左子树中插入元素
- 在结点X的左孩子结点的右子树中插入元素
- 在结点X的右孩子结点的左子树中插入元素
- 在结点X的右孩子结点的右子树中插入元素
解决问题:
1,4是同一类问题,我们只需要:左左右旋转,右右左旋转即可。
2,3是同一类问题,我们只需要:左右插入,左,右旋转;右左插入,右,左旋转。(不要颠倒旋转次序哦)
代码实现
/**
* AVL二叉树(平衡二叉树): 一棵AVL树是其每个结点的左子树和右子树的高度最多相差1的二叉查找树(空树的高度为-1),这个差值也称为平衡因子
* 参考地址:http://blog.csdn.net/javazejian/article/details/53892797
* bww
*/
public class AVLBinaryTree {
private TreeNode root = null;
//左旋转
public TreeNode rightRightLeftRotate(TreeNode node) {
TreeNode w = node.rightChild;
node.rightChild = w.leftChild;
w.leftChild = node;
node.height = Math.max(getNodeHeight(node.leftChild), getNodeHeight(node.rightChild)) + 1;
w.height = Math.max(getNodeHeight(w.leftChild), getNodeHeight(w.rightChild)) + 1;
return w;
}
//右旋转
public TreeNode leftLeftRightRotate(TreeNode node) {
TreeNode w = node.leftChild;
node.leftChild = w.rightChild;
w.rightChild = node;
node.height = Math.max(getNodeHeight(node.leftChild), getNodeHeight(node.rightChild)) + 1;
w.height = Math.max(getNodeHeight(w.leftChild), getNodeHeight(w.rightChild)) + 1;
return w;
}
//左右插入,先左后右
public TreeNode doubleRotateWithLeftRight(TreeNode node) {
node.leftChild = rightRightLeftRotate(node.leftChild);
return leftLeftRightRotate(node);
}
//右左插入,先右后左
public TreeNode doubleRotateWithRightLeft(TreeNode node) {
node.rightChild = leftLeftRightRotate(node.rightChild);
return rightRightLeftRotate(node);
}
public void insert(int data) {
root = insert(data, root);
}
public TreeNode insert(int data, TreeNode node) {
if (node == null) {
node = new TreeNode(data);
} else {
//左
if (data < node.value) {
//左插入
node.leftChild = insert(data, node.leftChild);
if (getNodeHeight(node.leftChild) - getNodeHeight(node.rightChild) == 2) {
//左左,右旋转
if (data < node.leftChild.value) {
node = leftLeftRightRotate(node);
} else {
//左右,左右旋转
node = doubleRotateWithLeftRight(node);
}
}
} else {
node.rightChild = insert(data, node.rightChild);
if (getNodeHeight(node.rightChild) - getNodeHeight(node.leftChild) == 2) {
//右右,左旋转
if (data > node.rightChild.value) {
node = rightRightLeftRotate(node);
} else {
//右左,右左旋转
node = doubleRotateWithRightLeft(node);
}
}
}
}
node.height = Math.max(getNodeHeight(node.leftChild), getNodeHeight(node.rightChild)) + 1;
return node;
}
public Integer find(int value) {
TreeNode currentNode = root;
if (currentNode == null) {
return null;
}
Integer temp;
while ((temp = currentNode.value) != value) {
System.out.println("pass=" + temp);
if (temp > value) {
currentNode = currentNode.rightChild;
} else {
currentNode = currentNode.leftChild;
}
if (currentNode == null) {
return null;
}
}
return temp;
}
//中序遍历,这样遍历出来的数据是递增的,从小到大
public void inOrder(TreeNode currentNode) {
if (currentNode != null) {
inOrder(currentNode.leftChild);
System.out.println("---" + currentNode.value);
inOrder(currentNode.rightChild);
}
}
int count = 15;
//前序遍历,这样遍历出来的数据是
public void printlnOrder(TreeNode currentNode, boolean point) {
if (currentNode != null) {
if (point) {
count++;
} else {
count--;
}
String k = " ";
for (int i = 0; i < count; i++) {
k += " ";
}
System.out.println(k + currentNode.value);
printlnOrder(currentNode.leftChild, false);
printlnOrder(currentNode.rightChild, true);
}
}
public void spanFirst(TreeNode root) {
System.out.println("--广度优先---");
if (root == null) {
return;
}
LinkedList<TreeNode> linkedList = new LinkedList<TreeNode>();
linkedList.offer(root);
while (linkedList.size() > 0) {
TreeNode node = linkedList.poll();//出队列,队列先进先出,记住:出队列后元素就会被废弃掉哦。这就是出队列。
System.out.println(node.value);
if (node.leftChild != null) {
linkedList.offer(node.leftChild);
}
if (node.rightChild != null) {
linkedList.offer(node.rightChild);
}
}
}
public int getNodeHeight(TreeNode node) {
if (node == null) {
return 0;
}
int leftHeight = getNodeHeight(node.leftChild);
int rightHeight = getNodeHeight(node.rightChild);
return Math.max(leftHeight, rightHeight) + 1;
}
private class TreeNode {
private int value;
private int height;//当前结点的高度
private TreeNode leftChild = null;
private TreeNode rightChild = null;
public TreeNode(int value) {
this.value = value;
this.leftChild = null;
this.rightChild = null;
}
}
public static void main(String[] args) {
AVLBinaryTree tree = new AVLBinaryTree();
for (int i = 1; i <= 10; i++) {
tree.insert(i);
}
tree.printlnOrder(tree.root, false);
tree.spanFirst(tree.root);
System.out.println("tree height----");
System.out.println(tree.getNodeHeight(tree.root));
}
}
1-10顺序插入后的效果图:
动态演示网站:http://www.cs.usfca.edu/~galles/visualization/AVLtree.html