这个题目出现在MS公司的一次面试题当中。公共最近父节点,也叫公共最近祖先(Least Common Ancestors),就是寻找二叉书中,两个结点最近的祖先结点。
在网上查找资料的时候,看到有Tarjan离线算法,过程比较复杂,我自己写了一个复杂度O(n)的算法,思路比较清晰,算法的长度也只有10行左右。经过简单的测试,可以找到正确结果。欢迎大家指正。
整个过程是一次后续遍历二叉树的过程,在遍历的过程中,会得到所有公共父结点,代码中采用了flag表示已经找出了最近的父节点,从而取消之后得到的更远的父节点赋值。从而返回最近的父节点。该方法可以在小范围的修改上,编程寻找多个结点的最近父节点算法。
LCA函数的源代码如下:
int search_lcn(tree root, tree_node node1, tree_node node2, int *flag, tree_node *pres) { if (root) { int res = (root->id == node1.id || root->id == node2.id) + search_lcn(root->left, node1, node2, flag, pres) + search_lcn(root->right, node1, node2, flag, pres); if (res == 2 && *flag == 0) { pres->id = root->id; *flag = 1; } return res; } return 0; }
数的结点采用id来表示。构建二叉树的代码,如下:
typedef struct tree_node { int id; struct tree_node *left; struct tree_node *right; }tree_node, *tree; void build_bitree(tree *proot) //proot 的类型为 tree_node ** { int val; scanf("%d", &val); if (val == -1) { *proot = NULL; } else { *proot = (tree_node *) malloc(sizeof (tree_node)); (*proot)->id = val; build_bitree(&((*proot)->left)); build_bitree(&((*proot)->right)); } }
int main() { tree root; build_bitree(&root); //proot 的类型为 tree_node ** tree_node node1 = {3, NULL, NULL}; tree_node node2 = {6, NULL, NULL}; int flag = 0; tree_node resnode = {0, NULL, NULL}; search_lcn(root, node1, node2, &flag, &resnode); printf("resnode->id = %d\n", resnode.id); return 0; }