您的位置:首页 > 编程语言 > C语言/C++

二叉排序树C语言实现二

2016-05-07 11:12 495 查看
在上一篇文章中(http://blog.csdn.net/xiaowang627/article/details/51332201),对二叉排序树的定义和查找、插入等操作进行了图文描述和C语言实现,本文将详解二叉搜索树的删除操作。

一、节点删除:如下图所示



(1)删除叶节点(2、4、9、20):直接删除

(2)删除的节点只有一个孩子(左孩子或右孩子)(7、13):将这个节点的孩子提升替换该节点即可

如图所示,删除节点7:



(3)删除的节点有两个孩子节点(6、15、18)。需要保证删除该节点后仍然满足二叉排序树的性质,则必须要用该节点的中序后继替换该节点!再对该节点和替换节点的子树进行处理。

根据求节点中序后继的算法,一个节点的中序后继为该节点右子树上的最左节点,该后继节点必不存在左孩子,考虑两种情况,a、该后继节点为其右孩子(如节点6后继节点7为其右孩子);b、该后继节点不为其右孩子(如节点15,其后继节点17不为其右孩子)

情况a:直接将后继节点替换该节点,如下图删除节点6:



情况b:先用后继节点右孩子替换该后继节点,再用后继节点替换源节点,如下图删除节点15



综上所述,将删除节点my_node的情形总结为以下几种:

1、my_node为叶节点

2、my_node仅有一个孩子

      2.1、my_node有仅左孩子

      2.2、my_node仅有右孩子

3、my_node既有左孩子又有右孩子

     3.1、my_node后继为my_node->rchild(my_node->rchild无左孩子)

     3.2、my_node后继不为my_node->rchild(my_node->rchild有左孩子)

代码:(此处代码以个人理解的通俗方式书写,可能比较冗长,有较大优化空间)

STnode *STree_Delete(STnode *tree, STnode *my_node)
{
STnode *parent=my_node->p;
STnode *suc_parent;
STnode *successor;

if(my_node->left==NULL && my_node->right==NULL)//叶节点
{
if(parent==NULL)//只有一个节点
return NULL;

if(my_node==parent->left)
parent->left=NULL;
else
parent->right=NULL;
}
else if(my_node->left && my_node->right==NULL)//仅有左孩子
{
if(parent==NULL)//删除根节点
{
return tree->left;
}

if(my_node==parent->left)
{
parent->left=my_node->left;
my_node->left->p=parent;
}
else
{
parent->right=my_node->left;
my_node->left->p=parent;
}
}
else if(my_node->left==NULL && my_node->right)//仅有右孩子
{
if(parent==NULL)//删除根节点
{
return tree->right;
}

if(my_node==parent->left)
{
parent->left=my_node->right;
my_node->right->p=parent;
}
else
{
parent->right=my_node->right;
my_node->right->p=parent;
}
}
else//有两个孩子
{
successor=STree_Successor(my_node);

if(successor == my_node->right)//my_node后继为my_node->rchild
{
if(my_node==parent->left)
{
parent->left=successor;
successor->p=parent;
successor->left=my_node->left;
}
else
{
parent->right=successor;
successor->p=parent;
successor->left=my_node->left;
}
}
else //my_node后继不为my_node->rchild
{
suc_parent=successor->p;
suc_parent->left=successor->right;
successor->right->p=suc_parent;

successor->right=my_node->right;
successor->left=my_node->left;
successor->p=my_node->p;
}
}
if(parent==NULL)//删除根节点
return successor;
else
return tree;
}


二、主函数,测试用例及其头文件等

#include <stdio.h>
#include <stdlib.h>
typedef struct STnode
{
int key;//数据信息
struct STnode *left;//指向左孩子
struct STnode *right;//指向右孩子
struct STnode *p;//指向父节点
} STnode;
STnode* STree_Insert(STnode *tree, STnode *my_node);
void STree_Inorder(STnode *tree);
STnode *STree_Creat(STnode *tree, int arr[], int n);
STnode *STree_Find(STnode *tree, int my_key);
STnode *STree_Max(STnode *tree);
STnode *STree_Min(STnode *tree);
STnode *STree_Successor(STnode *my_node);
STnode *STree_Predecessor(STnode *my_node);
STnode *STree_Delete(STnode *tree, STnode *my_node);

int main(void)
{
int i;
int arr[]={15,6,20,3,7,17,21,4,13,19,9};
STnode *tree=NULL;
STnode *p;

tree=STree_Creat(tree, arr, 11);

STree_Inorder(tree);
printf("\n");

p=STree_Find(tree, 7);
printf("find the key: %d\n",p->key);

p=STree_Max(tree);
printf("the max key: %d\n", p->key);

p=STree_Min(tree);
printf("the min key: %d\n",p->key);

p=STree_Successor(STree_Find(tree, 7));
printf("the successor of 7 is %d\n",p->key);

p=STree_Predecessor(STree_Find(tree, 7));
printf("the predessor of 7 is %d\n",p->key);

//以下三组删除操作在同一颗树上连续进行;
p=STree_Delete(tree, STree_Find(tree, 4));
printf("delete the leaf node 4:");
STree_Inorder(p);
printf("\n");

p=STree_Delete(tree, STree_Find(tree, 20));
printf("delete the node 20 which only have left child:");
STree_Inorder(p);
printf("\n");

p=STree_Delete(tree, STree_Find(tree, 7));
printf("delete the node 7 which only have right child:");
STree_Inorder(p);
printf("\n");

//重置二叉排序树,实验删除节点6和15
tree=NULL;
tree=STree_Creat(tree, arr, 11);

p=STree_Delete(tree, STree_Find(tree, 6));
printf("delete the node 6 which have two children:");
STree_Inorder(p);
printf("\n");

p=STree_Delete(tree, STree_Find(tree, 15));
printf("delete the node 15 which have two children:");
STree_Inorder(p);
printf("\n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息