二叉搜索树
二叉搜索树定义
对于任意结点,其关键字不小于其左子树的最大关键字,不大于其右子树中的最小关键字。
示例:
二叉搜索树构建 ```c / 31_二叉树——构建二叉查找树/ Status binSerchAddElem_T(BinaryTree& cur, BiTreeNodeElementType elem) { // 方法是向已有二叉搜索树中加入元素,若当前二叉树为空,则构建新的二叉树 // 结点为空时创建结点并设置值,从父节点迭代到左孩子或右孩子时执行 if (!cur) {
cur = (BinaryTree)malloc(sizeof(BinaryTreeNode));if (!cur){printf("构建失败!");return ERROR;}cur->data = elem;cur->left = NULL;cur->right = NULL;cur->ltag = false;cur->rtag = false;return OK;
} // 元素小于当前结点值,创建左结点 if (elem < cur->data) {
if (!binSerchAddElem_T(cur->left, elem)){return ERROR;}
} // 元素大于等于当前结点值,创建右结点 else {
if (!binSerchAddElem_T(cur->right, elem)){return ERROR;}
}
return OK; }
/ 32_二叉树——构建二叉查找树/ void buildBinarySearchTree(BinaryTree& bst, BiTreeNodeElementType arr, int length) { // 批量加元素即可 for (int i = 0; i < length; i++) { binSerchAddElem_T(bst, (arr + i)); } }
- 概念- 或为空树。- 左子树不空,左子树上所有结点值均小于根结点值;- 右子树不空,右子树上所有结点值均大于根结点值。- 构建过程。- 顺着二叉搜索树,逐一于当前结点进行比较;- 若小于当前结点的值,则与其左孩子根结点值比较;- 否则与右孩子根结点值比较。- 重复比较过程,直到当前结点为空。创建结点,将元素值赋值到新结点中。- 二叉搜索树删除单个结点- 性质不变:删除某个结点后,仍然保持二叉搜索树的结构特性(**中序遍历为非递减序列**)。- 关键影响因素 => 在BST中**待删除结点的位置**。- 删除操作的关键:对不同位置结点的删除操作处理,如何**保证**删除后的**性质不变性**。- 根据对不同情况的处理(主要是**根据后继结点**的处理思路),分为以下几种情况(定义**待删除结点z**,其**左孩子left**, **右孩子right**,**中序后继结点Y**,**Y的右孩子为X**)- z无左子树,右子树可有可无(00, 01)<br />- 直接将**右孩子替换Z的位置**- z有且仅有左孩子(10)<br />- 直接将**左孩子替换Z的位置**- z有两个孩子(11),则需要先找到Z的中序后继结点Y- Z的右孩子根结点无左子树,则Y == Z->right<br />- Y替换Z的位置,并且**左指针**指向Z的左孩子- Z的右孩子根结点有左子树,则后继Y在其左子树中。<br />- 首先用**Y的右子树X**的位置替换Y的位置;- 用结点**Y的右指针指向right**;- Y的**左指针指向left**,并**替换Z的位置**。- 注意事项- 替换位置,即是需要找到其父结点指向该结点的指针,父结点可能通过**左指针或右指针**指向该结点;- 找Z的中序后继结点Y的操作,关键在于Z的**右子树根结点是否有左子树**。- 代码实现```c/* 33_二叉树——二叉搜索树删除指定结点*/Status deleteBiSearchElem_T(BinaryTree& bst, BinaryTree& toDel){// 先找到其父结点BinaryTree parent = parentBiNode_T(bst, toDel);// 若父结点不存在,则当前即为根结点,直接删除结点并置空if (!parent){bst = NULL;delete toDel;toDel = NULL;return OK;}// 四种情况// 1. 待删除结点z无左孩子,用右孩子替换if (!toDel->left){// 当前结点与父节点的关系if (parent->left == toDel) {parent->left = toDel->right;}else{parent->right = toDel->right;}delete toDel;toDel = NULL;return OK;}// 2. 待删除结点z仅有左孩子else if (toDel->left && !toDel->right){if (parent->left == toDel){parent->left = toDel->left;}else{parent->right = toDel->left;}return OK;}// 3. 待删除结点z有两个孩子else{// 待删除结点的后继BinaryTree post = inorderPost_T(bst, toDel);// 无左孩子,右子树根结点即是后继if (post == toDel->right){// 左孩子先替换为待删除结点的左孩子post->left = toDel->left;// 将后继替换待删除if (parent->left == toDel){parent->left = post;}else{parent->right = post;}}// 否则后继在其z->right的左子树中else{// 后继的父结点pBinaryTree pParent = parentBiNode_T(bst, post);if (pParent->left == post){pParent->left = post->right;}else{pParent->right = post->right;}// 将后继替换待删除结点,并连接待删除的右子树if (parent->left == toDel){parent->left = post;}else{parent->right = post;}post->left = toDel->left;post->right = toDel->right;delete toDel;toDel = NULL;}return OK;}}/* 34_二叉树——查找二叉树中某个结点中序后继,找不到返回NULL*/BinaryTree inorderPost_T(BinaryTree bt, BinaryTree cur){if (!bt || !cur){return NULL;}// 1. 有右子树,后继在其右子树中BinaryTree post = cur->right;if (post){while (post->left){post = post->left;}return post;}// 2. 无右子树BinaryTree parent = NULL;BinaryTree p = cur;// 找到当前为父结点左孩子的结点do{parent = parentBiNode_T(bt, p);p = parent;} while (parent && parent->left != p);return parent;}
