#include <iostream>
#include <queue>
using namespace std;
/******************************
PROGRAMER: Fanchenxin
M阶多路查找树:
1.定义任意非叶子结点最多只有M个儿子;且M>2;
2.根结点的儿子数为[2, M];
3.除根结点以外的非叶子结点的儿子数为[M/2, M];
4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
5.非叶子结点的关键字个数=指向儿子的指针个数-1;
6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的
子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
8.所有叶子结点位于同一层;
1、每个结点的属性:
(1)BTreeNode.keyNum: 每个结点包含的关键字个数;
(2)BTreeNode.key1, BTreeNode.key2, .....BTreeNode.keyn, 以非降序排列
(3)BTreeNode.isLeaf, 表示BTreeNode 结点是否是叶子结点。
(4)BTreeNode.subTree: 每个结点还包含BTreeNode.keyNum+1个孩子指针
BTreeNode.subTree1, BTreeNode.subTree2, BTreeNode.subTree3......BTreeNode.subTree(keyNum+1)
(5) BTreeNode.father 指向该节点的父亲节点。
2、BTreeNode中的关键字对存储在各子树中的关键字范围加以分割。
3、每个叶结点具有相同的深度,为树的高度
4、我们可以为每棵B树规定一个最小度数:T,
那么每个结点所包含的关键字个数的范围:
T-1 ~2T-1, 所包含的孩子结点个数为T ~ 2T。
当结点关键字个数为2T - 1时,该结点满。
(根结点至少包含1个关键数,而其他结点至少包含T - 1个关键字。
******************************/
#define T (2)
typedef struct _B_TreeNode_
{
int keyNum;
char key[2*T-1];
bool isLeaf;
struct _B_TreeNode_* subTree[2*T];
struct _B_TreeNode_* father;
}BTreeNode;
BTreeNode* newBTreeNode(bool is_Leaf)
{
BTreeNode* newNode = (BTreeNode*)malloc(sizeof(BTreeNode));
if(newNode != NULL)
{
newNode->keyNum = 0;
memset(newNode->key, '\0', (2*T-1) * sizeof(char));
newNode->isLeaf = is_Leaf;
memset(newNode->subTree, NULL, 2*T * sizeof(BTreeNode*));
newNode->father = NULL;
}
else
return NULL;
return newNode;
}
void deleteKey(BTreeNode* pCur, const char keyChar);
/* father为需要分裂的节点的父节点
splitChildIdx 为需要分裂的节点的index,
*/
void splitChild(BTreeNode* father, int splitChildIdx)
{
if(!father)
return;
/*father->subTree[splitChildIdx] 为需要分裂的节点,分裂完后作为
父节点subTree相应位置的左孩子*/
BTreeNode* leftChild = father->subTree[splitChildIdx];
BTreeNode* rightChild = newBTreeNode(true); /* 新分裂出来的节点放在分裂点的右边 */
rightChild->father = father;
int i = 0, n = T-1;
char midChar = leftChild->key[n]; /* 保存中间KEY 值 */
for(; i < n; i++)
{
rightChild->key[i] = leftChild->key[i+T]; /* 将分裂节点的后T-1个KEY给右孩子 */
}
memset(&leftChild->key[n], '\0', sizeof(char)*T); /* 清空分裂节点后面的T个KEY 值 */
leftChild->keyNum = n; /* 分裂成的两个节点key 的个数都为T-1 */
rightChild->keyNum = n;
/* 如果该分裂节点不是叶子节点,也就是说它存在子节点
则需要将后面T个子节点送给右节点*/
if(leftChild->isLeaf == false){
rightChild->isLeaf = false;
for(i = 0; i < n + 1; i++){
rightChild->subTree[i] = leftChild->subTree[i+n+1];
rightChild->subTree[i]->father = rightChild;
}
/* 同时清除分裂节点的后面T个子节点指针 */
memset(&leftChild->subTree[n+1], NULL, sizeof(BTreeNode*) * T);
}
for(i = father->keyNum; i >= splitChildIdx; i--){
father->subTree[i+1] = father->subTree[i];
}
father->keyNum++;
father->subTree[splitChildIdx+1] = rightChild; /*将新分裂出来的右节点加到父节点的相应位置*/
for(i = father->keyNum-1; i >= splitChildIdx; i--){
father->key[i+1] = father->key[i];
}
father->key[splitChildIdx] = midChar; /* 将分裂节点的中间KEY 放到父节点的KEY数组中 */
}
/*往节点KEY个数未满的节点处插入key值*/
void insertKeyNotFull(BTreeNode* pNode, char keyChar)
{
if(!pNode)
return;
if(pNode->keyNum == 0){
pNode->key[0] = keyChar;
pNode->keyNum = 1;
return;
}
int idx = pNode->keyNum - 1;
if(pNode->isLeaf){ /* 如果该节点是叶子节点则找到合适位置并插入 */
for(; idx >= 0; idx--)
{
if(keyChar < pNode->key[idx])
pNode->key[idx+1] = pNode->key[idx];
else
break;
}
pNode->key[idx+1] = keyChar;
pNode->keyNum++;
}
else{
for(; idx >= 0; idx--)
{
if(keyChar > pNode->key[idx])
break;
}
idx += 1;
/* 如果该节点的子孩子需要分裂 */
if(pNode->subTree[idx]->keyNum >= 2*T -1){
splitChild(pNode, idx);
if(keyChar > pNode->key[idx])
idx += 1;
}
insertKeyNotFull(pNode->subTree[idx], keyChar);
}
return;
}
void insertKey(BTreeNode** root, char keyChar)
{
if(*root == NULL){
*root = newBTreeNode(true);
}
BTreeNode* pCur = *root;
if(pCur->keyNum >= 2*T-1){
BTreeNode* newRoot = newBTreeNode(false);
newRoot->subTree[0] = *root;
newRoot->subTree[0]->father = newRoot;
*root = newRoot;
splitChild(newRoot, 0);
insertKeyNotFull(newRoot, keyChar);
}
else{
insertKeyNotFull(*root, keyChar);
}
return;
}
void printKey(char* arry, int n, int layer)
{
int i = 0;
cout << "<" << layer << "> ";
for(; i < n; i++)
cout << arry[i];
cout << " ";
}
static int layer = 1;
/* 深度优先遍历: layer 为该节点所在的层*/
void DPSearch(BTreeNode* pNode)
{
if(pNode == NULL)
return;
printKey(pNode->key, pNode->keyNum, layer);
int i = 0;
layer++;
for(; i < pNode->keyNum+1; i++){
DPSearch(pNode->subTree[i]);
}
layer--;
return;
}
/* 广度优先遍历 */
void BPSearch(BTreeNode* pNode)
{
if(pNode == NULL)
return;
queue<BTreeNode*> q;
q.push(pNode);
BTreeNode* pCur = NULL;
while(!q.empty())
{
pCur = q.front();
printKey(pCur->key, pCur->keyNum, 0);
q.pop();
int i = 0;
for(; i < pCur->keyNum+1; i++){
if(pCur->subTree[i]){
q.push(pCur->subTree[i]);
}
}
}
}
BTreeNode* searchKey(BTreeNode* pCur, char keyChar, int* keyIndex)
{
if(pCur== NULL)
return NULL;
int i = 0;
while(i < pCur->keyNum && keyChar > pCur->key[i])
++i;
if(i < pCur->keyNum && keyChar == pCur->key[i]){
if(keyIndex)
*keyIndex = i;
return pCur;
}
if(pCur->isLeaf == false){
pCur = pCur->subTree[i];
return searchKey(pCur ,keyChar, keyIndex);
}
else
return NULL;
}
BTreeNode* create_Btree(const char* key, int n)
{
BTreeNode* root = newBTreeNode(true);
if(root){
int i = 0;
for(; i < n; i++){
insertKey(&root, key[i]);
}
}
return root;
}
/* pNode 需要删除的key 在该节点里
isLeft标识找到的兄弟是左兄弟还是右兄弟
index 为pNode 在父节点的subTree数组中的位置
返回值为true 表示找到否则没找到
*/
bool checkBrotherIsRich(BTreeNode* pNode, int* index, bool* isLeft)
{
if(pNode == NULL)
return false;
if(pNode->father == NULL)
return false;
BTreeNode* father = pNode->father;
/* 查找该节点在父节点的subTree 的索引 */
int i = 0;
for(; i < father->keyNum+1; i++){
if(father->subTree[i] == pNode){
*index = i;
break;
}
}
if(i == 0) //如果该节点是最左边的孩子,则只存在右兄弟
{
if(father->subTree[i+1]->keyNum > T-1){
*isLeft = false;
return true;
}
else
return false;
}
if(i == father->keyNum) //如果该节点是最右边的孩子,则只存在左兄弟
{
if(father->subTree[i-1]->keyNum > T-1){
*isLeft = true;
return true;
}
else
return false;
}
if(i > 0 && i < father->keyNum){
if(father->subTree[i-1]->keyNum > T-1){
*isLeft = true;
return true;
}
else{
if(father->subTree[i+1]->keyNum > T-1){
*isLeft = false;
return true;
}
else
return false;
}
}
return false;
}
/* 将arry 数组index 后面的内容前移一个单位到index 位置 */
//template<typename T>
void moveProcess(char arry[], int index, int n)
{
int i = index, j = index + 1;
for(; j < n; j++){
arry[i++] = arry[j];
}
arry[i] = '\0';
}
/* 需要旋转的是叶子节点 */
void leafRotateAndDelete(BTreeNode* pNode, int index, bool isLeft, char deleteKeyChar)
{
if(!pNode)
return;
char fatherChar = '\0', brotherChar = '\0';
BTreeNode* father = pNode->father;
int fatherKeyNum = father->keyNum;
BTreeNode* pBrother = NULL;
if(isLeft == true){ /* 如果富有的兄弟节点位于删除节点的左边 */
pBrother = father->subTree[index-1];
fatherChar = father->key[index-1];
brotherChar = pBrother->key[pBrother->keyNum-1];
/* 将从父节点借的key 插入到该节点中,并删除deleteChar */
int i = 0, j = 1;
for(; i < pNode->keyNum; i++){
if(pNode->key[i] != deleteKeyChar){
pNode->key[j++] = pNode->key[i];
}
}
pNode->key[j] = '\0';
pNode->key[0] = fatherChar;
/* 用左兄弟的最大的key 替换父亲被借走的key */
father->key[index-1] = brotherChar;
/* 左兄弟节点最大的key 删掉 */
pBrother->key[pBrother->keyNum-1] = '\0';
pBrother->keyNum--;
}
else{
pBrother = father->subTree[index+1];
fatherChar = father->key[index];
brotherChar = pBrother->key[0];
int i = 0, j = 0;
for(; i < pNode->keyNum; i++){
if(pNode->key[i] != deleteKeyChar){
pNode->key[j++] = pNode->key[i];
}
}
pNode->key[j] = fatherChar; //从父节点借一个key 插入到删除节点的最右边
/*从删除节点的右边兄弟节点借得最小的key替换父节点被借走的key*/
father->key[index] = brotherChar;
/* 右边的兄弟节点的所有key 往前移一位 */
moveProcess(pBrother->key, 0, pBrother->keyNum);
pBrother->keyNum--;
}
}
/* 将pSubRoot 为根节点的子树的所有key 重新插入pTree中 */
void insertTreeNode(BTreeNode*pTree, BTreeNode* pSubRoot)
{
if(!pTree || !pSubRoot)
return;
queue<BTreeNode*> q;
q.push(pSubRoot);
BTreeNode* pCur = NULL;
int i = 0;
while(!q.empty())
{
pCur = q.front();
for(i = 0; i < pCur->keyNum; i++){
insertKey(&pTree, pCur->key[i]);
}
q.pop();
for(i = 0; i < pCur->keyNum+1; i++){
if(pCur->subTree[i]){
q.push(pCur->subTree[i]);
}
}
free(pCur);
pCur = NULL;
}
return;
}
/* 执行合并或旋转操作 */
void mergeOrRotate(BTreeNode* pNode)
{
if(!pNode)
return;
/* pNode 为根节点 */
if(pNode->father == NULL){ //根节点,合并成一个节点 少一层
/* 如果根节点只有一个key,且它的左右孩子的key
都不大于T-1,那么将它们合并后总的key 的个数
不超过(1 + T-1 + T-1) = 2*T -1, 因此可以将三个节点
合并成一个节点 */
if(pNode->keyNum == 1 &&
pNode->subTree[0]->keyNum <= T-1
&& pNode->subTree[1]->keyNum <= T-1){
BTreeNode* left = pNode->subTree[0];
BTreeNode* right = pNode->subTree[1];
char tmp = pNode->key[0];
int i = 0, j = 0;
for(; j < left->keyNum; j++){
pNode->key[j] = left->key[j];
}
pNode->key[j] = tmp;
pNode->keyNum += left->keyNum;
for(i = 0; i < left->keyNum+1; i++){
pNode->subTree[i] = left->subTree[i];
pNode->subTree[i]->father = pNode;
}
for(i = pNode->keyNum, j = 0; j < right->keyNum; j++){
pNode->key[i] = right->key[j];
pNode->subTree[i] = right->subTree[j];
pNode->subTree[i]->father = pNode;
i++;
}
pNode->subTree[i] = right->subTree[j];
pNode->subTree[i]->father = pNode;
pNode->keyNum += right->keyNum;
free(left);
free(right);
left = NULL;
right = NULL;
}
return;
}
/* 如果不是根节点 */
bool isLeft = true; int sub_idx = 0;
/* sub_idx 为pNode 在父节点subTree的位置,
isLeft 标记找到的富裕的节点是左还是右兄弟*/
bool isFind = checkBrotherIsRich(pNode, &sub_idx, &isLeft);
if(isFind){ // 如果能找到比较富裕的兄弟节点,借个节点进行旋转操作
if(isLeft == false){ //如果右兄弟富裕则左旋操作
BTreeNode* pRight = pNode->father->subTree[sub_idx+1];
char tmp = pNode->father->key[sub_idx];
pNode->father->key[sub_idx] = pRight->key[0]; //用右节点的第一个key覆盖父节点的key
/* 右孩子的key 前移 */
moveProcess(pRight->key, 0, pRight->keyNum);
BTreeNode* pRightFirstChild = pRight->subTree[0]; //保存右孩子的第一子树的节点指针
/* 右孩子子树指针前移 */
int i = 0, j = 1;
for(; j < pRight->keyNum+1; j++){
pRight->subTree[i++] = pRight->subTree[j];
}
pRight->subTree[i] = NULL;
pRight->keyNum--;
/* 将右子树的第一个子树挂接到pNode的最大子树处
并且将tmp 这个key 放在最大处*/
int n = pNode->keyNum;
pNode->key[n] = tmp;
n = pNode->keyNum++;
pNode->subTree[n+1] = pRightFirstChild;
pRightFirstChild->father = pNode;
}else{ // 如果左兄弟富裕则进行右旋操作
BTreeNode* pLeft = pNode->father->subTree[sub_idx-1];
char tmp = pNode->father->key[sub_idx];
int n = pLeft->keyNum;
pNode->father->key[sub_idx] = pLeft->key[n-1]; //用左节点的最大一个key覆盖父节点的key
pLeft->key[n-1] = '\0';
BTreeNode* pLeftLastChild = pLeft->subTree[n];
pLeft->subTree[n] = NULL;
pLeft->keyNum--;
int i = 0, j = 1;
for(; i < pNode->keyNum; i++){
pNode->key[j++] = pNode->key[i];
}
pNode->key[0] = tmp;
for(i = 0, j = 1; i < pNode->keyNum+1; i++){
pNode->subTree[j++] = pNode->subTree[i];
}
pNode->subTree[0] = pLeftLastChild;
pLeftLastChild->father = pNode;
pNode->keyNum++;
}
}else{// 如果左右兄弟节点都不富裕
if(pNode->keyNum == 0){// 如果当前节点的key被删空了
BTreeNode* pCur = pNode;
BTreeNode* pFather = pCur->father;
if(pFather->keyNum > T -1){ //如果它的父节点还富裕
int idx = 0;
for(; idx < pFather->keyNum+1; idx++){
if(pFather->subTree[idx] == pCur)
break;
}
BTreeNode* pBrother = NULL;
if(idx == pFather->keyNum){
pBrother = pFather->subTree[idx-1];
int n = pBrother->keyNum;
pBrother->key[n] = pFather->key[idx-1];
moveProcess(pFather->key, idx-1, pFather->keyNum);
pBrother->subTree[n+1] = pCur->subTree[0];
pBrother->subTree[n+1]->father = pBrother;
pFather->subTree[idx] = NULL;
pBrother->keyNum++;
pFather->keyNum--;
free(pCur);
pCur = NULL;
}
else{
pBrother = pFather->subTree[idx+1];
pCur->key[0] = pFather->key[idx];
pCur->keyNum = 1;
moveProcess(pFather->key, idx, pFather->keyNum);
int i = 1, j = 0;
for(; j < pBrother->keyNum; j++){
pCur->key[i++] = pBrother->key[j];
}
for(i = 1, j = 0; j < pBrother->keyNum+1; j++){
pCur->subTree[i] = pBrother->subTree[j];
pCur->subTree[i]->father = pCur;
i++;
}
pCur->keyNum += pBrother->keyNum;
pFather->keyNum--;
free(pBrother);
pBrother = NULL;
}
}
else{ //如果父节点也不富裕则递归调用
mergeOrRotate(pNode->father);
}
return;
}
else{ //如果该节点既不是父节点,左右兄弟也不富裕,并且key个数也不为0
mergeOrRotate(pNode->father);
}
}
}
/* pNode 是叶子节点,index 为其在父节点subTree 中的索引 */
void leafMergeAndDelete(BTreeNode* pNode, int index, const char deleteKeyChar)
{
if(pNode == NULL)
return;
char fatherChar = '\0';
BTreeNode* father = pNode->father;
BTreeNode* brother = NULL;
if(index == 0){ /* 如果删除节点位于最左边只能和右边的节点进行merge */
fatherChar = father->key[0];
brother = father->subTree[1];
/* 虽然删除了一个key 但是父节点的key添加在其最右边以此
key 的个数没变*/
int step = pNode->keyNum;
/* 将右边的兄弟节点的[0~step) 位置留给pNode和父节点的key */
int i = brother->keyNum + step - 1, j = brother->keyNum - 1;
for(; i >= step; i--){
brother->key[i] = brother->key[j--];
}
/* 将删除节点pNode 除了deleteChar 复制到brother节点 */
for(i = 0, j = 0; i < step; i++)
{
if(pNode->key[i] != deleteKeyChar)
brother->key[j++] = pNode->key[i];
}
brother->key[step-1] = fatherChar;
brother->keyNum += step;
free(pNode); //删除该节点
pNode = NULL;
/* 将父节点的key 索引前移 */
moveProcess(father->key, 0, father->keyNum);
/*父节点的子树索引前移*/
for(i = 1, j = 0; i < father->keyNum+1; i++){
father->subTree[j++] = father->subTree[i];
}
father->subTree[j] = NULL;
father->keyNum--;
}
else{
fatherChar = father->key[index-1];
brother = father->subTree[index-1];
moveProcess(father->key, index-1, father->keyNum);
int n = brother->keyNum;
brother->key[n] = fatherChar;
int i = n+1, j = 0;
for(; j < pNode->keyNum; j++){
if(pNode->key[j] != deleteKeyChar){
brother->key[i++] = pNode->key[j];
}
}
for(i = index, j = index+1; j < father->keyNum+1; j++){
father->subTree[i++] = father->subTree[j];
}
father->subTree[i] = NULL;
father->keyNum--;
brother->keyNum += pNode->keyNum;
free(pNode); //删除该节点
pNode = NULL;
}
/* case 3.2 : merger 后父节点变得不富裕 */
if(father->keyNum < T-1){
/*
空
| ==> UV
UV
*/
if(father->keyNum == 0 && father->father == NULL){
BTreeNode* ptmp = father->subTree[0];
int i = 0;
for(; i < ptmp->keyNum; i++){
father->key[i] = ptmp->key[i];
}
father->keyNum = i;
father->isLeaf = true;
father->subTree[0] = NULL;
free(ptmp);
ptmp = NULL;
return;
}
mergeOrRotate(father);
}
// case 3.1 如果合并后父节点任然富裕,则删除结束返回
return;
}
/***************************************************************************
(1) 找不到包含keyChar 的节点,直接return
(2) 以下的case 都是能够找到删除节点的情况
<1>删除的节点是叶子节点:
case 1: 删除一个KEY 后,key 的个数不小于T-1,则直接删除
case 2: 删除后key的个数小于T-1,这时候如果其
相邻的兄弟节点(富有的)的个数有大于T-1的,借
一个KEY,并且将富有的兄弟节点的最邻近父节点的
KEY移到父节点上,父节点的KEY 则移到删除节点。
case 3: 如果左右兄弟节点都不富有,也就是说他们的key个
数都是T-1的情况。
case 3.1: 如果父节点富裕,则将删除节点和相邻的一个
兄弟节点合并再删除。
case 3.2: 如果父节点也不富裕,进行合并旋转操作等
操作并删除KEY。
<2>删除的节点不是叶子节点:
先找到这个key所在的右子树的最小key , 用这个最小key
来替换要删除的key,然后再从叶子节点删除最小key。
把删除的节点不是叶子节点转换为在叶子节点上删除
key 的情况。
*********************************************************************************/
void deleteKey(BTreeNode* pCur, const char deleteKeyChar)
{
if(!pCur)
return;
int key_idx = 0;
/* 查找需要删除的key 在哪个节点上 */
BTreeNode* pDeleteNode = searchKey(pCur, deleteKeyChar, &key_idx);
if(!pDeleteNode)
return;
if(pDeleteNode->isLeaf == true){ // <1>删除的节点是叶子节点
if(pDeleteNode->keyNum > T - 1){ // case 1 该节点删除一个key后也足够富裕
/*将deleteKey 从其所在的节点删除 */
moveProcess(pDeleteNode->key, key_idx, pDeleteNode->keyNum);
pDeleteNode->keyNum--;
}
else{ //删除后不富裕
if(pDeleteNode->father == NULL){
if(pDeleteNode->keyNum == 1){
cout << "根节点只有一个key 不能再删除了!!!" << endl;
return; //如果只有一个根节点,且只有一个key
}
else{
moveProcess(pDeleteNode->key, key_idx, pDeleteNode->keyNum);
pDeleteNode->keyNum--;
}
return;
}
bool isLeft = true; int sub_idx = 0;
/* sub_idx 为pDeleteNode 在父节点subTree的位置,
isLeft 标记找到的富裕的节点是左还是右兄弟*/
bool isFind = checkBrotherIsRich(pDeleteNode, &sub_idx, &isLeft);
if(isFind){ // case 2 找到富裕的兄弟节点
leafRotateAndDelete(pDeleteNode, sub_idx, isLeft, deleteKeyChar);
}
else{ // case 3 左右兄弟节点都不富裕, 都只有T-1个key
leafMergeAndDelete(pDeleteNode, sub_idx, deleteKeyChar);
}
}
}
else{ // <2>删除的节点不是叶子节点
/* deleteKey 右边的子树 */
BTreeNode* deleteRightSubTree = pDeleteNode->subTree[key_idx+1];
BTreeNode* pCur = deleteRightSubTree;
/* 一直找到右边子树的叶子节点的最小key */
while(pCur->subTree[0])
pCur = pCur->subTree[0];
char sm_key = pCur->key[0];
/* 用最小key 替换要删除的key */
pDeleteNode->key[key_idx] = sm_key;
deleteKey(pCur, sm_key); //从叶子节点删除最小key
}
return;
}
int main()
{
BTreeNode* pRoot;
char key[] = {'C', 'N', 'G', 'A', 'H', 'E', 'K', 'Q', 'M', 'F', 'W', 'L', 'T', 'Z', 'D', 'P', 'R', 'X', 'Y', 'S'};
pRoot = create_Btree(key, 20);
/*
树建完后是这样的:
G N
/ | \
C K Q T X
/ \ / \ / | | \
A DEF H LM P RS W YZ
*/
layer = 1;
DPSearch(pRoot);
cout << endl;
//BPSearch(pRoot);
//cout << endl;
BTreeNode* pFind = NULL;
char fChar = 'F';
pFind = searchKey(pRoot, fChar, NULL);
if(pFind != NULL){
cout << "find the key: " << pFind->key << endl;
}else{
cout << "can not find the Key: " << fChar << endl;
}
#if 1
/* (1) 测试删除的key 在叶子节点的情况 */
cout << "删除L后:" << endl;
deleteKey(pRoot, 'L');
DPSearch(pRoot);
cout << endl;
/* 删除L 后: (直接删除L)
G N
/ | \
C K Q T X
/ \ / \ / | | \
A DEF H M P RS W YZ
*/
cout << "删除W后:" << endl;
deleteKey(pRoot, 'W');
DPSearch(pRoot);
cout << endl;
/* 删除W 后: (向父节点借T, 将左兄弟的最大key 'S' 移到父节点)
G N
/ | \
C K Q S X
/ \ / \ / | | \
A DEF H M P R T YZ
*/
cout << "删除R后:" << endl;
deleteKey(pRoot, 'R');
DPSearch(pRoot);
cout << endl;
/* 删除R 后: (左右兄弟都不富裕,将R所在的分支和左分支合并 )
G N
/ | \
C K S X
/ \ / \ / | \
A DEF H M PQ T YZ
*/
cout << "删除M后:" << endl;
deleteKey(pRoot, 'M');
DPSearch(pRoot);
cout << endl;
/* 删除M 后: (其实执行了一次合并和一次左旋操作。M的左右兄弟都不富裕,并且删除合并后其父节点
的keyNum = 0, 父节点的右兄弟SX 富裕,于是向它借一个
S,进行左旋操作。)
(1) 合并操作
G N
/ | \
C 空 S X
/ \ | / | \
A DEF HK PQ T YZ
(2) 左旋操作: (S放到父节点,N给空节点,S的左分支
挂接到N的最右孩子处。
G S
/ | \
C N X
/ \ / \ / \
A DEF HK PQ T YZ
*/
cout << "删除H后:" << endl;
deleteKey(pRoot, 'H');
DPSearch(pRoot);
cout << endl;
/* 删除H 后: (直接删除)
G S
/ | \
C N X
/ \ / \ / \
A DEF K PQ T YZ
*/
cout << "删除K后:" << endl;
deleteKey(pRoot, 'K');
DPSearch(pRoot);
cout << endl;
/* 删除K 后: (K的右兄弟富裕,借一个P 进行左旋操作)
G S
/ | \
C P X
/ \ / \ / \
A DEF N Q T YZ
*/
cout << "删除N后:" << endl;
deleteKey(pRoot, 'N');
DPSearch(pRoot);
cout << endl;
/* 删除N 后: (其实进行了两次合并,N的右兄弟不富裕,
且父亲也只有一个节点,父亲的左右兄
弟也不富裕,这时候将父节点
和父亲的右孩合并)
(1)第一次合并: P和Q合并父节点变为空。
G S
/ | \
C 空 X
/ \ | / \
A DEF PQ T YZ
(2)第二次合并: 空的父节点和其右节点合并
G
/ \
C S X
/ \ / | \
A DEF PQ T YZ
*/
cout << "删除P后:" << endl;
deleteKey(pRoot, 'P');
DPSearch(pRoot);
cout << endl;
/* 删除P 后:
G
/ \
C S X
/ \ / | \
A DEF Q T YZ
*/
cout << "删除Q后:" << endl;
deleteKey(pRoot, 'Q');
DPSearch(pRoot);
cout << endl;
/* 删除Q 后: 合并操作
G
/ \
C X
/ \ / \
A DEF ST YZ
*/
cout << "删除T后:" << endl;
deleteKey(pRoot, 'T');
DPSearch(pRoot);
cout << endl;
/* 删除T 后:
G
/ \
C X
/ \ / \
A DEF S YZ
*/
cout << "删除A后:" << endl;
deleteKey(pRoot, 'A');
DPSearch(pRoot);
cout << endl;
/* 删除A 后:
G
/ \
D X
/ \ / \
C EF S YZ
*/
cout << "删除E后:" << endl;
deleteKey(pRoot, 'E');
DPSearch(pRoot);
cout << endl;
/* 删除E 后:
G
/ \
D X
/ \ / \
C F S YZ
*/
cout << "删除F后:" << endl;
deleteKey(pRoot, 'F');
DPSearch(pRoot);
cout << endl;
/* 删除F 后: 两次合并操作
(1) 第一次合并
G
/ \
空 X
| / \
CD S YZ
(2) 第二次合并: 少了一层
G X
/ | \
CD S YZ
*/
cout << "删除S后:" << endl;
deleteKey(pRoot, 'S');
DPSearch(pRoot);
cout << endl;
/* 删除S 后: S 的左右节点都富裕,向左兄弟借D
D X
/ | \
C G YZ
*/
cout << "删除C后:" << endl;
deleteKey(pRoot, 'C');
DPSearch(pRoot);
cout << endl;
/* 删除C 后: C 的左右节点都不富裕,合并
X
/ \
DG YZ
*/
cout << "删除D后:" << endl;
deleteKey(pRoot, 'D');
DPSearch(pRoot);
cout << endl;
/* 删除D 后:
X
/ \
G YZ
*/
cout << "删除G后:" << endl;
deleteKey(pRoot, 'G');
DPSearch(pRoot);
cout << endl;
/* 删除G 后:
Y
/ \
X Z
*/
cout << "删除X后:" << endl;
deleteKey(pRoot, 'X');
DPSearch(pRoot);
cout << endl;
/* 删除X 后:
YZ
*/
cout << "删除Y后:" << endl;
deleteKey(pRoot, 'Y');
DPSearch(pRoot);
cout << endl;
/* 根节点只有一个key 不能再删了 */
cout << "删除Z后:" << endl;
deleteKey(pRoot, 'Z');
DPSearch(pRoot);
cout << endl;
#endif
#if 0
/* (2) 测试删除的key 不在叶子节点的情况 */
cout << "删除N后:" << endl;
deleteKey(pRoot, 'N');
DPSearch(pRoot);
cout << endl;
/* 删除N 后: 先从P的右子树找到叶子节点key 最小的Q,
用Q 覆盖P, 然后相当于从叶子节点删除P.
G P
/ | \
C K R T X
/ \ / \ / | | \
A DEF H LM Q S W YZ
*/
cout << "删除P后:" << endl;
deleteKey(pRoot, 'P');
DPSearch(pRoot);
cout << endl;
/* 删除P 后:
G Q
/ | \
C K T X
/ \ / \ / | \
A DEF H LM RS W YZ
*/
cout << "删除K后:" << endl;
deleteKey(pRoot, 'K');
DPSearch(pRoot);
cout << endl;
/* 删除K 后:
G Q
/ | \
C L T X
/ \ / \ / | \
A DEF H M RS W YZ
*/
cout << "删除L后:" << endl;
deleteKey(pRoot, 'L');
DPSearch(pRoot);
cout << endl;
/* 删除L 后:
G T
/ | \
C Q X
/ \ / \ / \
A DEF HM RS W YZ
*/
cout << "删除G后:" << endl;
deleteKey(pRoot, 'G');
DPSearch(pRoot);
cout << endl;
/* 删除G 后: 用G 右子树最小的H 来替换,并从叶子节点
删除H 即可。
H T
/ | \
C Q X
/ \ / \ / \
A DEF M RS W YZ
*/
cout << "删除Q后:" << endl;
deleteKey(pRoot, 'Q');
DPSearch(pRoot);
cout << endl;
/* 删除Q 后:
H T
/ | \
C R X
/ \ / \ / \
A DEF M S W YZ
*/
cout << "删除R后:" << endl;
deleteKey(pRoot, 'R');
DPSearch(pRoot);
cout << endl;
/* 删除R 后:
H
/ \
C T X
/ \ / | \
A DEF MS W YZ
*/
#endif
return 0;
}
运行结果:
(1)测试删除的key在叶子节点上:
(2)测试删除的key不是在叶子节点上: