二叉排序树是一种排序和查找都很有用的特殊二叉树。
二叉树的性质:
1. 若它的左子树不为空,则左子树上所有结点的值均小于它的根节点的值。
2. 若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。
3. 他的左右子树也是二叉排序树。
由于其以上性质,查找的时候只需要判断关键字与节点值的大小,查找器左右子树就可以找到所要找的值(当然,如果二叉树中没有这个值得话最后也肯定找不到,返回NULL)。
以下是实现代码:
预定义和类型定义:
typedef int Status;
typedef int ElemType;
typedef struct BSTNode{
ElemType data;
BSTNode *lchild, *rchild;
}BSTNode,*BSTree;
二叉排序树的查找:
BSTree SearchBST(BSTree T, ElemType key)
{
if (T->data == key)
return T;
else
if (T->data > key)
return SearchBST(T->lchild, key);
else
if (T->data < key)
return SearchBST(T->rchild, key);
}
如果二叉排序树T的根节点就是所要找的值key,则返回T的地址;若根节点的值大于要找的值key,则将T的左子树作为根节点,调用SearchBST()函数;若根节点的值小于要查找的值key,则将T的右子树作为根节点,调用 SearchBST()函数。
含有n个节点的二叉树的平均查找长度为(n+1)/2,这是最差情况。最好情况平均查找长度和log2n成正比。二叉排序树和折半查找相差不大,但就维护的有序性而言,二叉树更有效。
二叉树的插入:
BSTree InsertBST(BSTree T, ElemType e)
{
BSTree S;
if (!T)
{
S = (BSTNode *)malloc(sizeof(BSTNode));
S->data = e;
S->lchild = NULL;
S->rchild = NULL;
return S;
}
else
if (T->data > e)
T->lchild = InsertBST(T->lchild, e);
else
if (T->data < e)
T->rchild = InsertBST(T->rchild, e);
return T;
}
如果树T为空,则为S分配一个节点空间,将要保存的值e存放在S中,并让它的左右子树为空。返回S的值。若不为空则判断T的值与要保存的值e的大小。若根节点值大于e,则将T的左子树作为根节点递归调用InsertBST(),反之,则将T的右子树作为根节点递归调用InsertBST()。
二叉排序树的创建:
BSTree CreateBST(BSTree T)
{
ElemType e;
scanf("%d", &e);
while (e != 0)
{
T = InsertBST(T, e);
scanf("%d", &e);
}
return T;
}
重复输入保存元素并调用InsertBST()函数,这个函数比较简单,不再啰嗦。
二叉树的删除:
BSTree DeleteBST(BSTree T, ElemType key)
{
BSTree p, q, s, f;
p = T;
f = NULL;
while (p)
{
if (p->data == key)
break;
f = p;
if (p->data > key)
p = p->lchild;
else
if (p->data < key)
p = p->rchild;
}
q = p;
if ((p->lchild) && (p->rchild))
{
s = p->lchild;
while (s->rchild)
{
q = s;
s = s->rchild;
}
p->data = s->data;
if (p != q)
q->rchild = s->lchild;
else
if (p == q)
q->lchild = s->lchild;
free(s);
return T;
}
else
if (!p->lchild)
p = p->rchild;
else
if (!p->rchild)
p = p->lchild;
if (!f)
T = p;
else
if (q == f->lchild)
f->lchild = p;
else
f->rchild = p;
free(q);
return T;
}
让指针p先指向根节点,初始化指针f为空。当指针p不为空的时候,根据二叉排序树的性质若关键字大于根节点则让指针p指向右子树,反正指向左子树来确定删除节点的位置,相等时退出循环,此时p指向所要删除节点。
由于删除节点位置的元素必然比其左子树的任何一个元素都大,所以要在不破坏原有结构的情况下删除该节点只需要将其值改为其左子树的最大值。
如果删除节点的左子树右子树都不为空,则让指针s指向p的左子树,并且当s的右子树不为空的时候,让指针q指向s的节点,并让s指向s的右子树。最后s记录的是易p的左子树为根节点的树的最右的节点,即最大值节点,q指向s节点的双亲节点。然后将s节点的data域赋值给p节点的data域。由于不确定s的左子树是否为空,所以得将其左子树连接到树上:当q不等于p的时候,表示s并非p的左子树,则让q的右子树(原来指向s节点)等于s的左子树;当q等于p的时候,表示s为p的左子树,则将s的左子树赋值给q的左子树。释放s节点,返回T。
如果删除节点的左子树为空,则让p指向p的右子树(此时q指向要删除节点);如果删除节点的右子树为空,则让p指向p的左子树(此时q指向要删除的节点)。如果f为空,说明要删除的节点为树T的根节点,则让T指向p(此时p指向要删除节点的左子树或右子树,q指向要删除的节点);f不为空的时候,如果q为f的左子树,则让f的左子树指向p;如果q为f的右子树,则让f的右子树指向p。释放q节点。
返回指针T。
中序遍历:
void print(BSTree T)
{
if (!T)
return;
print(T->lchild);
printf("%d ", T->data);
print(T->rchild);
}
加入main():
int main(void)
{
BSTree T;
ElemType key;
T = NULL;
printf("输入要保存的数值:");
T = CreateBST(T);
printf("输入要删除的节点的值:");
scanf("%d", &key);
T = DeleteBST(T, key);
print(T);
printf("\n");
return 0;
}