码迷,mamicode.com
首页 > 其他好文 > 详细

T树索引的学习与实现(二)

时间:2016-07-19 10:16:10      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:

源代码:

ttree.h源代码:

/*
 * ttree.h: header file
 *
 * T树的结构
 *
 */
#ifndef TTREE
#define TTREE

#include <QString>
#include <QMap>

/*
 * 为了保持空间的利用率,每一个内部节点都需要包含一个最小数目的键值
 */
enum
{
    ttPageSize = 10,
    ttminSize = ttPageSize - 2
};

typedef QString ElementKey;
typedef QMap<QString, QString>* ElementData;

typedef struct TTREENODE         //树节点的结构
{
    TTREENODE *left;             //节点的左子树指针
    TTREENODE *right;            //节点的右子树指针
    unsigned short int nItems;      //节点中键值的数目
    ElementKey key[ttPageSize];       //key值数组
    ElementData data[ttPageSize];     //对应数据行的指针  因为需要保证每个内部节点的
                                    //最小数目键值,所以用数组,不用map之类的容器
    int balance;                    //balance(平衡因子),其绝对值不大于1,balance =右子树高度-左子树高度;
} TTREENODE;

class TTree                         //T树的结构
{
public:
    TTree();
    virtual ~TTree();

public:
    //向T树中插入一条数据
    void insertRecord(ElementKey key, ElementData data);

    //删除T树中对应的key的数据
    void deleteRecord(ElementKey key);

    //查找对应key值得数据指针
    ElementData findRecord(ElementKey key);

    //返回T树中的节点数
    int getNodeSize();

    //返回T树的深度
    int depth(TTREENODE *pNode) const;

    //比较两个key值得大小,1 : key1 > key2, 0 : key1 = key2, -1 : key1 < key2
    virtual int keyCompare(ElementKey key1, ElementKey key2);

    //清除树节点
    void clear();

    //如果树为空返回TRUE, 不为空返回FALSE
    bool isEmpty() const;

    //T树的前序遍历
    void PreOrderTraverse(TTREENODE *pNode) const;

private:
    //从内存中为node分配空间
    TTREENODE *mallocNode();

    //释放节点占用的内存
    void freeNode(TTREENODE *pNode);

    //递归清除每个节点
    void _earse(TTREENODE *pNode);

    //插入的时候需要递归遍历整棵树,为了方便,额外增加一个方法  *& 表示一个指针的引用
    bool _insert(TTREENODE *&pNode, ElementKey key, ElementData data);

    //内部删除数据的方法
    int _delete(TTREENODE *&pNode, ElementKey key);

private:
    //获取该节点的平衡因子
    int getBalance(TTREENODE *pNode) const;

    //LL类型旋转 右旋
    TTREENODE *singleRotateLeft(TTREENODE *pNode);

    //RR类型旋转 左旋
    TTREENODE *singleRotateRight(TTREENODE *pNode);

    //LR类型旋转,节点的左子树先左旋,然后节点右旋
    TTREENODE *doubleRotateLeftRight(TTREENODE *pNode);

    //RL类型旋转,节点的右子树先右旋,然后节点左旋
    TTREENODE *doubleRotateRightLeft(TTREENODE *pNode);

    //平衡右子树分支
    int balanceRightBranch(TTREENODE *&pNode);

    //平衡左子树分支
    int balanceLeftBranch(TTREENODE *&pNode);

    //平衡右子树分支:节点隔层调用底层的节点的数据,需要另外一种平衡
    int balanceRightBranchInterlayer(TTREENODE *&pNode);

    //平衡左子树分支:节点隔层调用底层的节点的数据,需要另外一种平衡
    int balanceLeftBranchInterlayer(TTREENODE *&pNode);

public:
    TTREENODE* root;        //T树的根节点
    int nodeSize;           //T树中的节点数
};

#endif // TTREE


ttree.cpp源代码:

/*
 * ttree.cpp: source file
 */
