二叉搜索树的操作都需要建立在二叉搜索树上,所以我打算先谈一下树的建立。与之前讲到的堆不同,二叉搜索树的建立需要的是不断插入。
插入部分代码:
void Tree_Insert(Tree *root,Tree *z)
{
Tree *x,*y;
y=NULL;
x=root;
while (x!=NULL)
{
y=x;
if (x->key>z->key)
{
x=x->left;
}
else if (x->key<z->key)
{
x=x->right;
}
else
{
return ; //说明树中已经存在一样的结点,不用再插入
}
}
z->parent=y;
if (y==NULL)
{
root=z;
}
else if (z->key<y->key)
{
y->left=z;
}
else
{
y->right=z;
}
}
二叉搜索树的遍历有三种:先序遍历,中序遍历,后续遍历。根据当前结点输出,考察先后定义。先序:在其左右子结点之前输出,考察;中序:在左结点,右结点之间输出,考察;后序:在其左右子结点考察,输出后再考察。
先序:
void Print_Tree(Tree *x)
{
if (x!=NULL)
{
cout<<x->key<<endl;
Print_Tree(x->left);
Print_Tree(x->right);
}
}
中序:
void Print_Tree(Tree *x)
{
if (x!=NULL)
{
Print_Tree(x->left);
cout<<x->key<<endl;
Print_Tree(x->right);
}
}
后序:
void Print_Tree(Tree *x)
{
if (x!=NULL)
{
Print_Tree(x->left);
Print_Tree(x->right);
cout<<x->key<<endl;
}
}
查找依照key值进行查找,找到对应之后返回,若没有对应值将会返回NULL
Tree* Search(Tree *x,key)
{
while (x!=NULL||key==x->key)
{
if (x->key>key)
x=x->left;
else if (x->key<key)
x=x->right;
}
return x;
}
MAX()函数用于返回key值最大的结点,MIN()返回key值最小的结点。因为这两个函数以及二叉搜索树的特征使得能够使用二叉搜索树来实现优先队列,但似乎效果没有堆的好。
堆:http://blog.csdn.net/hermit_inwind/article/details/50413255
Tree* MIN(Tree *x)
{
while (x->left!=NULL)
x=x->left;
return x;
}
Tree* MAX(Tree *x)
{
while (x->right!=NULL)
x=x.right;
return x;
}
Transplant(Tree *root,Tree *u,Tree *v)
{
if (u->parent==NULL)
root=v;
else if (u->parent->left==u)
u->parent->left=v;
else
u->parent->right=v;
if (v!=NULL)
v->parent=u->parent;
}
显然,当u没有前驱结点的时候,u就为root结点,将root替换为v即可。除开这种情况,先判断u为其双亲结点的左结点还是右结点,然后将v指向的双亲结点替换为u指向的双亲结点即可。
接下来在实现删除的时候使用到Transplant()函数会然代码看上去更精简,更美观。
void Delet(Tree *root,Tree *x)
{
if (x->left==NULL)
Transplant(root,x,x->right);
else if (x->right==NULL)
Transplant(root,x,x-left);
else
{
Tree *y=MIN(x->right);
if (y->parent!=x)
{
Transplant(root,y,y->right);
y->right=x->right;
y->right->parent=y;
}
Transplant(root,x,y);
y->left=x->left;
y->left->parent=y;
}
free(x); //需要返还动态申请的内存
}
Delete实现:先判断需要删除的子树的根结点是否存在子结点中的一个,若不存在左结点,那么只需要将当前结点的右结点为根的子树替换当前子树即可。简单来说就是将删除结点的右节点的双亲结点更新为删除结点的双亲结点,删除结点的双亲结点的右结点更新为删除结点的右结点。若删除结点的右孩子不存在,则将删除结点与其左孩子替换。若删除结点的左右子树均存在,那么先求出删除结点右子树中的最小值,显然该结点的key值大于所有删除结点左子树中的结点,小于除开该结点以外所有删除结点右子树中的结点。当求出的key值最小结点就是删除结点的右结点时,只需要将该结点与删除结点替换即可,否则需要将该结点与其右结点替换(此时之前求出的结点的指向的右结点为删除结点的右子结点),然后将求出结点与删除结点替换,注意需要调整删除结点左子结点与替换结点之间的指向关系。最后,由于之前结点的内存是动态申请的,在删除后注意使用free()函数返还申请的内存。