网易面试题之求出树的直径

16 篇文章 0 订阅
10 篇文章 0 订阅

给定一颗二叉树,求出树中的任意两个节点之间的最大距离,即树的直径。

        从这个题目可以看到,树中任意两个节点的最大距离,显然应该是不同叶子间的最大距离。我们可以根据树的节点分布情况分情况考虑如何求树的直径。

       情况1:对于一般的树,根结点的左子树与右子树平衡,如图1。左子树与右子树的叶子节点的最大距离,应该为左子树的深度加上右子树的深度,然后加1,即为树的直径。

       情况2:根据上面的分析,我们可以明显感觉到,如果该树为一颗倾斜树,即节点的左子树与右子树不对称,那么根结点的左子树与右子树的高度相差较大,同时衍生道以根结点的左(或右)子树作为根结点的左子树和右子树高非对称,那么根据情况1来求树的直径是完全错误的。

       根据上面的分析,我们需要求出以树的根结点为根结点的左右子树的高度之和diameterOfRoot之后,与以树的根结点的左(右)孩子为根结点的左右子树的高度之和diameterOflChild(diameterOfrChild)进行比较,如果diameterOfRoot最大,那么diameterOfRoot,即为所求,否则diameterOflChild或者diameterOfrChild即为所求。当前这只是一次比较的节点。这个值还需要与树的根结点的左孩子的后代,以及右孩子的后代的不同叶子间的最大距离之和进行比较。

        因此,对树求出直径就是一个不断递归,不断比较的过程。

        它的伪代码为:

         1.输入为根结点,输出为树的直径大小,初始化树的直径大小为0,以及pNode=root。

         2.如果结点pNode为null,返回;否则,根据pNode递归求出左右子树的高度,以及递归2步骤,但是其输入为pNode->lChild、pNode->rChild。比较三者pNode递归求出左右子树的高度、pNode->lChild和pNode->rChild各自返回的左孩子和右孩子为根结点的树的直径。最终,三者的最大值即为树的直径。

         c++代码为:

int DiameterPathOfTree(Node *root,int& length)
{
    if(root==NULL){
        return -1;
    } 
    root->MaxLeft=1+DiameterPathOfTree(root->lChild, length);//求出左孩子的高度,以及以左孩子为根结点的2叉树直径保存在length中
    root->MaxRight=1+DiameterPathOfTree(root->rChild, length);//求出右孩子的高度,以右孩子为根结点的2叉树的直径保存在length中
    if(root->MaxLeft+root->MaxRight>length) length=root->MaxLeft+root->MaxRight+1;//孩子的为根结点的2叉树的直径与(左子树+右子树+1)进行对比,更新直径
    return (root->MaxLeft>root->MaxRight)?root->MaxLeft:root->MaxRight;//返回树的高度
};

         求出了树的直径大小,那么如果确定树的直径上面的节点呢?

要打印路径采用前序遍历来找到路径的根节点,根节点必须是满足:root->MaxLeft+root->MaxRight==length-1;

然后从跟节点遍历深度为root->MaxLeft-1的左子树路径和root->MaxRight-1的右子树路径。

//采用递归的方式来打印直径上的结点
void PrintDepthPathOfTree(Node* root,int depth)
{
    if(depth==-1) return;
    cout<<root->data<<"\t";
    if(root->MaxLeft==depth)
        PrintDepthPathOfTree(root->lChild,depth-1);
    else if(root->MaxRight==depth)
        PrintDepthPathOfTree(root->rChild, depth-1);
    else
        return;
};
//采用循环的方式来打印直径上的结点
void PrintDiameterPathOfTree(Node *root,int length)
{
    Node* pNode=root;
    stack<Node*> s;
    while (pNode!=NULL||s.size()!=0) {
        while (pNode!=NULL) {
            if(pNode->MaxLeft+pNode->MaxRight==length-1){ 
                cout<<pNode->data<<"\t";
                PrintDepthPathOfTree(pNode->lChild,pNode->MaxLeft-1);
                PrintDepthPathOfTree(pNode->rChild,pNode->MaxRight-1);
                return;
            }

            s.push(pNode);
            pNode=pNode->lChild;
        }
        if(s.size()!=0){
            //cout<<"s.szie()==="<<s.size()<<endl;
            pNode=s.top();
            s.pop();
            pNode=pNode->rChild;
        }
    }
};
最后,测试程序代码有:

typedef struct Node
{
    int data;
    Node* rChild;
    Node* lChild;
    int MaxLeft;
    int MaxRight;
    Node(){
        rChild=NULL;
        lChild=NULL;
        MaxLeft=-1;
        MaxRight=-1;
    }
} *BinTree;
int array[31]={1,2,4,8,0,0,9,0,0,5,10,11,0,0,0,0,3,6,12,0,0,13,0,0,7,14,0,0,15,0,0};
void CreateBinTree(BinTree* T)
{
    // 构造二叉链表。 T 是指向根指针的指针,故修改 *T 就修改了实参 ( 根指针 ) 本身
    int ch;
    static int i=0;
    ch=array[i++];
    if(ch==0)
        T=NULL ;// 读人空格,将相应指针置空
    else{ // 读人非空格
        *T=(BinTree)malloc(sizeof(Node)); // 生成结点
        (*T)->data=ch ;
        CreateBinTree(&(*T)->lChild) ; // 构造左子树
        CreateBinTree(&(*T)->rChild) ; // 构造右子树
        
    }
} 


int main (int argc, const char * argv[])
{
    // insert code here...
    BinTree root;
    CreateBinTree(&root);
    int length=0;
    cout<<"the Tree's Depth is:"<<DiameterPathOfTree(root, length)<<endl;
    cout<<"the Tree's Diameter is:"<<length<<endl;
    PrintDiameterPathOfTree(root,length);
    return 0;
}
输出结果为:

the Tree's Depth is:4

the Tree's Diameter is:8

the Nodes of Diameter are:1 2 5 10 11 3 6 12




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值