由平衡树引发的思考

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值