#include "ttree.h"
#include <math.h>
#include <QString>
#include <QDebug>

TTree::TTree()
{
    root = NULL;
    nodeSize = 0;

   // qDebug() << "in TTree()";
}

TTree::~TTree()
{
    clear();
    root = NULL;
    nodeSize = 0;
}

TTREENODE *TTree::mallocNode()
{
    TTREENODE *pNode = new TTREENODE;

    /*
     * void *memset(void *s, int ch, size_t n);
     * 函数解释:将s中前n个字节替换为ch并返回s;
     * memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。
     */
   // memset(pNode, 0, sizeof(TTREENODE));          //如果不注释,会导致程序异常

    pNode->nItems = 0;
    pNode->balance = 0;
    pNode->balance = 0;
    pNode->left = pNode->right = NULL;

    nodeSize ++;

    return(pNode);
}

void TTree::freeNode(TTREENODE *pNode)
{
    if(pNode)
    {
        delete pNode;
        pNode = NULL;
        nodeSize --;
    }
}

void TTree::_earse(TTREENODE *pNode)
{
    if(pNode == NULL)
    {
        return;
    }

    _earse(pNode->left);
    _earse(pNode->right);
    freeNode(pNode);
}

void TTree::clear()
{
    _earse(root);
}

int TTree::getNodeSize()
{
    return nodeSize;
}

ElementData TTree::findRecord(ElementKey key)
{
    TTREENODE *pNode = root;

    while(pNode != NULL)
    {
        int n = pNode->nItems;
        ElementKey minKey = pNode->key[0];
        ElementKey maxKey = pNode->key[n > 0 ? n - 1 : 0];
        int nDiff1 = keyCompare(key, minKey);
        int nDiff2 = keyCompare(key, maxKey);

        if(nDiff1 >= 0 && nDiff2 <= 0)
        {
            int l = 0, r = n - 1;

            //二分查找算法
            while(l <= r)
            {
                int i = (r - l) / 2 + l;
                ElementKey itemKey = pNode->key[i];
                int nDiff = keyCompare(key, itemKey);

                if(nDiff == 0)
                {
                    return pNode->data[i];
                }
                else if(nDiff > 0)
                {
                    l = i + 1;
                }
                else
                {
                    r = i - 1;
                }
            }

            break;
        }
        else if(nDiff1 < 0)
        {
            pNode = pNode->left;
        }
        else if(nDiff2 > 0)
        {
            pNode = pNode->right;
        }
    }

    return NULL;
}

/*int TTree::getBalance(TTREENODE *pNode) const    //第三次修改BUG,此处需要递归,你个辣鸡!!!
{
    int l, r;
    TTREENODE *p1, *p2;
    l = r = 0;
    p1 = p2 = pNode;

    if(p1 != NULL)
    {
        while(p1->left != NULL)
        {
            p1 = p1->left;
            l++;
        }
    }

    if(p2 != NULL)
    {
        while(p2->right != NULL)
        {
            p2 = p2->right;
            r++;
        }
    }
    qDebug() << "key: " << pNode->key[0] << " l : " << l << " r : " <<r;

    return (r - l);
}   */

int TTree::getBalance(TTREENODE *pNode) const
{
    return depth(pNode->right) - depth(pNode->left);
}



int TTree::depth(TTREENODE *pNode) const
{
    if(pNode == NULL)
    {
        return 0;
    }

    return depth(pNode->left) > depth(pNode->right) ? depth(pNode->left) + 1 : depth(pNode->right) + 1;
}

//LL类型的旋转需要右旋一次,然后返回新的根节点
TTREENODE *TTree::singleRotateLeft(TTREENODE *pNode)
{
    TTREENODE *k = pNode->left;
    pNode->left = k->right;
    k->right = pNode;

    pNode->balance = getBalance(pNode);
    k->balance = getBalance(k);

  //  qDebug() << "右旋完毕:pNode: " << pNode->key[0] << " pNode->bf: " << pNode->balance;
  // qDebug() << "右旋完毕:k: " << k->key[0] << " k->bf: " << k->balance;

    return k;
}

