Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
平衡树的算法以前研究过,可是因为没总结这次又忘了,思路往往是一瞬间的,不断总结还是程序员应该养成的一个习惯。
平衡二叉树是特殊的二叉排序树,加了一个限定条件:
每个节点的左右子树不大于1;
二叉排序树是插入一个节点时,只需要随意插入即可,随意性很大,导致极端情况是单支二叉树。
插入时候的旋转,分成四种情况:
1>左左型:
二叉树本是 8,4当插入3时
二叉树情况是,此时我们就应该进行调整,让其平衡.
我们来看看更复杂的情况:
2>左右型
必须先转换成左左状态,在按照左左的方法转化成平衡树
复杂情况:
3>右右型
复杂情况:
4>右左型
处理方法类似左右
复杂情况:
说是旋转,其实更多的是换位,比如在左左型情况中,将根节点8拿下来充当4的右子树,4从而成为新的根节点,而4原来的右子树变成8的左子树,调整完后仍符合BST。我们只是将根节点与其中某个节点进行换位,便实现了树的平衡,在左右和右左两种情况,我们需要先将其转化为左左或右右,然后再次调用已经实现了的方法即可。
问题是:
将升序的数组转化成一颗平衡树。
完成后搜索一番,发现我的思路有点复杂,忘记了数组是有序,
思路:
从第一个开始插入,每插入一个将树调整为平衡,直到数组中所有的值已全部插完。
下面贴代码:
class Tree
{
int data;
Tree left;
Tree right;
Tree(int x) { data = x; }
Tree(){}
}
class AvlTree
{
//获取当前节点在二叉树中的高度
public static int getHeight(Tree root)
{
if(root == null)
{
return 0;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
if(leftHeight > rightHeight )
{
return leftHeight + 1;
}
else
{
return rightHeight + 1;
}
}
public static Tree AvlTreeLeftLeft(Tree root)
{
//左左型
//必须先将根的左子树保存起来,否则根直接换位,左子树的地址就会丢失
Tree temp = root.left;
root.left = temp.right;
temp.right = root;
return temp;
}
public static Tree AvlTreeLeftRight(Tree root)
{
//左右
//跟图中的方法一样,先变成左左,再调用左左型的处理方法
Tree temp = root.left;
root.left = root.left.right;
temp.right = root.left.left;
root.left.left = temp;
root = AvlTreeLeftLeft(root);
return root;
}
public static Tree AvlTreeRightRight(Tree root)
{
//右右
Tree temp = root.right;
root.right = temp.left;
temp.left = root;
return temp;
}
public static Tree AvlTreeRightLeft(Tree root)
{
//右左
//类似左右型,分为两步,先变成右右,然后调用右右的处理方法
Tree temp = root.right;
root.right = temp.left;
temp.left = root.right.right;
root.right.right = temp;
root = AvlTreeRightRight(root);
return root;
}
//插入新节点
public static Tree insertNode(int data , Tree root)
{
if(root == null)//如果当前节点不存在,则分配节点
{
root = new Tree(data);
root.left = root.right = null;
}
else
if(data<root.data)//小于根节点的权值,往左子树走
{
//直到走到最后的左子树
root.left = insertNode(data,root.left);
//左子树的高度和右子树的高度如果等于2,就说明当前BST不平衡,需要调整
if(getHeight(root.left) - getHeight(root.right) == 2)
{
//左左
if(data < root.left.data)//如果值小于左子树的值,也就说插入了左子树的左边,即左左型
root = AvlTreeLeftLeft(root);
else
//左右
root = AvlTreeLeftRight(root);//相反是插入到左子树的右边
}
}
else if(data >root.data) //大于,往右子树走
{
root.right = insertNode(data,root.right);
if(getHeight(root.right) - getHeight(root.left) == 2)
{
if(data > root.right.data)
//右右
root = AvlTreeRightRight(root);
else
//右左
root = AvlTreeRightLeft(root);
}
}
return root;
}
//先序遍历
public static void prePrint(Tree root)
{
if(root!=null)
{
System.out.print(root.data);
prePrint(root.left);
prePrint(root.right);
}
}
//中序遍历
public static void InorderPrint(Tree root)
{
if(root!=null)
{
InorderPrint(root.left);
System.out.print(root.data);
InorderPrint(root.right);
}
}
public static void main(String[] args)
{
int[] num = {1,2,3,4,5,6,7,8};
Tree root = null;
for(int i = 0; i<num.length ;i++)
{
root = insertNode(num[i],root);
}
//我们利用先序遍历和中序遍历可以确定一颗唯一的BST
prePrint(root);
System.out.println();
InorderPrint(root);
}
}
完成后我们发现右右型,右左型其实完全就是左左型,左右型的一个镜像,只是进行了相反的操作。
提交到Leetcode上结果正确,但是时间超长,觉得应该有更好的方法,然后,傻眼了
其实我们完全可以利用数组升序来处理这件事,每次选择中间的,对两侧进行递回,从而就可以得到一颗平衡树。
代码如下:
class Tree
{
int data;
Tree left;
Tree right;
Tree(int x) { data = x; }
Tree(){}
}
class Soultion
{
public static Tree toBST(num,start,end)
{
if(start > end) return null;
if(start == end)return new Tree(num[start]);
int mid = (start + end)/2;
Tree node = new Tree(num[mid]);
node.left = toBST(num,start,mid-1);
node.right = toBST(num,mid+1.end);
}
public static Tree getBST(int[] num)
{
Tree root = null;
root = toBST(num,0,num,length-1);
return root;
}
}
参考文章:
http://blog.csdn.net/wangxiaojun911/article/details/18916957
http://www.cnblogs.com/fornever/archive/2011/11/15/2249492.html