源代码:
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: 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);
}
}