插入
在实现插入算法的时候,由于树状结构本身是递归的,因此可以使用递归函数实现插入算法
// 假设 BST 节点存储的数据类型是 int
node *newNode(int data)
{
// 准备好新节点,并将数据填入其中
node *new = (node *)malloc(sizeof(node));
if(new != NULL)
{
new->data = data;
new->lchild = NULL;
new->rchild = NULL;
}
return new;
}
// 将新节点new插入到一棵以 root 为根的 BST 中
// 插入节点后,返回新的 BST 的根
node *bstInsert(node *root, node *new)
{
// 若此时 BST 为空,则返回 new 使之成为二叉树的根节点
if(root == NULL)
return new;
// 若新节点比根节点小,那么新节点应该插入左子树中
// 至于插入到左子树的具体什么位置就不用管了,直接递归即可
if(new->data < root->data)
root->lchild = bstInsert(root->lchild, new);
// 若新节点比根节点大,那么新节点应该插入右子树中
// 至于插入到右子树的具体什么位置就不用管了,直接递归即可
else if(new->data > root->data)
root->rchild = bstInsert(root->rchild, new);
// 若已存在,则不处理
else
{
printf("%d已存在\n", new->data);
free(new);
}
return root;
}
删除节点
假设要删除的节点是x,大体思路如下:
若要删除的节点小于根节点,则递归地在左子树中删除x
若要删除的节点大于根节点,则递归地在右子树中删除x
若要删除的节点恰好就是根节点,则分如下几种情况:
a. 根节点若有左子树,则用左子树中最大的节点max替换根节点,并在左子树中递归删除max
b. 否则,若有右子树,则用右子树中最小的节点min替换根节点,并在右子树中递归删除min
c. 否则,直接删除根节点
以下图为例,假设在一棵二叉树中要删除节点15,在找到节点之后,判断其有左子树,那么就沿着其左子树找到最右下角(最大)的节点19,替换要删除的节点15,然后再将多余的节点19删掉:
而如果要删除的节点没有左子树,只有右子树,那么情况是完全对称的,如下图所示,假设要删除节点25,由于25没有左子树,因此找到其右子树中最左下角(最小)的节点16,替换要删除的节点25,然后再将多余的节点16删掉:
// 将数据(以整型为例)data从二叉树中删除
// 并返回删除之后的二叉树的根
node *bstRemove(node *root, int data)
{
if(root == NULL)
return NULL;
// 若data小于根节点,则递归地在左子树中删除它
if(data < root->data)
root->lchild = bstRemove(root->lchild, data);
// 若data小于根节点,则递归地在左子树中删除它
else if(n > root->data)
root->rchild = bstRemove(root->rchild, data);
// 若data恰好就是根节点,则分如下几种情况:
else
{
// a. 根节点若有左子树,则用左子树中最大的节点max替换根节点
// 并在左子树中递归删除max
if(root->lchild != NULL)
{
node *max;
for(max=root->lchild; max->rchild!=NULL;
max=max->rchild);
root->data = max->data;
root->lchild = bstRemove(root->lchild, max->data);
}
// b. 否则,若有右子树,则用右子树中最小的节点min替换根节点
// 并在右子树中递归删除min
else if(root->rchild != NULL)
{
for(tmp=root->rchild; tmp->lchild!=NULL;
tmp=tmp->lchild);
root->data = tmp->data;
root->rchild = bst_remove(root->rchild, tmp->data);
}
// c. 否则,直接删除根节点
else
{
free(root);
return NULL;
}
}
return root;
}
遍历
// 前序遍历
void preOrder(node *root)
{
if(root == NULL)
return;
// 先访问根节点
printf("%d", root->data);
// 再依次使用前序算法,遍历其左、右子树
preOrder(root->lchild);
preOrder(root->rchild);
}
// 中序遍历
void inOrder(node *root)
{
if(root == NULL)
return;
// 先访问左子树
inOrder(root->lchild);
// 再访问根节点
printf("%d", root->data);
// 再访问右子树
inOrder(root->rchild);
}
// 后序遍历
void postOrder(node *root)
{
if(root == NULL)
return;
// 先依次使用后序算法,遍历其左、右子树
postOrder(root->lchild);
postOrder(root->rchild);
// 再访问根节点
printf("%d", root->data);
}