【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

3 普通节点的删除

3.1 删除的节点没有左子树,也没有右子树

测试用例1: 删除节点6

/*
*
*         10          ======>     10
*        /  \                      \
*      6     15                     15
*
*/static void test8()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 6));assert(6 == pTreeNode->left_child->data);assert(TRUE == insert_node_into_tree(&pTreeNode, 15));assert(TRUE == delete_node_from_tree(&pTreeNode, 6));assert(NULL == pTreeNode->left_child);free(pTreeNode->right_child);free(pTreeNode);
}

测试用例2: 删除节点15

/*
*
*         10          ======>     10
*        /  \                    /
*      6     15                 6
*
*/static void test9()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 6));assert(TRUE == insert_node_into_tree(&pTreeNode, 15));assert(15 == pTreeNode->right_child->data);assert(TRUE == delete_node_from_tree(&pTreeNode, 15));assert(NULL == pTreeNode->right_child);free(pTreeNode->right_child);free(pTreeNode);
}

那么代码应该怎么编写呢?

STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{TREE_NODE* pLeftMax;if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = NULL;elsepTreeNode->parent->right_child = NULL;}free(pTreeNode);return TRUE;
}

3.2 删除的节点有左子树,没有右子树

测试用例1: 测试节点6

/*
*
*         10          ======>     10
*        /                      /
*      6                      3
*     /
*    3
*/static void test10()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 6));assert(TRUE == insert_node_into_tree(&pTreeNode, 3));assert(TRUE == delete_node_from_tree(&pTreeNode, 6));assert(3 == pTreeNode->left_child->data);assert(pTreeNode = pTreeNode->left_child->parent);free(pTreeNode->left_child);free(pTreeNode);
}

测试用例2: 删除节点15

/*
*
*         10          ======>     10
*           \                       \
*           15                       12
*            /
*           12
*/static void test11()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 15));assert(TRUE == insert_node_into_tree(&pTreeNode, 12));assert(TRUE == delete_node_from_tree(&pTreeNode, 15));assert(12 == pTreeNode->right_child->data);assert(pTreeNode = pTreeNode->right_child->parent);free(pTreeNode->right_child);free(pTreeNode);
}

添加左子树不为空,右子树为空的处理代码,如下所示:

STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{TREE_NODE* pLeftMax;if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = NULL;elsepTreeNode->parent->right_child = NULL;}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){pTreeNode->left_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->left_child;elsepTreeNode->parent->right_child = pTreeNode->left_child;}free(pTreeNode);return TRUE;
}

3.3 删除的节点左子树为空,右子树节点不为空

测试用例1: 删除数据6

/*
*
*         10          ======>    10
*        /                     /
*      6                      8
*       \
*        8
*/static void test12()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 6));assert(TRUE == insert_node_into_tree(&pTreeNode, 8));assert(TRUE == delete_node_from_tree(&pTreeNode, 6));assert(8 == pTreeNode->left_child->data);assert(pTreeNode = pTreeNode->left_child->parent);free(pTreeNode->left_child);free(pTreeNode);
}

测试用例2: 删除数据15

/*
*
*        10          ======>    10
*          \                      \
*           15                     20
*             \
*             20
*/static void test13()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 15));assert(TRUE == insert_node_into_tree(&pTreeNode, 20));assert(TRUE == delete_node_from_tree(&pTreeNode, 15));assert(20 == pTreeNode->right_child->data);assert(pTreeNode = pTreeNode->right_child->parent);free(pTreeNode->right_child);free(pTreeNode);
}

添加左子树为空,右子树不为空的处理情形。代码如下:

STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{TREE_NODE* pLeftMax;if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = NULL;elsepTreeNode->parent->right_child = NULL;}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){pTreeNode->left_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->left_child;elsepTreeNode->parent->right_child = pTreeNode->left_child;}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){pTreeNode->right_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->right_child;elsepTreeNode->parent->right_child = pTreeNode->right_child;}free(pTreeNode);return TRUE;
}

3.4 删除的节点左右子树均不为空,不过又要分为两种情形:

1) 左节点是删除节点左侧的最大节点 (删除节点6)

/*
*
*         10          ======>    10
*        /                     /
*      6                      5
*    /  \                      \
*   5    8                      8
*/static void test14()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 6));assert(TRUE == insert_node_into_tree(&pTreeNode, 5));assert(TRUE == insert_node_into_tree(&pTreeNode, 8));assert(TRUE == delete_node_from_tree(&pTreeNode, 6));assert(5 == pTreeNode->left_child->data);assert(pTreeNode = pTreeNode->left_child->parent);assert( 8 == pTreeNode->left_child->right_child->data);assert(pTreeNode->left_child = pTreeNode->left_child->right_child->parent);free(pTreeNode->left_child->right_child);free(pTreeNode->left_child);free(pTreeNode);
}

