1. 程式人生 > >T樹索引的學習與實現(二)

T樹索引的學習與實現(二)

原始碼:

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);
    }
}