//RR类型的旋转需要左旋一次,然后返回新的根节点
TTREENODE *TTree::singleRotateRight(TTREENODE *pNode)
{
    TTREENODE *k = pNode->right;
    pNode->right = k->left;
    k->left = pNode;

    pNode->balance = getBalance(pNode);
    k->balance = getBalance(k);

    return k;
}

//LR类型的旋转需要根节点的左子树先左旋一次,变成LL类型,然后根节点再右旋一次,然后返回新的根节点
TTREENODE *TTree::doubleRotateLeftRight(TTREENODE *pNode)
{
    pNode->left = singleRotateRight(pNode->left);

    pNode->balance = getBalance(pNode);

    return singleRotateLeft(pNode);
}

//RL类型的旋转需要根节点的右子树先右旋一次,变成RR类型,然后根节点再左旋一次,返回根节点
TTREENODE *TTree::doubleRotateRightLeft(TTREENODE *pNode)
{
    pNode->right = singleRotateLeft(pNode->right);

    pNode->balance = getBalance(pNode);
   // leverlOrderTraverse(root);

    return singleRotateRight(pNode);
}

//插入一条数据记录的时候需要先判断树中是否有节点,没有节点需要创建节点插入,如果有
//节点,需要遍历T树查找相应的位置插入
void TTree::insertRecord(ElementKey key, ElementData data)
{
   // qDebug() << "in insertRecord(), key = " << key << " data = " <<  data;

    if(root == NULL)
    {
        root = mallocNode();
        root->balance = 0;
        root->key[0] = key;
        root->data[0] = data;
       // qDebug()<< "i got here   ";
       // qDebug() << "ROOT " << root->key[0] << root->data[0];
        root->nItems = 1;
        root->left = NULL;
        root->right = NULL;
    }
    else
    {
       // qDebug() << "ROOT is not NULL";

        TTREENODE *pNode = root;
        bool bRet = _insert(pNode, key, data);

        /*
         * 插入数据可能导致插入节点,导致T树不平衡开始旋转,导致root改变
         */
        if(pNode != root)
        {
            root = pNode;
        }
    }
}

/*
 * 在一个节点中插入数据的时候:
 * (1)比最小的key值小
 * (2)比最大的key值大
 * (3)处于这个节点的key值范围内
 */
