偶然看到一个特别特别巧妙的方法,在此记录一下~
1、二叉树的结构
在建立二叉树的时候可以选择存储该节点的parent指针,指向该节点的上一个分叉节点,因此二叉树的结构为:
typedef struct XBNode{
char data;
XBNode *lchild;
XBNode *rchild;
XBNode *parent;
}XBNode,*XBTree;
取名叫XBTree是因为以为这个是线索二叉树 > < 记住!这个不是线索二叉树,线索二叉树是存储了前驱和后继的指针,包括前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
2、建立二叉树
由于建立的时候多了一个parent指针,所以注意要把该节点的parent作为参数传递。这种写法的时候还需要注意最后不要忘记return节点,不然就建了一个空树啦~
XBTree CreateXBTree(XBTree tree){
char e = getchar();
if (e == ' '){
return NULL;
}
XBTree xb = (XBTree)malloc(sizeof(XBNode));
xb->data = e;
xb->parent = tree;
xb->lchild = CreateXBTree(xb);
xb->rchild = CreateXBTree(xb);
return xb;
}
3、获取到节点的指针
根据用户输入的字符找到该节点,也用递归的方法,判断是否是为空,判断是否是该字符,如果不是再遍历左树和右树。
XBTree GetPosition(XBTree p, char e,XBTree &out){
if (p == NULL){
return NULL;
}
if (p->data == e){
out = p;
}
GetPosition(p->lchild, e,out);
GetPosition(p->rchild, e,out);
}
4、二重循环求解
这个就是最简单的思路,采用二重循环遍历出所有有可能的情况,时间复杂度为O(n^2)。
char GetAncestor(XBTree tree, char x1, char x2){
XBTree p1, p2;
GetPosition(tree, x1, p1);
GetPosition(tree, x2, p2);
if (!p1 || !p2){
printf("结点不存在!");
return NULL;
}
XBTree q1 = p1;
XBTree q2 = p2;
while (q1 != NULL){
if (q1->data == q2->data){
return q1->data;
}
while (q2 != NULL){
if (q2 != NULL && q1->data == q2->data){
return q1->data;
}
q2 = q2->parent;
}
q1 = q1->parent;
q2 = p2;
}
return NULL;
}
这种暴力的方法很容易理解,但是时间复杂度较高!
5、巧妙求两个链表的交点
可以换一种方式理解,这两个节点分别和他们的parent们可以构成一个链表:
然后这个问题就转换为如何求两个链表的交点。求解的时候也有一个很巧妙的方法,从两个链表的头开始遍历,当某个链表遍历到根节点的时候使其等于另外一个链表的头,比如链表1的长度为m,链表2的长度n,交点在a位置,那么链表1需要next 这么多次 m+(n-a)正好到交点a,链表2需要next这么多次 n + (m-a)正好到交点a,发现没有!正好同时遍历到交点a!附上代码:
XBTree q1 = p1;
XBTree q2 = p2;
while (q1->data != q2->data){
q1 = q1->parent;
q2 = q2->parent;
if (q1 == NULL)
q1 = p2;
if (q2 == NULL)
q2 = p1;
if (q1->data == q2->data)
return q1->data;
}
return NULL;
这样时间复杂度就只有O(n)了,真的感觉这个方法特别巧妙!!!