Algorithm 如何查找节点';s BST中的前置节点,每个节点有3个属性——成功、左和右?
来自CLRS的问题,第3版 12.3-5Algorithm 如何查找节点';s BST中的前置节点,每个节点有3个属性——成功、左和右?,algorithm,clrs,Algorithm,Clrs,来自CLRS的问题,第3版 12.3-5 假设不是每个节点x都保持属性x.p,指向x的父节点,而是保持x.succ,指向x的后续节点。给出使用此表示法在二进制搜索树T上搜索、插入和删除的伪代码。这些程序应在时间O(h)内运行,其中h是树的高度T。(提示:您可能希望实现一个返回节点父节点的子例程。) 我知道如何实现在O(h)时间内返回节点父节点的子例程 要查找节点x的父节点,我们应该首先在x根目录树中找到最大键M。然后,我们从M.succ.left向下到右侧。当我们到达x时,我们在x之前遇到的节点
假设不是每个节点x都保持属性x.p,指向x的父节点,而是保持x.succ,指向x的后续节点。给出使用此表示法在二进制搜索树T上搜索、插入和删除的伪代码。这些程序应在时间O(h)内运行,其中h是树的高度T。(提示:您可能希望实现一个返回节点父节点的子例程。) 我知道如何实现在O(h)时间内返回节点父节点的子例程 要查找节点
x
的父节点,我们应该首先在x
根目录树中找到最大键M
。然后,我们从M.succ.left
向下到右侧。当我们到达x
时,我们在x
之前遇到的节点是x
的父节点
请参阅代码
typedef结构树{
结构树*左、右、成功;
}*英国理工学院;
家长(英国夏令时x)
{
如果(x==root)返回NULL;
BST max=树的最大值(x);
BST parent=max->succ,t;
如果(父项)t=parent->left;
否则t=根;
而(t!=x){parent=t;t=t->right;}
返回父母;
}
当DELETE
x
时,应将x
的前身的succ修改为指向x.succ
,而不再是x
。现在问题来了——如何在O(h)时间内找到x
的前身
当x
的左子树为非空时,它是x
的左子树中最右边的节点。但是,当x
的左子树为空时,前一子树是x
的祖先,以查找调用PARENT
的O(h)次。这需要O(h*h)时间吗?还是应该从根本上向下搜索
请注意,操作INSERT
,还需要查找节点的前置节点
有一个问题——如果所有键共享相同的值怎么办?然后,我们无法通过比较找到
x
,因为键a
,它等于键x
,可能出现在x
的左子树或右子树中。如果x
的左子树为空,x
的前子树不仅仅是它的祖先,它是x
的直接父级。因此,您只需要对parent
子例程进行一次调用,就可以使整个运行时O(h)+O(h)=O(h)
p.S即使它不是直接的父节点,您也不必重复调用
parent
来获取所有的祖先节点,您可以像通常一样从树的根开始搜索x
,在一次长度O(h)
的遍历中保存路径上的所有节点。搜索x
时通过的所有节点,并且根据定义,只有这些节点是x
的祖先。如果键是离散的,则x的前身的键是注意:只有根直接可用时才可能是O(h)。(应该是这种情况)
稍微改变一下你的数据结构
typedef struct TREE{
int key;
struct TREE* left,right,succ;
}*BST;
如果左子树非空,我们使用tree_max,否则我们在BST中搜索x,从根开始搜索,并维护(在变量目标中)右子树遇到的最后一个(即最新的)节点。在搜索结束时,目标是前置项
前置函数
BST PRE(BST x)
{
if(x->left!=NULL)
return TREE_MAXIMUM(x->left);
if(x== root)
return NULL;
BST goal = NULL, y = root;
while(1)
{
if(x->key <= y->key)
y=y->left;
else
{
goal=y;
y=y->right;
}
if(x==y)
{
return goal;
}
}
}
BST前(BST x)
{
如果(x->左!=NULL)
返回树_最大值(x->左);
if(x==根)
返回NULL;
BST目标=空,y=根;
而(1)
{
如果(x->键)
y=y->左;
其他的
{
目标=y;
y=y->右;
}
如果(x==y)
{
回归目标;
}
}
}
为什么需要调用父
子例程O(h)次?为什么一次还不够?