二叉排序树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有左孩子)
代码:(此处代码以个人理解的通俗方式书写,可能比较冗长,有较大优化空间)
二、主函数,测试用例及其头文件等
一、节点删除:如下图所示
(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; }
相关文章推荐
- 二叉查找树
- 详解Java二叉排序树
- 合并两个二叉排序树(二叉查找树)到一个数组中
- 一个先序或后序序列 还原唯一 二叉排序树 (C语言实现)
- 二叉查找树(二叉排序树、有序二叉树)算法分析及实现
- 二叉排序树相关操作
- 程序员面试100题---1.把二元查找树转变成排序的双向链表
- 二叉查找树
- 二叉排序树节点删除&简单性能分析
- 二叉搜索树性质与实现
- 二叉排序树
- 九度oj 1201 二叉排序树的创建+遍历
- 单向链表结点删除问题
- 数据结构学习之二叉排序树
- 二叉搜索树转双向链表(面试题27)
- 判断是否为合法排序二叉树
- 二叉排序树_C++实现
- 数据结构 JAVA描述(十五) 动态查找表 二叉排序树 二叉平衡树
- poj2418~Hardwood Species~二叉排序树
- poj1577~Falling Leaves~二叉排序树~