二叉查找树
定义:

例如,这是一棵二叉查找树
你会发现它的任何一个结点都满足:
- 如果他比他的˫亲С,则他是他˫亲的左孩子如果他比他的双亲小,则他是他双亲的左孩子
- 如果他比他的˫亲С,则他是他˫亲的左孩子如果他比他的双亲小,则他是他双亲的左孩子
特点:
- 若它的左子树不Ϊ空,则左子树上所有结点的ֵ均С于它的根结点的ֵ若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值
- 若它的右子树不Ϊ空,则右子树上所有结点的ֵ均大于它的根结点的ֵ若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值
- 它的左、右子树Ҳ分别Ϊ二叉查找树它的左、右子树也分别为二叉查找树
但是对于任意一个列表,不同的输入会构成不同的二叉查找树

建空树
结点结构定义如下:
typedef struct node* tree struct node { int data=-1; tree lc=NULL,rc=NULL,parent=NULL; }t[105]
二叉查找树的每个结点比普通二叉树多了指向双亲的指针
以便通过双亲找到前驱、后继
插入操作
函数:当前二叉树根结点的指针
、要插入的数
、上一个查找的节点
)
当向一棵二叉树插入一个结点时,要判断此结点是否比根结点大
如果比根结点大就插入左子树中,比根结点小就插入右子树中,等于根结点插入失败
若当前二叉树的根结点为空,插入成功,将该结点直接覆盖在根节点上
代码如下
bool Insert(tree T,int s,tree p) { int root=T->data; if(root==-1) //插入成功 { T->data=s; T->parent=p; return true; } else { if(s>root) Insert(T->lc,s,T); //递归左子树 else if(s<root) Insert(T->rc,s,T); //递归右子树 else return false; //插入失败 } }
查找操作
普通查询:比根小往左子树走,比根大往右子树走
查找前驱与后继
任何一个节点x的前驱是小于x的最大的数
任何一个节点x的后继是大于x的最小的数
其实找前驱,就是从根节点开始,递归子树,如果当前节点大于你要找的数,就找他的左子树,反之找他的右子树,直到没有可以找的为止
但其实不用如此,x只有两种情况:有左子树和没有左子树(这还用你说)
- 有左子树的前驱:左子树中最大的结点
- 没有左子树的前驱:往上找,第一个具有右子树的父亲节点
以下是查找前驱的代码,后继同理
typedef struct node* tree; tree midf(Node *x) { if(x->lc!= NULL) return findmax(x->lc); //如果x存在左孩子,则x的前驱为其左子树的最大结点 else { tree y=x->p; while(y!=NULL&&x==y->lc) { x=y; y=y->p; } return y; } //如果x没有左孩子。则查找x的最低的具有右孩子的父结点,这个节点就是x的前驱 }
删除操作
让我们想一想,在二叉树中的每一棵节点,存在哪几种状态呢?
因此,我们在删除树中的一个节点来说,也要去分情况讨论了。
1.无左子树,无右子树。
叶子结点
2.无左子树,有右子树。
3.有左子树,无右子树
4.既有左子树,也有右子树。
替代节点呢?我们发现,作为替代节点必须满足的条件是:
(因为该节点位于58节点的左子树,所以肯定比58节点的右子树所有节点都要小)。
但现在又一个问题来了:代替节点被移走后剩下的节点怎么办呢

替代节点移到了该节点上,其实就是把替代结点删除了,按照删除操作再次进行即可
因为每次的替代节点都是往下一层的,所以总有一次不需要替代节点,用前三种情况就可以搞定