2) 左节点不是删除节点左侧的最大节点(删除节点5)

/*
*
*         10          ======>    10
*        /                     /
*       5                      4
*      / \                    / \
*     2   6                  2   6
*      \
*       4
*/static void test15()
{TREE_NODE* pTreeNode = NULL;assert(TRUE == insert_node_into_tree(&pTreeNode, 10));assert(TRUE == insert_node_into_tree(&pTreeNode, 5));assert(TRUE == insert_node_into_tree(&pTreeNode, 2));assert(TRUE == insert_node_into_tree(&pTreeNode, 4));assert(TRUE == insert_node_into_tree(&pTreeNode, 6));assert(TRUE == delete_node_from_tree(&pTreeNode, 5));assert(4 == pTreeNode->left_child->data);assert(NULL == pTreeNode->left_child->left_child->right_child);free(pTreeNode->left_child->left_child);free(pTreeNode->left_child->right_child);free(pTreeNode->left_child);free(pTreeNode);
}

那么针对这两种类型,我们的代码究竟应该怎么处理呢?

STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{TREE_NODE* pLeftMax;if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = NULL;elsepTreeNode->parent->right_child = NULL;}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){pTreeNode->left_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->left_child;elsepTreeNode->parent->right_child = pTreeNode->left_child;}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){pTreeNode->right_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->right_child;elsepTreeNode->parent->right_child = pTreeNode->right_child;}else{pLeftMax = find_max_node(pTreeNode->left_child);if(pLeftMax == pTreeNode->left_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->left_child;elsepTreeNode->parent->right_child = pTreeNode->left_child;pTreeNode->left_child->parent = pTreeNode->parent;pTreeNode->left_child->right_child = pTreeNode->right_child;pTreeNode->right_child->parent = pTreeNode-> left_child;}else{pTreeNode->data = pLeftMax->data;pLeftMax->parent->right_child = pLeftMax->left_child;pLeftMax->left_child->parent = pLeftMax->parent;pTreeNode = pLeftMax;}}free(pTreeNode);return TRUE;
}

结束总结:

上面的过程记录了我们的代码是怎么一步一步走过来的。最后我们给出一份完整的节点删除代码:

STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{TREE_NODE* pLeftMax;if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = NULL;elsepTreeNode->parent->right_child = NULL;}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){pTreeNode->left_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->left_child;elsepTreeNode->parent->right_child = pTreeNode->left_child;}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){pTreeNode->right_child->parent = pTreeNode->parent;if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->right_child;elsepTreeNode->parent->right_child = pTreeNode->right_child;}else{pLeftMax = find_max_node(pTreeNode->left_child);if(pLeftMax == pTreeNode->left_child){if(pTreeNode == pTreeNode->parent->left_child)pTreeNode->parent->left_child = pTreeNode->left_child;elsepTreeNode->parent->right_child = pTreeNode->left_child;pTreeNode->left_child->parent = pTreeNode->parent;pTreeNode->left_child->right_child = pTreeNode->right_child;pTreeNode->right_child->parent = pTreeNode-> left_child;}else{pTreeNode->data = pLeftMax->data;pLeftMax->parent->right_child = pLeftMax->left_child;pLeftMax->left_child->parent = pLeftMax->parent;           pTreeNode = pLeftMax;}}free(pTreeNode);return TRUE;
}STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{TREE_NODE* pTreeNode;TREE_NODE* pLeftMax;if(NULL == ppTreeNode || NULL == *ppTreeNode)return FALSE;pTreeNode = find_data_in_tree_node(*ppTreeNode, data);if(NULL == pTreeNode)return FALSE;if(*ppTreeNode == pTreeNode){if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){*ppTreeNode = NULL;}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){*ppTreeNode = pTreeNode->left_child;pTreeNode->left_child->parent = NULL;}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){*ppTreeNode = pTreeNode->right_child;pTreeNode->right_child->parent = NULL;}else{pLeftMax = find_max_node(pTreeNode->left_child);if(pLeftMax == pTreeNode->left_child){*ppTreeNode = pTreeNode->left_child;(*ppTreeNode)->right_child = pTreeNode->right_child;(*ppTreeNode)->right_child->parent = *ppTreeNode;(*ppTreeNode)->parent = NULL;}else{pTreeNode->data = pLeftMax->data;pLeftMax->parent->right_child = pLeftMax->left_child;pLeftMax->left_child->parent = pLeftMax->parent;pTreeNode = pLeftMax;}}free(pTreeNode);return TRUE;}return _delete_node_from_tree(pTreeNode);
}

