排序二叉树BST的基本操作(2)前驱,后继,删除
来源:互联网 发布:python爬虫是什么发展 编辑:程序博客网 时间:2024/04/30 16:30
前文中写了基本操作中的插入,查找,最大节点,最小节点。本文主要写如何进行删除。
删除的最重要的原则是,删除后依然要维护BST的性质,也就是说,中序遍历后为升序。 删除的思路有三个。
思路一
先理解前驱和后继的含义。
节点key的前驱,就是中序遍历时,比key小的所有节点中最大的那个节点。
节点key的后继,就是中序遍历时,比key小的所有节点中最大的那个节点。
容易看出,节点key的前驱一定没有右儿子,可能有左儿子。反证很容易。如下图,节点10的前驱8可能有左儿子,可能没有左儿子。
容易看出,节点key的后继一定没有左儿子,可能有右儿子。反证很容易。如下图,节点10的后继12可能有右儿子,可能没有右儿子。
假定要删除的节点为key,那么要删除key可以用key的前驱替换key也可以用key的后继替换key。
第一种思路,优先用key的前驱替换key,如果key没有前驱,则用key的后继替换key。
首先,如果key的前驱不存在,后继也不存在。
则key是叶结点,直接删就行。
其次,如果key的前驱存在。
要做到删除p并且不丢掉p的左儿子并且依然维护BST的特性,可以用p的左儿子替换p,用p替换key。这个过程也嵌套了一个删除的过程,是一个以p的左儿子为root的子树上删除p的过程,所以接下来可以看到代码中递归的实现。(不管P的左儿子是不是NULL都可以这样嵌套地删除)
最后,如果key的前驱不存在,后继存在,
则设key的后继为p,那么类似的,根据上面的结论,p一定没有左儿子,可能有右儿子。接下来的过程和上面是对称的。
用p的值替换key,然后在以p的右儿子为root的子树中,删除p,不断嵌套删除下去。(同样,不管P的右儿子是不是NULL,这样嵌套地删除都合理。)
代码如下link erase(link t, int key){link p;if(!t)return NULL;if(t->item>key)t->l=erase(t->l,key);else if(t->item<key)t->r=erase(t->r,key);else{if(t->l == NULL&&t->r == NULL) {free_node(t);t = NULL;} else if(t->l) {for(p=t->l;p->r;p=p->r);t->item = p->item;t->l = erase(t->l,t->item);} else {for(p=t->r;p->l;p=p->l);t->item = p->item;t->r = erase(t->r,t->item);}}return t;}
思路二
把上面的优先顺序颠倒一下,优先删除后继,再删除前驱。
link erase_3(link t, int key){link p;if(!t)return NULL;if(t->item>key)t->l=erase_3(t->l,key);else if(t->item<key)t->r=erase_3(t->r,key);else{if(t->l == NULL&&t->r == NULL) {free_node(t);t = NULL;} else if(t->r) { //先判断是否有右儿子,再判断是否有左儿子,顺序和link erase(link t, int key)相反for(p=t->r;p->l;p=p->l);t->item = p->item;t->r = erase_3(t->r,t->item);} else {for(p=t->l;p->r;p=p->r);t->item = p->item;t->l = erase_3(t->l,t->item);}}return t;}
思路三
来自于《CLRS算法导论》的做法。如果说上面的思路一和思路二是从节点升序排列的角度进行的删除,那么思路三就是从形状角度进行的删除。
分3种情况处理.
(待删除的节点key和图a图b图c中的节点y是相同的节点。)
情况1 key为叶节点,则直接删。
情况2 key只有一个子节点,就把key给排挤掉。也就是,让key的父节点指向key的左儿子节点(或右儿子节点),并且让key的左子节点(或右儿子节点)的父节点指向key的父节点。如果要通过这样的图形形象的方式而非前面数字逻辑的方式进行删除,那么需要在节点结构体中增加parent指针,从而维护树的结构。
情况3 key有两个子节点,则找到key的后继,然后先用key的后继的值替换key的值,在进入到以key的后继为root的子树中,删除key节点。容易根据后继的特点知道,key的后继没有左儿子,所以删除key节点,转化为了在以key后继为root的子树中,进行情况2的删除。
代码如下。
首先修改node结构体
typedef struct node* link;struct node{int item;link l,r,parent;};
接下来删除
link erase_4(link t, int key){link del_node = search_recur(t,key);link y = NULL;link x = NULL;if ((del_node->l == NULL) || (del_node->r == NULL))y = del_node;else y = successor(del_node);if(y->l!=NULL)x = y->l;elsex = y->r;if(x!=NULL)x->parent = y->parent;if(y->parent != NULL) { if(y==y->parent->l) y->parent->l= x; else y->parent->r= x;}else {t=x;}if(y!=del_node)del_node->item = y->item;free_node(y);return t;}
- 排序二叉树BST的基本操作(2)前驱,后继,删除
- 排序二叉树BST的基本操作(2)前驱,后继,删除 http://blog.csdn.net/feliciafay/article/details/12174307
- 二查排序树的基本操作(插入,删除,找前驱与后继)
- 算法导论-二叉树删除 前驱 后继
- 二叉树的前驱和后继
- 二叉树遍历的前驱和后继
- 二叉树的遍历 插入 查找 删除 最大值 最小值 前驱 后继节点的查找
- 二叉树的祖先结点,删除,插入,查找,前驱结点,后继结点等
- 二叉查找树查找后继,前驱的问题
- 线索二叉树前驱后继的查询算法(C 语言)
- 二叉树遍历的前驱和后继规则说明
- 二叉树前驱后继的查找(这个容易理解)
- 二叉树的线索化及其前驱后继查找
- 分析线索二叉树的前驱、后继求法
- 求二叉搜索树任一节点的前驱后继节点
- 关于二叉树遍历的前驱后继规则
- 查找线索二叉树的前驱和后继
- [数据结构] 二叉搜索树 前驱和后继的经验总结
- win7下搭建cocos2d-x环境
- Asp.net MVC 4 Html帮助类
- 二进制-hdu-4759-Poker Shuffle
- 锐捷面试 2014--武汉
- Asp.net MVC 4 Html帮助类 II
- 排序二叉树BST的基本操作(2)前驱,后继,删除
- asp.net 在使用母版页的子页面cs后台代码中控制母版页中的登录控件显示
- 《JAVA与模式》之适配器模式
- 常用的oracle的sql函数
- 黑马程序员_基础加强笔记_静态导入
- PHP校验ISBN码的函数
- CF202 Div 1 题解
- java中堆和堆栈的区别
- mapreduce之组件,join,排序原理