求二叉树两个节点的最近公共祖先

偶然看到一个特别特别巧妙的方法,在此记录一下~

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)了,真的感觉这个方法特别巧妙!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值