编程之美 3.8 求二叉树中节点的最大距离 3.9 重建二叉树

3.8 题意为:将一棵二叉树看成一个图,求树上两点之间的距离。距离定义为两点之间边的条数,如下图的二叉树中,节点8和5之间的距离为3。

3.9题意为已知二叉树的前序遍历结果和中序遍历结果,要求重建二叉树。之所以在这里说3.9,是因为解第八题的时候为了处理输入建成二叉树,实现了一个重建二叉树的函数。

代码如下(六个参数分别为前序遍历结果数组,其起点和终点;中序遍历结果数组,其起点和终点):

node* buildTree(int* nodesPre,int s1,int e1,int* nodesIn,int s2,int e2)
{
    if (s1 > e1)
    {
        return NULL;
    }
    if (s2 > e2)
    {
        return NULL;
    }

    node* root = new node;
    root->data = nodesPre[s1];

    int lenOfLeft = 0;
    for (;s2 + lenOfLeft <= e2;lenOfLeft++)
    {
        if (nodesPre[s1] == nodesIn[s2 + lenOfLeft])
            break;
    }

    root->left = buildTree(nodesPre,s1+1,s1+lenOfLeft,nodesIn,s2,s2+lenOfLeft-1);
    root->right = buildTree(nodesPre,s1+lenOfLeft+1,e1,nodesIn,s2+lenOfLeft+1,e2);

    return root;
}

回到3.8,遍历树中的所有节点,为每个节点生成由0和1组成的串作为ID,递归定义,节点a的左孩子ID为ID(a).push_back(1),右孩子ID为ID(a).push_back(0)。即根的ID为空串,在遍历过程中,每向左走一次,就在其父节点ID后添加一个1作为其ID,若向右则添加一个0。如图中的节点8,ID为111,即因为它可以通过从根节点连续三次向左走来到达。

有了这个ID,就可以很容易地计算两个节点之间的距离了。先给出递归遍历所有节点并计算ID的函数:

void buildMap(node* root,map<int,vector<int>>& nodesInfo)
{
    if (root->left)
    {
        vector<int> lstr = nodesInfo[root->data];
        lstr.push_back(1);
        nodesInfo[root->left->data] = lstr;
        buildMap(root->left,nodesInfo);
    }

    if (root->right)
    {
        vector<int> rstr = nodesInfo[root->data];
        rstr.push_back(0);
        nodesInfo[root->right->data] = rstr;
        buildMap(root->right,nodesInfo);
    }
}

一个点的ID表示了从根节点需要经过怎样的路径能到达它。于是,若两个点的ID开头有相同的部分,说明它们在一开始路径是一直的,即没有分离,这段路径不会增加两者的距离。忽略掉开头的相同部分后,两者ID中剩下的部分就代表了两者完全不同的路径了,将两者ID剩余部分的长度相加即得到了两者的距离。如图中的节点8和节点5,ID分别是111和10,忽略掉开头的一个1后,两者的剩余部分分别是11和0,则distance(8,5)=length(11)+length(0)=2+1=3。

计算两个节点距离的函数如下:

int findDistance(map<int,vector<int>>& nodesInfo,int i,int j)
{
    vector<int> v1 = nodesInfo[i];
    vector<int> v2 = nodesInfo[j];

    while (!v1.empty() && !v2.empty() && v1[0] == v2[0])
    {
        v1.erase(v1.begin());
        v2.erase(v2.begin());
    }

    return v1.size() + v2.size();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值