bool TTree::_insert(TTREENODE *&pNode, ElementKey key, ElementData data)
{
    int n = pNode->nItems;
    ElementKey minKey = pNode->key[0];
    ElementKey maxKey = pNode->key[n > 0 ? n-1 : 0];
    int nDiff = keyCompare(key, minKey);

    /*
     * 如果key值小于这个节点中最小的key值
     * (1)如果这个节点中存储的值个数小于pageSize(节点存储的最大个数)&&(没有左子树||key等于节点中的最小值)
     *      把节点中的数组向后移一位,把当前key插入到最前面
     * (2)如果不满足(1),也就是当前节点存储满了,并且没有左子树,需要添加新的节点
     * (3)如果(1)(2)都不满足,说明需要向子节点中插入,需要递归,一直到插入为止
     * 当插入新的节点的时候,需要重新计算平衡因子,看是否需要旋转
     */
    if(nDiff == 0)          //因为每次只返回一条数据,所以如果key值相同,说明是同一条数据,就不能再次插入
    {
        return false;
    }
    if(nDiff < 0)
    {
        TTREENODE *pLeftId = pNode->left;

        /*
         * 疑惑!!!!!!!!
         * 如果key值相同怎么还插入了,虽然返回false
         * 查找的时候findRecord只返回一条数据的地址
         */
        //if(pLeftId == NULL && pNode->nItems < pageSize)
        if(pNode->nItems < ttPageSize)            //第三次修改BUG
        {
            TTREENODE * pleftId = pNode->left;
            if(pleftId != NULL)
            {
                while(pleftId->right)
                {
                    pleftId = pleftId->right;
                }
            }

            if(pNode->left == NULL || keyCompare(key, pleftId->key[pleftId->nItems-1]) > 0)
            {
                for(int i = n; i > 0; i--)
                {
                    pNode->key[i] = pNode->key[i-1];
                    pNode->data[i] = pNode->data[i-1];
                }
                pNode->key[0] = key;
                pNode->data[0] = data;
                pNode->nItems += 1;

                return false;
            }

        }
        if(pLeftId == NULL)
        {
         //   qDebug() << "开辟新的左子节点";

            pLeftId = mallocNode();
            pLeftId->key[0] = key;
            pLeftId->data[0] = data;
            pLeftId->nItems += 1;

            pNode->left = pLeftId;
        }
        else
        {
            TTREENODE *pChildId = pLeftId;
            bool issuccess = _insert(pChildId, key, data);

            if(pChildId != pLeftId)
            {
                pNode->left = pLeftId = pChildId;
            }

            if(!issuccess)
            {
                return false;
            }
        }

        /*
         * 由于某些插入导致递归查找插入,下层节点旋转平衡节点后,
         * 再重新递归上层看是否旋转,一直到root,完成整棵树的旋转
         */
        if(pNode->balance > 0)
        {
            pNode->balance = 0;

            return false;
        }
        else if(pNode->balance == 0)
        {
            pNode->balance = -1;

            return true;                    //true或false用来控制是否需要递归旋转,当多出一层节点的时候才会导致树失衡
        }                                   //当旋转完毕,多出的那一层就会剪掉,整棵树已经平衡,没必要继续递归检测
        else
        {
            if(pLeftId->balance < 0)
            {
                pNode = singleRotateLeft(pNode);
            }
            else
            {
                pNode = doubleRotateLeftRight(pNode);
            }

            return false;
        }
    }

    /*
     * 第二种情况,大于最大的key值,与上面类似
     */
    nDiff = keyCompare(key, maxKey);
   // qDebug() << "keyCompare(key, maxKey) : " << key << maxKey << nDiff;

    if(nDiff == 0)
    {
        return false;
    }
    if(nDiff > 0)
    {
    //    qDebug()<<"新插入数据>节点最大key值";

        TTREENODE *pRightId = pNode->right;

       // if(pRightId == NULL && pNode->nItems < pageSize)        //当节点中的数据只有一个并且引起旋转导致节点上升,导师pRightId!=NULL
        if(pNode->nItems < ttPageSize)
        {                                                       //然而再次插入的时候,随然当前节点数据量<PageSize,但是也不能插入当前结点
    //        qDebug() << "当前结点未满,插入当前节点";               //T树效率影响点之一,可以动手修改点

            TTREENODE * prightId = pNode->right;                    //第三次修改BUG:成功避免节点因旋转导致空间利用率低下问题
            if(prightId != NULL)
            {
                while(prightId->left)
                {
                    prightId = prightId->left;
                }
            }

            if(pNode->right == NULL || keyCompare(key, prightId->key[0]) < 0)
            {

                pNode->key[n] = key;
                pNode->data[n] = data;
                pNode->nItems ++;

                return false;
            }
        }
        if(pRightId == NULL)
        {
    //        qDebug() << "需要开辟新节点";

            pRightId = mallocNode();
            pRightId->key[0] = key;
            pRightId->data[0] = data;
            pRightId->nItems = 1;

            pNode->right = pRightId;
        }
        else
        {
    //        qDebug() << "进入下一级节点";
            TTREENODE *pChildId = pRightId;

            bool bGrow = _insert(pChildId, key, data);

            if(pChildId != pRightId)
            {
                pNode->right = pRightId = pChildId;
            }

            if(!bGrow)
            {
                return false;
            }
        }

     //   qDebug() << "pNode->balance : " << pNode->balance;

        if(pNode->balance < 0)
        {
            pNode->balance = 0;

            return false;
        }
        else if(pNode->balance == 0)
        {
            pNode->balance = 1;

            return true;        //增加一个新节点,返回true,进入现在代码,进行重置节点中的平衡点
        }
        else
        {
           // qDebug()  << "in rotate";

            if(pRightId->balance > 0)
            {
            //    qDebug() << "in RR: pNode->bf: " << pNode->balance << "  pRightId->bf : " << pRightId->balance;
                pNode = singleRotateRight(pNode);       //RR类型, 左旋
             //   qDebug() << "after RR : " <<pNode->balance;
            }
            else if(pRightId->balance < 0)
            {
            //    PreOrderTraverse(root);
           //     qDebug() << "int RL: pNode->bf: " << pNode->balance << "  pRightId->bf : " << pRightId->balance;
                pNode = doubleRotateRightLeft(pNode);   //RL类型,先右旋,再左旋
          //      qDebug() << "out RL";
            }

    //        qDebug() << "out rotate";

            return false;
        }
    }

    /*
     * 第三种情况,key值在节点的key值范围内
     * (1)如果该节点中的数据还没有满,只需找到合适的位置插入即可
     * (2)如果节点中数据已满,只需要考虑把节点往前挤掉一个,还是往后挤掉一个
     *      ((1))如果节点的平衡点>0,为了避免插入可能带来的增加节点导致旋转引起
     *              效率下降,需要往前挤掉,把最前面的节点重新往左子树插
     *      ((2))如果节点的balance<0,同理往后挤
     */
  //  qDebug() << "确定位置为节点中间位置";
    int l = 0, r = n -1;
    while(l < r)        //利用二分查找找到需要插入位置r
    {
         int i = (r - l) / 2 + l;
         ElementKey itemKey = pNode->key[i];
         nDiff = keyCompare(key, itemKey);

         if(nDiff > 0)
         {
             l = i + 1;
         }
         else
         {
             r = i;
             if(nDiff == 0)
             {
                 return false;
             }
         }
    }

    if(n < ttPageSize)
    {
      //  qDebug() << "节点中数据未满,直接插入中间合适的位置 r: " << r;
        for(int i = r; i < n; i++)
        {
            pNode->key[i+1] = pNode->key[i];
            pNode->data[i+1] = pNode->data[i];
        }
        pNode->key[r] = key;
        pNode->data[r] = data;
        pNode->nItems ++;
      //  qDebug() << "插入完毕 nItems: " << pNode->nItems;
        return false;
    }
    else
    {
        ElementKey reInsertKey;
        ElementData reInsertData;

        if(pNode->balance >= 0)
        {
            reInsertKey = pNode->key[0];
            reInsertData = pNode->data[0];

            for(int i = 0; i < r - 1; i++)
            {
                pNode->key[i] = pNode->key[i+1];
                pNode->data[i] = pNode->data[i+1];
            }

            pNode->key[r-1] = key;
            pNode->data[r-1] = data;

            return _insert(pNode, reInsertKey, reInsertData);
        }
        else
        {
            reInsertKey = pNode->key[n-1];
            reInsertData = pNode->data[n-1];

            for(int i = n -1 ; i > r; i--)
            {
                pNode->key[i] = pNode->key[i-1];
                pNode->data[i] = pNode->data[i-1];
            }

            pNode->key[r] = key;
            pNode->data[r] = data;

            return _insert(pNode, reInsertKey, reInsertData);
        }
    }
}

