寻找树中两个结点的最低公共祖先
Q:在树中寻找两个结点的最低公共祖先,是什么意思呢?
A:树是由根节点衍生左右孩子继续衍生左右孩子的左右孩子。所以呢树中的两个结点是一定拥有最低公共祖先(这两个结点Q:是在这个祖先结点衍生的孩子中)至于最低:就是第一个公共祖先。
-
树是二叉树并且是BST树嘛?
我们根据BST树(二叉搜索树/二叉排序树)的特性:树中任意结点的val大于左孩子的val。如果该结点是这两个结点的最低公共祖先
那么他的val一定是大于等于其中一个结点的val,并且小于另外一个结点的val或者小于等于其中一个结点的val并且大于另外一个结点的val。
如上图三种情况,此图省略了父节点和孩子之间的结点,不代表不存在
typedef int KeyType;
typedef struct BstNode{
BstNode*left;
BstNode*right;
BstNode*parent;
KeyType key;
}BstNode;
typedef struct BstTree{
BstNode* head;
KeyType cursize; //BST树中结点个数(不包括头结点)
}BstTree;
BstNode* lowestCommonAncestor(BstNode*root, BstNode*p, BstNode*q)
{
while (1)
{
if (root->key > max(p->key, q->key))
{
root = root->left;
}
else if (root->key < min(p->key, q->key))
{
root = root->right;
}
else
{
//如上图三种形式
return root;
}
}
}
- 如果是一颗普通的树,并且拥有指向父结点的指针
如果拥有指向父结点的指针,我们就可以从两个结点开始往根遍历。显示成两条链表,两个链表相交的结点就是最低公共祖先结点。
如图所示,寻找F和H的最低公共祖先,利用parent指针往根遍历,我们可以的得到两个链表:
FDBA 和HEBA
两个链表相交于B结点,所以公共祖先是结点B。
- 没有指向父结点的指针的树
这里我们用的树的前序遍历,前序遍历的规则:父节点,左孩子,右孩子。 这里的前序遍历为我们提供了很大帮助,但是不是完全利用前序遍历。
如上图树所示。我们需要申请两个辅助空间,来存放到达这两个结点的必经路径。我们根据前序遍历的规则如下演示:
寻找F的必经路径:
①A
②A->B
③A->B->D
④A->B->D->F
所以ABD是到F的必经路径。
寻找H的必经路径:
①A
②A->B
③A->B->D
④A->B->D->F
F的左右孩子都为空,所以无法到达H,删除F。
⑤A->B->D->G
G的左右孩子都为空,所以无法到达H,删除G。
因为D的两个孩子都无法到达H,所以删除D。
⑥A->B->E
⑦A->B->E->H
所以ABE是到H的必经路径。
两链表相交于B,所以B结点时F,H两结点的最低公共祖先。