当前位置:   article > 正文

C语言实现 二叉排序树 的插入、删除、查找(详细图解)_二叉排序树的删除

二叉排序树的删除

1 二叉排序树定义

如果它的左子树不为空,那么左子树上所有节点的值均小于它的根节点的值

如果它的右子树不为空,那么右子树上所有节点的值均大于它的根节点的值

根节点的左子树和右子树均是二叉排序树

二叉排序树可能退化为链表,所以有平衡二叉树的概念;二叉排序树的中序遍历是从小到大有序的)

2 二叉排序树结构体及节点创建函数

  1. typedef struct Tree //二叉树
  2. {
  3. int data; //数据域
  4. struct Tree *left; //左子节点指针
  5. struct Tree *right; //右子节点指针
  6. } Tree;
  7. Tree *createBinarySortTreeNode(int data)
  8. {
  9. Tree *node = (Tree *)malloc(sizeof(Tree));
  10. node->data = data;
  11. node->left = NULL;
  12. node->right = NULL;
  13. return node;
  14. }

3 二叉排序树的节点插入

思路:将要插入节点的data与根节点data比较,如果小于根节点data,则插入根节点的左子树;如果大于根节点的data,则插入根节点的右子树;

插入子树相当于插入一个更小的树,因此可以用递归方法实现,直到找到没有子树的节点,将新节点插到其下面,成为叶子节点。

  1. void insertBinarySortTreeNode(Tree *dataNode, Tree **root) //二叉排序树插入节点,因为根节点可能改变,所以传二级指针
  2. {
  3. if (*root == NULL || dataNode == NULL)
  4. {
  5. *root = dataNode;
  6. return;
  7. }
  8. if (dataNode->data > (*root)->data)//如果插入节点大于原节点的data,插入节点需要放在root的右子树
  9. {
  10. if ((*root)->right == NULL)//找到插入位置
  11. {
  12. (*root)->right = dataNode;
  13. return;
  14. }
  15. if ((*root)->right)
  16. insertBinarySortTreeNode(dataNode, &(*root)->right);//递归找dataNode的插入位置
  17. }
  18. if (dataNode->data <= (*root)->data)//如果去掉等于号,表示不插入相同data的节点
  19. {
  20. if ((*root)->left == NULL)//找到插入位置
  21. {
  22. (*root)->left = dataNode;
  23. return;
  24. }
  25. if ((*root)->left)
  26. insertBinarySortTreeNode(dataNode, &(*root)->left); //递归找dataNode的插入位置
  27. }
  28. }

4 二叉排序树最大键值节点获取

  • 思路:二叉排序树由于右子树节点键值均大于根节点键值,因此需要从右子树的根节点再开始查找.......直至找到最后一个右子树的右子节点,即为最大键值对应的节点。可用递归实现该过程
  1. Tree *maxValueOfBinaryTree(Tree *root)
  2. {
  3. if (root == NULL)//空指针判断
  4. return NULL;
  5. Tree *pointer = root;
  6. while (pointer->right)//跳出循环后,pointer指向最后一个右子节点
  7. pointer = pointer->right;
  8. return pointer;
  9. }

5 二叉排序树最小键值节点获取(思路同上,不再赘述)

  1. Tree *minValueOfBinaryTree(Tree *root)
  2. {
  3. if (root == NULL)
  4. return NULL;
  5. Tree *pointer = root;
  6. while (pointer->left)
  7. pointer = pointer->left;
  8. return pointer;
  9. }

6 二叉排序树查找指定节点的父节点

  1. Tree *parentNodeOfBinaryTreeNode(Tree *dataNode, Tree *root) //获取dataNode节点的父节点
  2. {
  3. if (dataNode == NULL || root == NULL || root == dataNode) //空指针判断,以及root自身无父节点
  4. return NULL;
  5. Tree *pointer = root;
  6. Tree *parentNode = pointer;
  7. while (pointer != NULL && pointer->data != dataNode->data)
  8. {
  9. parentNode = pointer;
  10. if (dataNode->data > pointer->data)
  11. pointer = pointer->right;
  12. else
  13. pointer = pointer->left;
  14. } //每一次循环后parentNode总是pointer的父节点
  15. //循环跳出后,要么找到了dataNode,要么pointer为NULL了
  16. if (pointer == NULL)
  17. {
  18. printf("节点dataNode不存在\n");
  19. return NULL;
  20. }
  21. return parentNode;
  22. }