/*
 * deleteRecord
 * 对外公开的delete方法
 */
void TTree::deleteRecord(ElementKey key)
{
    if(root != NULL)            //删除BUG地方之一,已修改
    {
        TTREENODE *pNode = root;
        int h = _delete(pNode, key);
        //assert(h >= 0);
        if(pNode != root)
        {
            root = pNode;
        }
    }

}

/*
 * 内部删除的方法
 *
 * 如果key值不再当前结点的key值范围内,则递归调用本方法在子节点中删除key值对应的数据
 * 如果key值在范围内:
 * (1)如果当前结点的nItems>minSize,则只需要删除节点中的数据,nItems-1即可
 * (2)如果当前结点的nItems=minSize,需要调用一个子节点中的数据添加到本节点中。
 *      至于调用子节点中小于当前结点最小值的最大值,还是大于当前结点的最大值的最小值
 *      需要看当前结点的balance,尽可能避免删除带来的旋转
 * (3)因为子节点的数据需要向上补充,所以有的子节点中的数据可能小于minSize,当节点中
 *      的数据=1,并且需要删除的时候,本节点也需要删除,因此可能导致T树不平衡,导致旋转
 *
 * T树与AVL树删除的不同的是,由于再删除中间节点的时候,子节点中的数据需要向上补充,所以
 * 删除的一直是子节点。
 *
 * return -1:没有删除成功 1:删除一个节点 0:没有删除节点,但删除数据成功
 */
