数据结构—二叉搜索树

来源:互联网 发布:oracle数据导出导入 编辑:程序博客网 时间:2024/05/29 05:52

二叉搜索树概念

      什么是二叉搜索树,在我看来二叉搜索树相对于二叉树最大的区别在于:二叉搜索树中的任意节点x,其左节点的关键字都小于x.key,其右节点的关键字都大于x.key。由该性质可以对二叉搜索树有三种遍历方法。

      先序遍历:先输出根节点的关键字,而后输出左子树的关键字,最后输出右子书的关键字。

      中序遍历:先输出左子树的关键字,而后输出根节点的关键字,最后输出右子树的关键字。

      后序遍历:先输出左子树的关键字,而后输出右子树的关键字,最后输出根节点的关键字。

如下图所示:

                                                                 

先序遍历:7,3,18,10,8,11,22,26

中序遍历:3,7,8,10,11,18,22,26

后序遍历:3,8,11,10,26,22,18,7

查询二叉树

二叉树的查询包括关键字查询,最大值、最小值查询,前驱和后驱的查询,其中关键字,最大值、最小值查询比较简单,重点介绍一下后驱的查询方法。
查找二叉树节点x的后驱会出现如下三种情况:
1.当节点x存在右孩子时,我们只需要查找以右孩子为树节点的树,关键字最小的节点,该节点则为节点x的后驱。
2.当节点x右孩子为空时,且该节点x为父节点的左孩子,则节点x的后驱为该父节点。
3.当节点x右孩子为空时,且该节点x为父节点的右孩子,则节点x的后驱为上层祖先。
伪代码如下:
TREE-SUCCESSOR(x)
if x.right!=NUL
return TREE_MINIMUM(x.right)
y=x.p
while y!=NULL and x==y.right
x=y
y=y.p
return y
tree_node* tree_successed(tree_node *x)//查找节点x的后驱{if(x->right!=NULL)//情况一,假设存在右子树{return tree_min(x->right);//查找右子树的最小值}while(x->parent->left!=x)//情况2、3,假设没有右子树,则为父节点或者上层父节点{x=x->parent;}return x->parent;}

插入和删除

插入操作相对于删除操作简单,插入只需要找到关键字所处的位置,并修改相应指针即可,具体代码如下:
void tree_insert(tree_node *x,tree_node *z)  //二叉树插入一个节点{tree_node *y=NULL;while(x!=NULL){y=x;if(x->data>=z->data){x=x->left;}else{x=x->right;}}z->parent=y;if(y->data>z->data){y->left=z;}else{y->right=z;}z->left=NULL;z->right=NULL;}

对于删除操作,是二叉搜索树的重点,也需要分成四种情况讨论:
1.节点x无孩子,即x为叶节点,直接将其用空节点替换就可以。
2.节点x存在一个孩子,则直接将孩子替换该节点,并修改相应节点属性。
3.节点x两个孩子都存在,但是节点x的后驱节点为节点x的右孩子,由二叉搜索树的性质可以知道后驱节点肯定没有左孩子,故直接将节点x的右孩子替换节点x,并修改相应节点(左孩子节点,父节点)的属性。
4.节点x两个孩子都存在,但后驱节点不为节点x的孩子,则通过后驱查找函数找到该节点y,由于后驱节点y没有左孩子,则可以用后驱节点y的右孩子替换后驱节点y,后驱节点y替换待删除节点x,并修改相应节点的属性。
具体情况如下所示:
情况1:
                                                                      
情况2:
                                                                                                
情况3:
                                                                                     
情况4:
                                                                                               
上图中所有删除节点都为z

删除具体代码如下:
void tree_transplant(tree_node *u,tree_node *v)//节点v代替节点u{ if(u->parent->left==u){u->parent->left=v;}else{u->parent->right=v;}if(v!=NULL)//防止指针v为空{v->parent=u->parent;}/*if(u->left!=NULL)//容易自己指向自己,造成死循环{v->left=u->left;u->left->parent=v;}if(u->right!=NULL){v->right=u->right;u->right->parent=v;}*/}void tree_delete(tree_node *x,tree_node *y)//删除节点y{tree_node *z,*successed;z=tree_search(x,y->data);if(z->left==NULL)//左孩子为空{tree_transplant(z,z->right);}else if(z->right==NULL)//右孩子为空{tree_transplant(z,z->left);}else//存在两个孩子{if(z->right->left==NULL)//情况3{tree_transplant(z,z->right);z->right->left=z->left;z->left->parent=z->right;}else//情况4{successed=tree_successed(z);tree_transplant(successed,successed->right);successed->right->left=successed->left;//将左孩子的属性更正successed->left->parent=successed->right;tree_transplant(z,successed);successed->left=z->left;z->left->parent=successed;}}}


原创粉丝点击