看了很长时间关于树的知识、今天自己尝试写一个二叉平衡树,个别代码稍微参考了一下,大部分是自己编写完成的。自己动手写的最大感受就是算法想起来比较简单,然实现起来还挺复杂的吧,还有,AVL树的插入和删除真不是一个级别的,本来想着应该类似的差不多,结果发现差好多啊,插入差不多半小时就写完了,删除用了一天、蓝瘦香菇......
package com.gaoxue.LeetCode;
public class AVLTreeGX<T extends Comparable<T>>{
private Node<T> root;
private static class Node<T>{
int height;
T data;
Node<T> left;
Node<T> right;
public Node(Node<T> left,Node<T> right,T data) {
this.data = data;
this.left = left;
this.right = right;
this.height = 0;
}
}
public Node<T> insert(T data){
return root = insert(data,root);
}
public Node<T> insert(T data,Node<T> node){
if(node == null)
return new Node<T>(null,null,data);
int CompareResult = data.compareTo(node.data);
if(CompareResult>0) {
node.right = insert(data,node.right);
if(getHeight(node.right)-getHeight(node.left)==2) {
//左右子树高度差为2则不符合AVL树的性质,需要进行旋转恢复平衡
int CompareResult2 = data.compareTo(node.right.data);
//判断在子树的左右哪边插入新的结点以确定使用单次或者二次旋转
if(CompareResult2>0) {
node = LeftRotate(node);
}else {
node = RightLeftRotate(node);
}
}
}else if(CompareResult<0) {
node.left = insert(data,node.left);
if(getHeight(node.left)-getHeight(node.right)==2) {
int CompareResult3 = data.compareTo(node.left.data);
if(CompareResult3<0) {
node = RightRotate(node);
}else {
node = LeftRightRotate(node);
}
}
}
node.height = Math.max(getHeight(node.left), getHeight(node.right))+1;
return node;
}
public Node<T> LeftRotate(Node<T> node) {
Node<T> rightNode = node.right;
node.right = rightNode.left;
rightNode.left = node;
// 旋转结束计算树高
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;
rightNode.height = Math.max(node.height, getHeight(rightNode.right)) + 1;
return rightNode;
}
public Node<T> RightRotate(Node<T> node) {
Node<T> leftNode = node.left;
node.left = leftNode.right;
leftNode.right = node;
// 旋转结束计算树高
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;
leftNode.height = Math.max(getHeight(leftNode.left), node.height) + 1;
return leftNode;
}
public Node<T> LeftRightRotate(Node<T> node) {
node.left = LeftRotate(node.left);
node = RightRotate(node);
return node;
}
public Node<T> RightLeftRotate(Node<T> node) {
node.right = RightRotate(node.right);
node = LeftRotate(node);
return node;
}
public void MiddleTraversal(Node<T> root) {
if(root.left!=null)
MiddleTraversal(root.left);
System.out.print(root.data+" ");
if(root.right!=null)
MiddleTraversal(root.right);
}
public int getHeight(Node<T> node) {
return node==null?-1:node.height;
}
public Node<T> remove(T data){
return root = remove(root,data);
}
private Node<T> remove(Node<T> node,T data) {
if (node == null) {
return null;
}
int compareResult = data.compareTo(node.data);
if (compareResult == 0) {
if (node.left != null && node.right != null) {
// 此节点存在左右子树
int balance = getHeight(node.left) - getHeight(node.right);
Node<T> temp = node;
// 保存需要进行删除的node节点
if (balance == -1) {
// 与右子树的最小值进行交换
exChangeRightData(node, node.right);
} else {
// 与左子树的最大值进行交换
exChangeLeftData(node, node.left);
}
// 此时已经交换完成并且把节点删除完成,则需要重新计算该节点的树高
temp.height = Math.max(getHeight(temp.left), getHeight(temp.right)) + 1;
// 注意此处,返回的是temp,也就是保存的需要删除的节点,而不是替换的节点
return temp;
} else {
// 此处隐含了一个node.left ==null && node.right == null 的条件,这时返回null
return node.left != null ? node.left : node.right;
}
} else if (compareResult > 0) {
node.right = remove(node.right,data);
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;
if (getHeight(node.left) - getHeight(node.right) == 2) {// 进行旋转
Node<T> leftSon = node.left;
if (getHeight(leftSon.left) > getHeight(leftSon.right)) {
node = RightRotate(node);
} else {
node = LeftRightRotate(node);
}
}
return node;
} else if (compareResult < 0) {
node.left = remove(node.left,data);
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;
if (getHeight(node.right) - getHeight(node.left) == 2) {
Node<T> rightSon = node.right;
if (rightSon.right.height > rightSon.left.height) {
node = LeftRotate(node);
} else {
node = RightLeftRotate(node);
}
}
return node;
}
return null;
}
private Node<T> exChangeLeftData(Node<T> node, Node<T> right) {
if (right.right != null) {
right.right = exChangeLeftData(node, right.right);
} else {
node.data = right.data;
// 此处已经把替换节点删除
return right.left;
}
right.height = Math.max(getHeight(right.left), getHeight(right.right)) + 1;
int isbanlance = getHeight(right.left) - getHeight(right.right);
if (isbanlance == 2) {
Node<T> leftSon = node.left;
if (getHeight(leftSon.left) > getHeight(leftSon.right)) {
return node = RightRotate(node);
} else {
return node = LeftRightRotate(node);
}
}
return right;
}
private Node<T> exChangeRightData(Node<T> node, Node<T> left) {
if (left.left != null) {
left.left = exChangeRightData(node, left.left);
} else {
node.data = left.data;
// 此处已经把替换节点删除
return left.right;
}
left.height = Math.max(getHeight(left.left), getHeight(left.right)) + 1;
// 回溯判断left是否平衡,如果不平衡则进行左旋操作。
int isbanlance = getHeight(left.left) - getHeight(left.right);
if (isbanlance == -2) {// 进行旋转
Node<T> rightSon = node.right;
// 判断是否需要进行两次右旋还是一次右旋
// 判断条件就是比较rightSon节点的左右子节点树高
if (getHeight(rightSon.left) > getHeight(rightSon.right)) {
return node = LeftRotate(node);
} else {
// 先右旋再左旋
return node = RightRotate(node);
}
}
return left;
}
public static void main(String args[]) {
AVLTreeGX<Integer> tree = new AVLTreeGX<Integer>();
int array[] = {4,5,10,7,8,9,15,30};
for (int i = 0; i < array.length; i++) {
tree.insert(array[i]);
}
tree.MiddleTraversal(tree.root);
System.out.println();
tree.remove(4);
tree.MiddleTraversal(tree.root);
}
}
可能有些地方还存在一些问题,但真的不能再测试了、脑子要炸了,就一直一直画树、测试数据都写了四五页了,有谁发现了问题一定记得纠正哈~