int TTree::_delete(TTREENODE *&pNode, ElementKey key)
{
    int n = pNode->nItems;
    ElementKey minKey = pNode->key[0];
    ElementKey maxKey = pNode->key[n > 0 ? n - 1 : 0];
    int nDiff = keyCompare(key, minKey);
   // qDebug() << "keyCompare(key, minKey); key:" << key << " minKey:" << minKey << " nDiff:" << nDiff;

    if(nDiff < 0)
    {
        TTREENODE *pLeftId = pNode->left;

        if(pLeftId != 0)
        {
            TTREENODE *pChildId = pLeftId;
        //    qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!  pChildId: " << pChildId << " pLeftId: " << pLeftId;
            int h = _delete(pChildId, key);      //h表示删除的节点数,不是数据数
         //   qDebug() << "pChildId: " << pChildId;
            if(pChildId != pLeftId)
            {
                pNode->left = pChildId;
            }
            if(h > 0)
            {
                return balanceLeftBranch(pNode);    //h>0 表示有删除的节点,需要平衡
            }
            else if(h == 0)
            {
                return 0;
            }
        }

        return -1;
    }

    nDiff = keyCompare(key, maxKey);
    if(nDiff > 0)
    {
        TTREENODE *pRightId = pNode->right;

        if(pRightId != 0)
        {
            TTREENODE *pChildId = pRightId;
            int h = _delete(pChildId, key);

            if(pChildId != pRightId)
            {
                pNode->right = pChildId;
            }
            if(h > 0)
            {
                return balanceRightBranch(pNode);
            }
            else if(h == 0)
            {
                return 0;
            }
        }
        return -1;
    }

    for(int i = 0; i < n; i++)
    {
        if(keyCompare(pNode->key[i],key) == 0)
        {
            if(n == 1 && pNode->left == NULL && pNode->right == NULL)                        //删除的一直是子节点
            {
                freeNode(pNode);
                pNode = NULL;
                return 1;
            }

            TTREENODE *pLeftId = pNode->left, *pRightId = pNode->right;
            TTREENODE *pre = pNode;
            if(n <= ttminSize)
            {
                if(pLeftId != NULL && pNode->balance <= 0)          //在调入子树节点数据的时候,尽量避免失衡,所以判断是从左子树调用还是从右子树
                {
                    bool isInterlayer = false;

                    while(pLeftId->right != NULL)
                    {
                        isInterlayer = true;
                        pre = pLeftId;
                        pLeftId = pLeftId->right;
                    }
                    while(--i >= 0)                     //删除数据,从左子树中调入最大数据
                    {
                        pNode->key[i+1] = pNode->key[i];
                        pNode->data[i+1] = pNode->data[i];
                    }
                    pNode->key[0] = pLeftId->key[pLeftId->nItems - 1];
                    pNode->data[0] = pLeftId->data[pLeftId->nItems - 1];

                    TTREENODE *pChildId = pLeftId;
                    int h = _delete(pChildId, pNode->key[0]);
          //          qDebug() << "pChildId : " << pChildId;
                    if(pChildId != pLeftId)
                    {
                        if(pre == pNode)
                        {
                            pre->left = pLeftId = pChildId;
                        }
                        else
                        {
                            pre->right = pLeftId = pChildId;             //警告,数据能报错点
                        }

                    }
                    if(h > 0)
                    {
                        if(isInterlayer)
                        {
                            h = balanceRightBranchInterlayer(pNode->left);
                            if(h > 0)
                            {
                                h = balanceLeftBranch(pNode);
                            }
                        }
                        else
                        {
                            h = balanceLeftBranch(pNode);
                        }
                    }

           //         qDebug() << "h: " << h;

                    return h;
                }
                else if(pNode->right != NULL)
                {
                 //   qDebug() << "in pNode->right";

                    bool isInterlayer = false;

                    while(pRightId->left != NULL)
                    {
                        isInterlayer = true;
                        pre = pRightId;
                        pRightId = pRightId->left;
                    }
                    while(++i < n)
                    {
                        pNode->key[i-1] = pNode->key[i];
                        pNode->data[i-1] = pNode->data[i];
                    }
                    pNode->key[n-1] = pRightId->key[0];
                    pNode->data[n-1] = pRightId->data[0];

                    TTREENODE *pChildId = pRightId;
                    int h = _delete(pChildId, pNode->key[n-1]);
                //    qDebug() << "pChildId : " << pChildId << " pRightId:" <<pRightId ;
                    if(pChildId != pRightId)
                    {
                        if(pre == pNode)
                        {
                            pre->right = pLeftId = pChildId;
                        }
                        else
                        {
                            pre->left = pLeftId = pChildId;
                        }


                    }
               //     qDebug() << "pChildId : " << pChildId << " pRightId:" <<pRightId << pNode->right->left ;
                    if(h > 0)
                    {
                //        qDebug() << "是时候起飞旋转了";
                        if(isInterlayer)
                        {
                   //         qDebug() << "开始in balanceLBI";
                            h = balanceLeftBranchInterlayer(pNode->right);
                //            qDebug() << "h: " << h;
                            if(h > 0)
                            {
                                h = balanceRightBranch(pNode);
                            }
                        }
                        else
                        {
                             h = balanceRightBranch(pNode);             //没有隔层调用子节点中的数据
                        }
                    }

                  //  qDebug() << "h: " << h;
                    return h;
                }
            }

            while(++i < n)
            {
                pNode->key[i-1] = pNode->key[i];
                pNode->data[i-1] = pNode->data[i];
            }
            pNode->nItems -= 1;

            return 0;
        }
    }

    return -1;
}