7 二叉排序树删除节点

  • 7.1 如果删除的节点是叶子节点(没有子结点),把删除节点置为NULL即可(删除节点的父节点指向NULL);特例:如果删除节点是root节点,则root置为NULL即可
  • 7.2 如果删除的节点有一个子结点,把删除节点的父节点指向删除节点的子结点即可。特例:如果删除节点是root节点,即可认为删除链表的头节点,把第二个节点当作表头即可。
  • 7.3 如果删除的节点有两个子结点,为保证二叉排序树的有序性,需要找到与删除节点键值最接近的两个节点,由二叉树的特性知,这两个节点位于删除节点左子树的最右节点,右子树的最左节点。然后将删除节点的父节点指向其中任意一个(例如左子树最右节点,简称替代节点),替代节点的右指针指向删除节点的右子树;替代节点的父节点如果不是删除节点时,替代节点的左指针指向删除节点的左子树,替代节点的父节点指向替代节点的左子树(替代节点处于最右时没有左子树); 特例1:删除的节点为root时 特例2:替代节点的父节点是删除节点时,可见代码分析
  • 最后释放删除节点的空间即可

 代码如下

  1. void deleteBinarySortTreeNode(Tree *deleteNode, Tree **root) //删除二叉树中的某一个节点
  2. {
  3. Tree *parentOfDeleteNode = parentNodeOfBinaryTreeNode(deleteNode, *root); //删除节点的父节点
  4. if (deleteNode == NULL || root == NULL) //空指针判断
  5. return;
  6. if (deleteNode != *root && parentOfDeleteNode == NULL) //删除节点不是root,parentOfDeleteNode==NULL说明没有找到deleteNode或者树的root节点为NULL,直接结束;
  7. return;
  8. if (deleteNode->left == NULL && deleteNode->right == NULL) // case:1 删除节点为叶子节点的情况
  9. {
  10. if (*root == deleteNode) //删除的节点是root节点
  11. {
  12. *root = NULL;
  13. return;
  14. }
  15. if (parentOfDeleteNode->left == deleteNode)
  16. parentOfDeleteNode->left = NULL;
  17. if (parentOfDeleteNode->right == deleteNode)
  18. parentOfDeleteNode->right = NULL;
  19. }
  20. else if (deleteNode->left == NULL || deleteNode->right == NULL) // case:2 删除节点只有左子树或右子树,其中之一
  21. {
  22. if (*root == deleteNode)
  23. {
  24. if ((*root)->left != NULL) //删除节点为root节点,且root节点只有左子树
  25. (*root) = (*root)->left;
  26. else if ((*root)->right != NULL)
  27. (*root) = (*root)->right; //删除节点为root节点,且root节点只有右子树
  28. }
  29. else if (deleteNode->left != NULL) //删除节点只有左子树
  30. {
  31. if (parentOfDeleteNode->left == deleteNode) //删除节点是父节点的左子节点,且删除节点只有左子树
  32. parentOfDeleteNode->left = deleteNode->left; //把父节点的left指向deleteNode的左子节点
  33. if (parentOfDeleteNode->right == deleteNode)
  34. parentOfDeleteNode->right = deleteNode->left;
  35. }
  36. else if (deleteNode->right != NULL)
  37. {
  38. if (parentOfDeleteNode->left == deleteNode) //
  39. parentOfDeleteNode->left = deleteNode->right;
  40. if (parentOfDeleteNode->right == deleteNode)
  41. parentOfDeleteNode->right = deleteNode->right;
  42. }
  43. }
  44. else if (deleteNode->left != NULL || deleteNode->right != NULL) // case:3 删除节点有左子树和右子树
  45. {
  46. Tree *replaceNode = maxValueOfBinaryTree(deleteNode->left);
  47. //找到删除节点的左子树的最右节点(对应左子树的最大键值)作为替代节点,替代节点的键值与删除节点的键值是相邻的,
  48. Tree *parentOfReplaceNode = parentNodeOfBinaryTreeNode(replaceNode, *root); //获取替代节点的父节点
  49. if (*root == deleteNode)
  50. {
  51. parentOfReplaceNode->right = replaceNode->left;
  52. replaceNode->left = (*root)->left;
  53. replaceNode->right = (*root)->right;
  54. (*root) = replaceNode;
  55. }
  56. else if (parentOfDeleteNode->left == deleteNode) //删除节点是其父节点的左子节点
  57. {
  58. parentOfDeleteNode->left = replaceNode; //删除节点的父节点left指向替代节点
  59. replaceNode->left = deleteNode->left;
  60. if (parentOfReplaceNode != deleteNode)
  61. {
  62. replaceNode->right = deleteNode->right;
  63. //替代节点右子树指向删除节点右子树(如果替代节点父节点就是删除节点,deleteNode->right就是该替代节点,造成后面子树丢失;parentOfReplaceNode->right也没有意义)
  64. parentOfReplaceNode->right = replaceNode->left;
  65. }
  66. else if (parentOfReplaceNode == deleteNode)
  67. replaceNode->right = deleteNode->right->left; //替换节点的右子树指向了替换节点的左子树,看树图很容易理解
  68. }
  69. else if (parentOfDeleteNode->right == deleteNode) //删除节点是父节点的右子节点
  70. {
  71. parentOfDeleteNode->right = replaceNode; //删除节点的父节点right指向左子树最大键值对应节点
  72. replaceNode->right = deleteNode->right;
  73. if (parentOfReplaceNode != deleteNode)
  74. {
  75. replaceNode->left = replaceNode->left;
  76. parentOfReplaceNode->right = replaceNode->left;
  77. }
  78. else if (parentOfReplaceNode == deleteNode)
  79. replaceNode->left = replaceNode->left->left;
  80. }
  81. }
  82. free(deleteNode);
  83. }

 8 中序遍历代码以及查找指定节点代码

  1. Tree *searchTreeNode(Tree *root, int value) //搜索二叉排序树含指定数据的节点
  2. {
  3. if (root == NULL)
  4. return NULL;
  5. if (root->data > value)
  6. return searchTreeNode(root->left, value);
  7. if (root->data < value)
  8. return searchTreeNode(root->right, value);
  9. else
  10. return root;
  11. }
  12. void inOrderList(Tree *root)//中序遍历
  13. {
  14. if (root == NULL)
  15. return;
  16. inOrderList(root->left);
  17. printf("%d->", root->data);
  18. inOrderList(root->right);
  19. }

