C++模板实现二叉树(五 树的平衡之dsw算法)

二叉树的高效查找算法依赖于树的平衡.如果树高度不平衡,二叉树将退化成类似链表的效率,则二叉树的优势就不存在了.平衡二叉树的dsw算法提供了一种将二叉树转化成平衡二叉树的方法.
算法的核心思想是利用旋转.
1.通过右旋转生成主链.
2.通过左旋转生成平衡二叉树.

核心代码分析:
1.旋转过程中,拆链建链的顺序很重要,如果顺序不对,很容易造成自己指向自己从而导致死循环.
右旋转可参考如下顺序 a)将祖父节点的右指针指向孩子节点. b)将父节点的左指针指向孩子节点的右子树. c)将孩子节点的右指针指向父亲节点. 特别的,如果祖父节点为空,说明当前的转换点在根节点,此时,旋转之后,孩子节点将成为新的根节点a)中的操作不需要执行(因为没有祖父节点).
左旋转的前提是主链已经形成,即每个节点初始时只有右子树. 左旋转可参考如下顺序 a)保存孩子节点的左节点. b)将孩子节点的左节点指向父亲节点. c)父亲节点的右节点指向前面a)中保存的节点. d)祖父节点的右节点指向孩子节点(父节点被向下旋转). 特别的,如果祖父节点为空,说明当前转换点在根节点,此时旋转之后,孩子节点成为新的根节点.d)中的操作不需要执行(因为没有祖父节点).
2.创建主链过程中,观察点一直为父亲节点.如果父亲节点有左节点,则左节点就是孩子节点,以此进行右旋转.旋转完成后,孩子节点变成新的父亲节点.继续循环.如果不存在左节点,则祖父节点与父亲节点均向右下移一个位置,继续循环.特别的,如果父亲节点为根节点,下移的时候,将祖父节点设置为根节点.
3.创建平衡树的过程中,首先对主链进行预处理,进行n-m次左旋转.左旋转完成一次后,孩子节点变成新的祖父节点,再进行下一次左旋转.之后,如果m>1,则m/2. 从头开始进行m次左旋转,直到m<=1为止.

特别注意,由于左右旋转会改变节点的位置与指向,所以在创建主链与创建平衡树的过程中,要找准判断条件.比如左旋转时,下一次左旋转比上一次左旋转相比,从原主链上看,是向下了2个节点.但是使用pa = pa->right->right;进行下移会出错,因为pa->right在左旋转时被重新指向其他位置了. 此时,需要设置新的gr指向原来的ch.通过新的gr进行下移操作就不会出错了.

实现代码如下:
头文件中添加如下方法:

    bool dswBalance();
    void createBackBone();
    void createPerfectTree();
    void rotationRight(BinNode<T>* gr, BinNode<T>* pa, BinNode<T>* ch);
    void rotationLeft(BinNode<T>* gr, BinNode<T>* pa, BinNode<T>* ch);

源文件中实现如下:

template <class T, unsigned int capacity>
void BinSearchTree<T, capacity>::rotationRight(BinNode<T>* gr, BinNode<T>* pa, BinNode<T>* ch)
{
    if (NULL == gr)                   //the current pa must be root, no gr case
    {
        pa->left = ch->right;
        ch->right = pa;
        root = ch;                    //In this case, ch should be the new root after rotate
    }
    else
    {
        gr->right = ch;
        pa->left = ch->right;
        ch->right = pa;
    }
    return;
}

template <class T, unsigned int capacity>
void BinSearchTree<T, capacity>::rotationLeft(BinNode<T>* gr, BinNode<T>* pa, BinNode<T>* ch)
{
    BinNode<T>* tmp = ch->left;
    ch->left = pa;
    pa->right = tmp;
    if (NULL == gr)
    {
        root = ch;
    }
    else
    {
        gr->right = ch;
    }
    return;
}

template <class T, unsigned int capacity>
void BinSearchTree<T, capacity>::createBackBone()
{
    BinNode<T>* gr = NULL;
    BinNode<T>* pa = root;
    BinNode<T>* ch = NULL;
    while (NULL != pa)
    {

        if (NULL != pa->left)                 //if has left child, rotate right
        {
            ch = pa->left;  
            rotationRight(gr, pa, ch);
            pa = ch;                   //After rotate, he ch should be the pa in the next time loop
        }
        else          //gr, pa, tmp move downto next right
        {
            if (root == pa)       //pa is root case, when move downto next right, gr should be set to root
            {
                gr = root;  
            }
            else
            {
                gr = gr->right;
            }
            pa = pa->right;
        }
    }
}

template <class T, unsigned int capacity>
void BinSearchTree<T, capacity>::createPerfectTree()
{
    unsigned int n = treeNodeNum;
    if (n <= 3)
    {
        return;
    }
    unsigned int m = pow(2, floor(log(n + 1)/log(2))) - 1;
    BinNode<T>* gr = NULL;
    BinNode<T>* pa = root;
    BinNode<T>* ch = root->right;
    for (unsigned int i = 0; i < n - m; i++)
    {
        rotationLeft(gr, pa, ch);
        gr = ch;
        pa = gr->right;
        if (NULL != pa)
        {
            ch = pa->right;
        }
        else
        {
            break;
        }
        //if ((NULL != pa->right) && (NULL != ch->right))
        //{
        //  pa = pa->right->right;         //The pa right should be changed in rorationLeft, can not use as
        //  ch = ch->right->right;
        //  if ((NULL == pa) || (NULL == ch))
        //  {
        //      break;
        //  }
        //}
        //else
        //{
        //  break;
        //}
    }
    while (m > 1)
    {
        m = m >> 1;
        BinNode<T>* gr = NULL;
        BinNode<T>* pa = root;
        BinNode<T>* ch = root->right;
        for (unsigned int i = 0; i < m; i++)
        {
            rotationLeft(gr, pa, ch);
            gr = ch;
            pa = gr->right;
            if (NULL != pa)
            {
                ch = pa->right;
            }
            else
            {
                break;
            }
        }
    }
    return;
}

template <class T, unsigned int capacity>
bool BinSearchTree<T, capacity>::dswBalance()
{
    bool result = false;
    if (isEmpty())
    {
        result = false;
    }
    else
    {
        createBackBone();
        createPerfectTree();
        result = true;
    }
    return result;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值