/*
 * 平衡左子树
 * 由于调用直接子节点数据,导致子节点删除的情况
 *
 */
int TTree::balanceLeftBranch(TTREENODE *&pNode)
{
    if(pNode->balance < 0)
    {
        pNode->balance = 0;
                                        //至于返不返回1,还需要看是不是(祖祖)祖父节点调用最下层节点的情况,(决定重新写一个这种情况下的平衡方法)
        return 1;                       //h>=1,证明子节点一层全部删除,pNode左子树少一层,可能导致旋转,返回1
    }
    else if(pNode->balance == 0)
    {
        pNode->balance = 1;
        return 0;                       //删除了pNode的左子树,但是还有右子树支撑平衡
    }
    else
    {
        TTREENODE *pRightId = pNode->right;
        int prightbf = pRightId->balance;
        if(prightbf >= 0)      //
        {
            pNode = singleRotateRight(pNode);
            if(prightbf == 0)               //第二次寻BUG:用prightbf代替pRightId->balance,因为是指针,在旋转后,balance变化,导致前后不一致
            {
                pNode->balance = -1;
                pNode->left->balance = 1;
                return 0;
            }
            else
            {
                pNode->balance = 0;
                pNode->left->balance = 0;
                return 1;               //旋转平衡导致pNode的深度-1,可能对上层造成影响
            }
        }
        else
        {
            pNode = doubleRotateRightLeft(pNode);
            return 1;
        }
    }

    return 0;

}

