二叉搜索树

二叉搜索树定义

对于任意结点,其关键字不小于其左子树的最大关键字,不大于其右子树中的最小关键字。

示例:

BST_Demo.svg

  • 二叉搜索树构建 ```c / 31_二叉树——构建二叉查找树/ Status binSerchAddElem_T(BinaryTree& cur, BiTreeNodeElementType elem) { // 方法是向已有二叉搜索树中加入元素,若当前二叉树为空,则构建新的二叉树 // 结点为空时创建结点并设置值,从父节点迭代到左孩子或右孩子时执行 if (!cur) {

    1. cur = (BinaryTree)malloc(sizeof(BinaryTreeNode));
    2. if (!cur)
    3. {
    4. printf("构建失败!");
    5. return ERROR;
    6. }
    7. cur->data = elem;
    8. cur->left = NULL;
    9. cur->right = NULL;
    10. cur->ltag = false;
    11. cur->rtag = false;
    12. return OK;

    } // 元素小于当前结点值,创建左结点 if (elem < cur->data) {

    1. if (!binSerchAddElem_T(cur->left, elem))
    2. {
    3. return ERROR;
    4. }

    } // 元素大于等于当前结点值,创建右结点 else {

    1. if (!binSerchAddElem_T(cur->right, elem))
    2. {
    3. return ERROR;
    4. }

    }

    return OK; }

/ 32_二叉树——构建二叉查找树/ void buildBinarySearchTree(BinaryTree& bst, BiTreeNodeElementType arr, int length) { // 批量加元素即可 for (int i = 0; i < length; i++) { binSerchAddElem_T(bst, (arr + i)); } }

  1. - 概念
  2. - 或为空树。
  3. - 左子树不空,左子树上所有结点值均小于根结点值;
  4. - 右子树不空,右子树上所有结点值均大于根结点值。
  5. - 构建过程。
  6. - 顺着二叉搜索树,逐一于当前结点进行比较;
  7. - 若小于当前结点的值,则与其左孩子根结点值比较;
  8. - 否则与右孩子根结点值比较。
  9. - 重复比较过程,直到当前结点为空。创建结点,将元素值赋值到新结点中。
  10. - 二叉搜索树删除单个结点
  11. - 性质不变:删除某个结点后,仍然保持二叉搜索树的结构特性(**中序遍历为非递减序列**)。
  12. - 关键影响因素 => BST中**待删除结点的位置**。
  13. - 删除操作的关键:对不同位置结点的删除操作处理,如何**保证**删除后的**性质不变性**。
  14. - 根据对不同情况的处理(主要是**根据后继结点**的处理思路),分为以下几种情况(定义**待删除结点z**,其**左孩子left**, **右孩子right**,**中序后继结点Y**,**Y的右孩子为X**)
  15. - z无左子树,右子树可有可无(00, 01)<br />![BST_Delete_1.svg](https://cdn.nlark.com/yuque/0/2021/svg/21873585/1624244711510-14c663c5-2eff-4e8a-85f1-e233bc1529f2.svg#align=left&display=inline&height=316&margin=%5Bobject%20Object%5D&name=BST_Delete_1.svg&originHeight=316&originWidth=679&size=10398&status=done&style=none&width=679)
  16. - 直接将**右孩子替换Z的位置**
  17. - z有且仅有左孩子(10)<br />![BST_Delete_2.svg](https://cdn.nlark.com/yuque/0/2021/svg/21873585/1624244727466-935f2c6f-af01-4bb9-a2f5-da6ecfdaf3ce.svg#align=left&display=inline&height=326&margin=%5Bobject%20Object%5D&name=BST_Delete_2.svg&originHeight=326&originWidth=766&size=10382&status=done&style=none&width=766)
  18. - 直接将**左孩子替换Z的位置**
  19. - z有两个孩子(11),则需要先找到Z的中序后继结点Y
  20. - Z的右孩子根结点无左子树,则Y == Z->right<br />![BST_Delete_3.svg](https://cdn.nlark.com/yuque/0/2021/svg/21873585/1624244733786-ffc7390b-9277-4208-a497-d6243e6aa6eb.svg#align=left&display=inline&height=476&margin=%5Bobject%20Object%5D&name=BST_Delete_3.svg&originHeight=476&originWidth=1086&size=16675&status=done&style=none&width=1086)
  21. - Y替换Z的位置,并且**左指针**指向Z的左孩子
  22. - Z的右孩子根结点有左子树,则后继Y在其左子树中。<br />![BST_Delete_4.svg](https://cdn.nlark.com/yuque/0/2021/svg/21873585/1624244751232-48430e58-dbda-4ff1-97ac-574873f47b7c.svg#align=left&display=inline&height=696&margin=%5Bobject%20Object%5D&name=BST_Delete_4.svg&originHeight=696&originWidth=1815&size=31934&status=done&style=none&width=1815)
  23. - 首先用**Y的右子树X**的位置替换Y的位置;
  24. - 用结点**Y的右指针指向right**;
  25. - Y的**左指针指向left**,并**替换Z的位置**。
  26. - 注意事项
  27. - 替换位置,即是需要找到其父结点指向该结点的指针,父结点可能通过**左指针或右指针**指向该结点;
  28. - Z的中序后继结点Y的操作,关键在于Z的**右子树根结点是否有左子树**。
  29. - 代码实现
  30. ```c
  31. /* 33_二叉树——二叉搜索树删除指定结点*/
  32. Status deleteBiSearchElem_T(BinaryTree& bst, BinaryTree& toDel)
  33. {
  34. // 先找到其父结点
  35. BinaryTree parent = parentBiNode_T(bst, toDel);
  36. // 若父结点不存在,则当前即为根结点,直接删除结点并置空
  37. if (!parent)
  38. {
  39. bst = NULL;
  40. delete toDel;
  41. toDel = NULL;
  42. return OK;
  43. }
  44. // 四种情况
  45. // 1. 待删除结点z无左孩子,用右孩子替换
  46. if (!toDel->left)
  47. {
  48. // 当前结点与父节点的关系
  49. if (parent->left == toDel) {
  50. parent->left = toDel->right;
  51. }
  52. else
  53. {
  54. parent->right = toDel->right;
  55. }
  56. delete toDel;
  57. toDel = NULL;
  58. return OK;
  59. }
  60. // 2. 待删除结点z仅有左孩子
  61. else if (toDel->left && !toDel->right)
  62. {
  63. if (parent->left == toDel)
  64. {
  65. parent->left = toDel->left;
  66. }
  67. else
  68. {
  69. parent->right = toDel->left;
  70. }
  71. return OK;
  72. }
  73. // 3. 待删除结点z有两个孩子
  74. else
  75. {
  76. // 待删除结点的后继
  77. BinaryTree post = inorderPost_T(bst, toDel);
  78. // 无左孩子,右子树根结点即是后继
  79. if (post == toDel->right)
  80. {
  81. // 左孩子先替换为待删除结点的左孩子
  82. post->left = toDel->left;
  83. // 将后继替换待删除
  84. if (parent->left == toDel)
  85. {
  86. parent->left = post;
  87. }
  88. else
  89. {
  90. parent->right = post;
  91. }
  92. }
  93. // 否则后继在其z->right的左子树中
  94. else
  95. {
  96. // 后继的父结点p
  97. BinaryTree pParent = parentBiNode_T(bst, post);
  98. if (pParent->left == post)
  99. {
  100. pParent->left = post->right;
  101. }
  102. else
  103. {
  104. pParent->right = post->right;
  105. }
  106. // 将后继替换待删除结点,并连接待删除的右子树
  107. if (parent->left == toDel)
  108. {
  109. parent->left = post;
  110. }
  111. else
  112. {
  113. parent->right = post;
  114. }
  115. post->left = toDel->left;
  116. post->right = toDel->right;
  117. delete toDel;
  118. toDel = NULL;
  119. }
  120. return OK;
  121. }
  122. }
  123. /* 34_二叉树——查找二叉树中某个结点中序后继,找不到返回NULL*/
  124. BinaryTree inorderPost_T(BinaryTree bt, BinaryTree cur)
  125. {
  126. if (!bt || !cur)
  127. {
  128. return NULL;
  129. }
  130. // 1. 有右子树,后继在其右子树中
  131. BinaryTree post = cur->right;
  132. if (post)
  133. {
  134. while (post->left)
  135. {
  136. post = post->left;
  137. }
  138. return post;
  139. }
  140. // 2. 无右子树
  141. BinaryTree parent = NULL;
  142. BinaryTree p = cur;
  143. // 找到当前为父结点左孩子的结点
  144. do
  145. {
  146. parent = parentBiNode_T(bt, p);
  147. p = parent;
  148. } while (parent && parent->left != p);
  149. return parent;
  150. }