BST的定义
二叉搜索树是这样一种二叉树,对于一个结点x, 如果它的左子树的结点值都小于x,它的右子树的结点值都大于x。并且他的左子树和右子树也满足此特性的二叉树。二叉搜索树的中序遍历可得到数据的有序序列。
BST的前驱和后继
BST结点的前驱是指该结点的前一个结点,即指向该结点的结点。
BST结点的后继是指该结点的右子树中值最接近于该结点值的结点,未必是后一个结点。
BST的插入
二叉搜索树插入结点的过程如下:
1. 如果二叉树是空树,建立根结点。
2. 当前值与根结点的值比较,如果当前值小于根结点值,那么往左子树,如果当前值大于根结点值,则往右子树。
3. 重复步骤2,直到到达叶结点。
4. 根据比较大小结果,建立左或右结点,并赋值。
我们以一个整数序列15, 6, 9, 7, 2, 3, 17, 20, 4, 13, 18来说明整个过程,建立如下图所示的二叉搜索树
我们插入结点值为 19 的过程如下所示:
1. 首先 19 与 15 比较,19 > 15 所以走右子树
2. 右子结点值为 17,19 > 17 所以走右子树
3. 右子结点值为 20 19 < 20 所以走左子树
4. 左子结点值为 18 19 > 18 所以走右子树
5. 18 为叶结点,所以将 19 插入到 18 的右子结点
插入过程如下图所示:
BST结构
BST的结构如下所示:
typedef struct BSTreeNode {
int elem;
struct BSTreeNode* leftChild;
struct BSTreeNode* rightChild;
}BSTreeNode;
其中elem,表示当前结点的值,leftChild, rightChild分别指向该结点的左子结点和右子结点。
BST的中序遍历
中序遍历,就是二叉树的中序遍历,先遍历左子树,再遍历根结点,再遍历右子树,以这样的递归方式进行。遍历代码如下:
void inOrder(struct BSTreeNode* bsTree)
{
if(bsTree == NULL)
return;
inOrder(bsTree->leftChild);
printf("%d, ", bsTree->elem);
inOrder(bsTree->rightChild);
return ;
}
BST的查找
BST的查找类似于二分查找,如果结点的值等于当前结点的值,返回该值,如果结点值小于当前值,继续查找左子树,如果结点的值大于当前的值,继续查找右子树。代码如下所示:
bool find(struct BSTreeNode* bsTree, int elem)
{
struct BSTreeNode* p = bsTree;
while(p)
{
if(p->elem == elem)
break;
else if(elem < p->elem)
p = p->leftChild;
else
p = p->rightChild;
}
return p != NULL;
}
BST的删除
BST的查找和遍历都比较容易,但是BST的删除,则有一点点复杂。可以分为以下几种情况
1. 删除叶结点
2. 删除只有左子树的结点
3. 删除只有右子树的结点
4. 删除包含左右子树的结点
删除叶结点
叶结点的删除很容易,直接删除该结点即可,但是需要注意的一点是,我们需要找到该结点的前驱结点,才能将对应的结点指针的内存正确释放。
删除只有左子树的结点
根据二叉树的性质,可以知道,左子结点的值都是小于该结点的值,所以要删除该结点,那么该结点的前驱结点的对应结点,即指向该结点的左子树。
删除只有右子树的结点
根据二叉树的性质,可以知道,右子结点的值都是大于该结点的值,所以要删除该结点,那么该结点的前驱结点的对应结点,即指向该结点的右子树。
删除包含左右子树的结点
要删除该类型的结点,首先要找到该结点的后继,根据二叉树的性质可以知道,该结点的后继位于该结点的右子结点的左子树上,且其后继必没有左子树(因为如果还有左子树,说明还有更小的值更接近该结点的值),那么该结点的右子结点的左子树指针应指向其后继的右子树。
比如说删除结点值 17 的结果如下:
完整代码
完整代码示例如下所示:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define SAFEDELETE(ptr) {if(ptr) {free(ptr); ptr = NULL;}}
typedef struct BSTreeNode {
int elem;
struct BSTreeNode* leftChild;
struct BSTreeNode* rightChild;
}BSTreeNode;
void insertNode(struct BSTreeNode* bsTree, int elem, bool root = false)
{
if(root == true)
{
bsTree->elem = elem;
bsTree->leftChild = bsTree->rightChild = NULL;
}else
{
struct BSTreeNode* p = bsTree;
while(p)
{
if(elem < p->elem)
{
if(p->leftChild != NULL)
p = p->leftChild;
else
{
struct BSTreeNode* q = (struct BSTreeNode*)malloc(sizeof(struct BSTreeNode));
q->elem = elem;
q->leftChild = q->rightChild = NULL;
p->leftChild = q;
q = NULL;
break;
}
}
else
{
if(p->rightChild != NULL)
p = p->rightChild;
else
{
struct BSTreeNode* q = (struct BSTreeNode*)malloc(sizeof(struct BSTreeNode));
q->elem = elem;
q->leftChild = q->rightChild = NULL;
p->rightChild = q;
q = NULL;
break;
}
}
}
}
return ;
}
bool find(struct BSTreeNode* bsTree, int elem)
{
struct BSTreeNode* p = bsTree;
while(p)
{
if(p->elem == elem)
break;
else if(elem < p->elem)
p = p->leftChild;
else
p = p->rightChild;
}
return p != NULL;
}
void Delete(struct BSTreeNode* bsTree, int elem)
{
struct BSTreeNode* p = bsTree, *q = p;
while(p)
{
if(p->elem == elem)
break;
else if(elem < p->elem)
q = p, p = p->leftChild;
else
q = p, p = p->rightChild;
}
if(p)
{
//如果p左、右子结点为空
if(p->leftChild == NULL && p->rightChild == NULL)
{
if(q->leftChild == p)
SAFEDELETE(q->leftChild)
else
SAFEDELETE(q->rightChild)
p = NULL;
}
//如果p左子树不为空,右子树为空
else if(p->leftChild != NULL && p->rightChild == NULL)
{
if(q->leftChild == p)
q->leftChild = p ->leftChild;
else
q->rightChild = p->leftChild;
p = NULL;
}
//如果p右子树不为空,左子树为空
else if(p->leftChild == NULL && p->rightChild != NULL)
{
if(q->leftChild == p)
q->leftChild = p->rightChild;
else
q->rightChild = p ->rightChild;
p = NULL;
}
//如果p左、右子树均不为空
else
{
//查找后继
struct BSTreeNode* r = p->rightChild;
while(r->leftChild)
q = r, r = r->leftChild;
if(r)
{
p->elem = r->elem;
q->leftChild = r ->rightChild;
SAFEDELETE(r);
}
}
}
return ;
}
void inOrder(struct BSTreeNode* bsTree)
{
if(bsTree == NULL)
return;
inOrder(bsTree->leftChild);
printf("%d, ", bsTree->elem);
inOrder(bsTree->rightChild);
return ;
}
void destroyTree(struct BSTreeNode* bsTree)
{
if(bsTree == NULL)
return ;
destroyTree(bsTree->leftChild);
destroyTree(bsTree->rightChild);
SAFEDELETE(bsTree);
return ;
}
int main(int argc, const char * argv[])
{
int arr[] = {15, 6, 9, 7, 2, 3, 17, 20, 4, 13, 18};
struct BSTreeNode* bsTree = (struct BSTreeNode*)malloc(sizeof(struct BSTreeNode));
for(int i = 0 ; i != sizeof(arr) / sizeof(int); ++i)
insertNode(bsTree, arr[i], i == 0);
printf("原二叉搜索树中序:");
inOrder(bsTree);
printf("\n");
printf("查找结点值为13的结点:");
printf("%s\n", find(bsTree, 13) ? "Find it." : "Not Found");
printf("查找结点值为30的结点");
printf("%s\n", find(bsTree, 30) ? "Find it." : "Not Found");
insertNode(bsTree, 16);
insertNode(bsTree, 19);
printf("插入16、 19两个结点:");
inOrder(bsTree);
printf("\n");
Delete(bsTree, 15);
Delete(bsTree, 19);
printf("删除15、 19两个结点:");
inOrder(bsTree);
printf("\n");
//销毁二叉树
destroyTree(bsTree);
return 0;
}
最终的执行结果如下所示:
如有错误,望批评指正。