/*
 * 平衡右子树
 * 由于调用直接子节点数据,导致子节点删除的情况
 * 由于删除可能导致旋转,所以需要判断,删除之前树肯定是平衡的
 */
int TTree::balanceRightBranch(TTREENODE *&pNode)
{
    if(pNode->balance > 0)
    {
        pNode->balance = 0;
        return 1;
    }
    else if(pNode->balance == 0)
    {
        pNode->balance = -1;
        return 0;
    }
    else
    {
        TTREENODE *pLeftId = pNode->left;
        int pleftbf = pLeftId->balance;
        if(pleftbf <= 0)
        {
            pNode = singleRotateLeft(pNode);

            if(pleftbf == 0)
            {
                pNode->balance = 1;
                pNode->right->balance = -1;
                return 0;
            }
            else
            {
                pNode->balance = 0;
                pNode->right->balance = 0;
                return 1;
            }
        }
        else
        {
            pNode = doubleRotateLeftRight(pNode);

            return 1;
        }
    }

    return 0;
}

/*
 * 平衡右子树分支
 * 由于删除的另一种情况,节点跨层调用底层节点的数据,导致节点删除,可能需要平衡旋转
 */
int TTree::balanceRightBranchInterlayer(TTREENODE *&pNode)
{
    int h;
    if(pNode->right == NULL)
    {
        if(pNode->left == NULL)                                                         //第二次BUG:两种情况,这种是虽然隔代调入删除节点,但是还有一层直接调入删除。见乱画本
        {
            return 1;
        }
        h = balanceRightBranch(pNode);
        return h;
    }

    TTREENODE *tempNode = pNode->right;
    if((h = balanceRightBranchInterlayer(tempNode)) > 0)
    {
        h = balanceRightBranch(pNode);
    }
    else
    {
        return 0;
    }

    return h;
}

/*
 * 平衡左子树分支
 * 由于删除的另一种情况,节点跨层调用底层节点的数据,导致节点删除,可能需要平衡旋转
 * 需要递归从最底层开始查看是否需要旋转,如果最底层高度不变,则对整棵树的平衡不会造成影响
 */
int TTree::balanceLeftBranchInterlayer(TTREENODE *&pNode)
{
    int h;
    //qDebug() << "pNode->left: " << pNode->left;
    if(pNode->left == NULL)
    {
      //  qDebug() << "最底层,开始balanceLeftBranch";
        if(pNode->right == NULL)                                                         //第二次修改:两种情况,这种是虽然隔代删除节点,但是还有一层删除。见本
        {
            return 1;
        }
        h = balanceLeftBranch(pNode);
        return h;
    }

    TTREENODE *tempNode = pNode->left;
    if((h = balanceLeftBranchInterlayer(tempNode)) > 0)
    {
        h = balanceLeftBranch(pNode);                                                       //第二次修改
    }
    else
    {
        return 0;
    }

    return h;
}

bool TTree::isEmpty() const
{
    return root == NULL;
}

int TTree::keyCompare(ElementKey key1, ElementKey key2)
{
    if(key1.size() < key2.size())
    {
        return -1;
    }
    else if(key1.size() > key2.size())
    {
        return 1;
    }
    else{
        return QString::compare(key1, key2, Qt::CaseSensitive);
    }

}

void TTree::PreOrderTraverse(TTREENODE *pNode) const
{
    if (pNode != NULL)
    {
        int nSize = pNode->nItems;
        qDebug()<<"bf: " << pNode->balance << " nItems: " << pNode->nItems;
        for (int i = 0; i < nSize; i++)
        {
            //printf("%02d ", pNode->item[i]);
            qDebug() << pNode->key[i] << " ";
        }
        qDebug()<<"||";
        PreOrderTraverse(pNode->left);
        PreOrderTraverse(pNode->right);
    }
}



T树索引的学习与实现(二)

标签:

原文地址:http://blog.csdn.net/u013815649/article/details/51941563

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!