- 平衡二叉树又叫平衡二叉搜索树,或者AVL树,有如下特点:
- 可以是一棵空树
- 或者它的左右子树的高度差的绝对值不大于1,并且左右子树也是平衡二叉树
- 当二叉树不平衡的时候,可以通过“旋转”来使它平衡
- 左旋转(适用于右子树高度 - 左子树高度 > 1)
- 右旋转(适用于左子树高度 - 右子树高度 > 1)
- 双旋转
左旋转
- 思路分析
- 创建一个新的节点,且其值等于二叉树根节点的值
- 把新节点的左子树设置成当前节点的左子树
- 把新节点的右子树设置成当前节点右子树的左子树
- 把当前节点的值设置成其右子节点的值
- 把当前节点的右子树设置成其右子树的右子树
- 把当前节点的左子树设置成新节点
右旋转
- 思路分析
- 创建一个新的节点,且其值等于二叉树根节点的值
- 把新节点的右子树设置成当前节点的右子树
- 把新节点的左子树设置成当前节点左子树的右子树
- 把当前节点的值设置成其左子节点的值
- 把当前节点的左子树设置成其左子树的左子树
- 把当前节点的右子树设置成新节点
双旋转
- 思路分析(以整棵二叉树需要右旋转为例)
- 如果当前节点的左子树的右子树的高度大于当前节点的左子树的左子树的高度
- 可以先对当前节点的左子树进行左旋转
- 然后对当前节点右旋转
- 思路分析(以整棵二叉树需要左旋转为例)
- 如果当前节点的右子树的左子树的高度大于当前节点的右子树的右子树的高度
- 可以先对当前节点的右子树进行右旋转
- 然后对当前节点左旋转
代码
- 定义节点类,在类中编写获取二叉树高度的相关方法,旋转的相关方法
public class Node {
private int value;
private Node left;
private Node right;
public Node(int value) {
this.value = value;
}
public int height(){
return Math.max(this.getLeft() == null?0:this.getLeft().height(),
this.getRight() == null?0:this.getRight().height()) + 1;
}
public int leftHeight(){
if (this.getLeft()!=null){
return this.getLeft().height();
}else {
return 0;
}
}
public int rightHeight(){
if (this.getRight()!=null){
return this.getRight().height();
}else {
return 0;
}
}
public void leftRotate(){
Node newNode = new Node(this.getValue());
newNode.setLeft(this.getLeft());
newNode.setRight(this.getRight().getLeft());
this.setValue(this.getRight().getValue());
this.setRight(this.getRight().getRight());
this.setLeft(newNode);
}
public void rightRotate(){
Node newNode = new Node(this.getValue());
newNode.setRight(this.getRight());
newNode.setLeft(this.getLeft().getRight());
this.setValue(this.getLeft().getValue());
this.setLeft(this.getLeft().getLeft());
this.setRight(newNode);
}
public void addNode(Node node){
if (node == null){
return;
}
if (node.value < this.value){
if (this.getLeft() == null){
this.setLeft(node);
}else {
this.getLeft().addNode(node);
}
}else{
if (this.getRight() == null){
this.setRight(node);
}else {
this.getRight().addNode(node);
}
}
if (this.rightHeight() - this.leftHeight() > 1){
if (this.getRight()!= null && this.getRight().leftHeight()>this.getRight().rightHeight()){
this.getRight().rightRotate();
this.leftRotate();
}else {
this.leftRotate();
}
return;
}
if (this.leftHeight() - this.rightHeight() > 1){
if (this.getLeft()!= null && this.getLeft().rightHeight()>this.getLeft().leftHeight()){
this.getLeft().leftRotate();
this.rightRotate();
}else {
this.rightRotate();
}
return;
}
}
public void midOrder(){
if (this.getLeft() != null){
this.getLeft().midOrder();
}
System.out.println(this);
if (this.getRight() != null){
this.getRight().midOrder();
}
}
}
public class AVLTree {
private Node root;
public void addNode(Node node){
if (this.getRoot() == null){
this.setRoot(node);
}else {
this.getRoot().addNode(node);
}
}
public void midOrder(){
if (root == null){
return;
}else {
root.midOrder();
}
}
public Node getRoot() {
return root;
}
public void setRoot(Node root) {
this.root = root;
}
}
public class AVLTreeDemo {
public static void main(String[] args) {
int[] array = {10,11,7,6,8,9};
AVLTree avlTree = new AVLTree();
for (int i = 0; i < array.length; i++) {
avlTree.addNode(new Node(array[i]));
}
avlTree.midOrder();
System.out.println(" root hight : " + avlTree.getRoot().height());
System.out.println(" root-left hight : "+avlTree.getRoot().leftHeight());
System.out.println("root-right hight : "+avlTree.getRoot().rightHeight());
System.out.println(" root : "+avlTree.getRoot());
}
}