9 函数测试与运行结果

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int main()
  5. {
  6. int array[] = {2, 6, 9, 8, 12, 3, 5, 4, 0, -66, 1, -88};
  7. Tree root = {2, NULL, NULL};
  8. Tree *pointer = &root;
  9. for (int i = 1; i < sizeof(array) / sizeof(array[0]); i++)
  10. {
  11. Tree *node = createBinarySortTreeNode(array[i]);
  12. insertBinarySortTreeNode(node, &pointer);//插入节点
  13. }
  14. inOrderList(&root); //二叉排序树中序遍历
  15. puts("");
  16. Tree *maxNode = maxValueOfBinaryTree(&root);//最大键值节点查找
  17. printf("the maxValueNode:{data:%d left:%p right:%p}\n", maxNode->data, maxNode->left, maxNode->right);
  18. Tree *minNode = minValueOfBinaryTree(&root);//最小键值节点查找
  19. printf("the minValueNode:{data:%d left:%p right:%p}\n", minNode->data, minNode->left, minNode->right);
  20. Tree *searchNode = searchTreeNode(&root, 6);//查找指定节点
  21. printf("searchNode->{data:%d left:%p right:%p}\n", searchNode->data, searchNode->left, searchNode->right);
  22. Tree *parentNode = parentNodeOfBinaryTreeNode(searchNode, &root);//指定节点的父节点查找
  23. printf("parentNode->{data:%d left:%p right:%p} searchNode:%p\n", parentNode->data, parentNode->left, parentNode->right, searchNode);
  24. //如果测试删除root节点,需要把上行printf里面的parentNode的data去掉,因为是NULL,无法解引用
  25. Tree *pointer2 = &root;
  26. deleteBinarySortTreeNode(searchNode, &pointer2);//删除指定节点
  27. printf("删除节点searchNode节点后: ");
  28. inOrderList(pointer2);//中序遍历
  29. return 0;
  30. }

 运行结果如下:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/709605
推荐阅读
相关标签
  

闽ICP备14008679号