一步一步写算法(之排序二叉树删除-3)相关推荐

  1. 归并有效排序算法matlab,科学网—[用MATLAB写算法]之排序算法2)归并排序merge sort - 徐勇刚的博文...

    归并排序(merge sort)是一种利用分治策略(divide and conquer)进行排序的算法,算法复杂度为 $\Theta (nlog_{2}n)$ . filename: merge_s ...

  2. 一步一步写算法(之排序二叉树删除-1)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 相比较节点的添加,平衡二叉树的删除要复杂一些.因为在删除的过程中,你要考虑到不同的情况,针对每 ...

  3. 一步一图一代码之排序二叉树

    作者:禅楼望月(http://www.cnblogs.com/yaoyinglong/) 属性: ①若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值. ②若它的右子树不为空,则右子树上所 ...

  4. 一步一步写算法(之排序二叉树删除-2)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 2.4 删除节点的左右子树都存在,此时又会分成两种情形 1)左节点是当前左子树的最大节点,此时 ...

  5. 一步一步写算法(之二叉树深度遍历)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 深度遍历是软件开发中经常遇到的遍历方法.常用的遍历方法主要有下面三种:(1)前序遍历:(2)中 ...

  6. 一步一步写算法(之二叉树广度遍历)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在二叉树的遍历当中,有一种遍历方法是不常见的,那就是广度遍历.和其他三种遍历方法不同,二叉树的 ...

  7. 二叉树 排序二叉树-可以通过中序遍历得到排序的数据 二叉排序树时间复杂度O(logn),...

    二叉树是一种非常重要的数据结构,它同时具有数组和链表各自的特点:它可以像数组一样快速查找,也可以像链表一样快速添加.但是他也有自己的缺点:删除操作复杂. 虽然二叉排序树的最坏效率是O(n),但它支持动 ...

  8. 一步一步写算法(之排序二叉树线索化)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们谈到了排序二叉树,还没有熟悉的同学可以看一下这个,二叉树基本操作.二叉树插入.二叉树删 ...

  9. 一步一步写算法(之排序二叉树)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们讲过双向链表的数据结构.每一个循环节点有两个指针,一个指向前面一个节点,一个指向后继节 ...

最新文章

  1. Linux 设备驱动中的并发控制 小感
  2. JFreeChart的简单图表的制作------柱形图
  3. 二分查找树性能分析(Binary Search Tree Performance Analysis)
  4. 全球及中国电动自行车零件和配件行业运营状况及未来发展趋势预测报告2022年版
  5. 笨小猴pascal题解
  6. VTK:vtkBillboardTextActor3D用法实战
  7. 90后码农可以拯救互联网吗?
  8. Linux的实际操作:Linux磁盘分区 、挂载
  9. VSS(Visual SourceSafe) 代码管理器 使用技巧---快速登录
  10. 常用加密算法的Java实现(一)
  11. OpenCV中的内存泄露问题(cvLoadImage,cvCloneImage)【转】
  12. 【TJOI2016】【bzoj4552】排序(二分答案+线段树01排序)
  13. OK335xS psplash Screen 移植
  14. 脚本——web_custom_request函数详解
  15. 值得收藏:一份非常完整的 MySQL 规范指南
  16. Kafka多数据中心部署灾备三要素
  17. Free Dwg Viewer-免费的AutoCAD DWG/DWF/DXF文件查看器
  18. 虚拟机上键盘右边的数字小键盘为什么不能使用
  19. 银河麒麟桌面操作系统【telnet配置】
  20. python运用ico图标_使用python将图片格式转换为ico格式的示例

热门文章

  1. Centos VIM 配置
  2. internet explorer 无法打开 Internet站点 已中止操作
  3. VDI序曲八 网关与VDI发布
  4. 经常用到的一些小病的预防的治疗
  5. 初始化一个指针的方法
  6. Web Server 和 HTTP 协议
  7. 深入Asyncio(八)异步迭代器
  8. JQuery实现轮播图及其原理
  9. 内存管理2-set方法的内存管理
  10. VC 写 TXT 文件分割器 附代码