标签:nbsp 指针 处理 type preview strong 保存 不用 amp
例如,这是一棵二叉查找树
你会发现它的任何一个结点都满足:
但是对于任意一个列表,不同的输入会构成不同的二叉查找树
结点结构定义如下:
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.无左子树,无右子树。
这种情况的这个节点其实就是叶子结点
这种情况的很简单,我们只要删除该节点,并且返回一个NULL值给上一层节点即可。
2.无左子树,有右子树。
我们需要先把被删除节点的右子树根地址给保存下来以备上一层连接使用
然后在去删除该节点(顺序不能反,否则右子树也一起消失了)
3.有左子树,无右子树
我们需要先把被删除节点的左子树根地址给保存下来以备上一层连接使用
然后在去删除该节点(顺序不能反,否则左子树也一起消失了)
4.既有左子树,也有右子树。
这种情况是最复杂的,处理起来也是最难的
首先我们不可能直接将该节点的左子树或右子树接上去,必须选一个节点进行代替
那我们应该选择哪一个节点作为替代节点呢?我们发现,作为替代节点必须满足的条件是:
根节点的左子树都比根节点小,右子树都比根节点大。
因为左子树所有节点都比该结点小,所以如果我们在58左子树中找到一个最大的节点作为替代节点,则这个节点我们发现比58左子树的所有节点都要大,而且一定是比58节点的 右子树所有节点都要小的(因为该节点位于58节点的左子树,所以肯定比58节点的右子树所有节点都要小)。
此时,我们在58右子树中找到一个最小节点作为替代节点。这样寻找替代节点也是可行的,一样是符合二叉树的结构定义的。右子树的最小节点本身就比右子树所有节点要小,然后根据二叉树的结构特点也能够很轻松的得出要比左子树所有的节点都要大的。
所以左子树中最大的节点与右子树中最小的节点都可以作为它的代替节点
但现在又一个问题来了:代替节点被移走后剩下的节点怎么办呢
替代节点移到了该节点上,其实就是把替代结点删除了,按照删除操作再次进行即可
因为每次的替代节点都是往下一层的,所以总有一次不需要替代节点,用前三种情况就可以搞定
标签:nbsp 指针 处理 type preview strong 保存 不用 amp
原文地址:https://www.cnblogs.com/shengzhe/p/10352447.html