zoukankan      html  css  js  c++  java
  • 【100题】第十一题(二叉树中节点的最大距离)

    一,题目:

           如果把二叉树看成一个图,父子节点之间的连线看成是双向的(无向图),定义"距离"为两节点之间边的个数。写一个程序,求一棵二叉树中相距最远的两个节点之间的距离。

    二,思路

           误导思路:不要以为求树的高度。

           正确思路:求“图”中任意两个节点之间,相距最远的的两个节点之间的距离。

           求解步骤:A,经过根节点,左边最深的点到右边最深的点的距离。

                              B,不经过根节点,而是左子树或右子树中最大距离,取其大者。

    三,图解

    情况A:                                                   情况B:

                                A                                                                A

                            /       \                                                         /        \

                          B        C                                                    B            O

                        /    \     /    \                                                /     \

                     D     E   F     G                                          C         D

                                                                                                                                        /             \

                                                                                   E                F

                                                                                 /                      \

                                                                             G                           H 

    情况A:最大距离经过顶点D-B-A-C-F(其中之一)

    情况B:最大距离不经过顶点G-E-C-B-D-F-H(其中之一)

     

    四,源码

     #include "stdio.h"
     #include"stdlib.h" 
     struct NODE
        {
             NODE* pLeft;            // 左子树
             NODE* pRight;          // 右子树
             int nMaxLeft;          // 左子树中的最长距离
             int nMaxRight;         // 右子树中的最长距离
             int chValue;        // 该节点的值
        };
       
        int nMaxLen = 0;
       
        // 寻找树中最长的两段距离
        void FindMaxLen(NODE* pRoot)
        {
             // 遍历到叶子节点,返回
             if(pRoot == NULL)
                  return;
     
             // 如果左子树为空,那么该节点的左边最长距离为0
             if(pRoot -> pLeft == NULL)   
                  pRoot -> nMaxLeft = 0;
             
       
             // 如果右子树为空,那么该节点的右边最长距离为0
             if(pRoot -> pRight == NULL)   
                  pRoot -> nMaxRight = 0;
             
       
             // 如果左子树不为空,递归寻找左子树最长距离
             if(pRoot -> pLeft != NULL)       
                  FindMaxLen(pRoot -> pLeft);
             
       
             // 如果右子树不为空,递归寻找右子树最长距离
             if(pRoot -> pRight != NULL)      
                  FindMaxLen(pRoot -> pRight);
             
       
             // 计算左子树最长节点距离
             if(pRoot -> pLeft != NULL)
             {
                  int nTempMax = 0;
                  if(pRoot -> pLeft -> nMaxLeft > pRoot -> pLeft -> nMaxRight)
                  {
                       nTempMax = pRoot -> pLeft -> nMaxLeft;
                  }
                  else
                  {
                       nTempMax = pRoot -> pLeft -> nMaxRight;
                  }
                  pRoot -> nMaxLeft = nTempMax + 1;
             }
       
             // 计算右子树最长节点距离
             if(pRoot -> pRight != NULL)
             {
                  int nTempMax = 0;
                  if(pRoot -> pRight -> nMaxLeft > pRoot -> pRight -> nMaxRight)
                  {
                       nTempMax = pRoot -> pRight -> nMaxLeft;
                  }
                  else
                  {
                       nTempMax = pRoot -> pRight -> nMaxRight;
                  }
                  pRoot -> nMaxRight = nTempMax + 1;
             }
       
             // 更新最长距离
             if(pRoot -> nMaxLeft + pRoot -> nMaxRight > nMaxLen)
             {
                  nMaxLen = pRoot -> nMaxLeft + pRoot -> nMaxRight;
             }
         }
             
    NODE *createTree()
    {
    	NODE *root;
    	int data;
    	printf("input data:");
    	scanf("%d",&data);
    	//printf("output data:%d\n",data);
    	
    	if(data==0)
    	  root=NULL;
        else/*根左右 前序建立二叉树*/
        {
        	root=(NODE*)malloc(sizeof(NODE));
        	root->chValue=data;
        	root->pLeft=createTree();
        	root->pRight=createTree();	
        }
    	return root;
    } 
    int main()
    {
    	NODE  *root;
    	root=createTree();
    	FindMaxLen(root);
    	
    	printf("%d",nMaxLen);
    	return 0;
    }
    

     

    第二种解法:

    这个问题的核心是,情况A 及 B 需要不同的信息: A 需要子树的最大深度,B 需要子树的最大距离。只要函数能在一个节点同时计算及传回这两个信息,代码就可以很简单:

    #include <iostream> 
      
    using namespace std; 
      
    struct NODE 
    { 
        NODE *pLeft; 
        NODE *pRight; 
    }; 
      
    struct RESULT 
    { 
        int nMaxDistance; 
        int nMaxDepth; 
    }; 
      
    RESULT GetMaximumDistance(NODE* root) 
    { 
        if (!root) 
        { 
            RESULT empty = { 0, -1 };   // trick: nMaxDepth is -1 and then caller will plus 1 to balance it as zero. 
            return empty; 
        } 
      
        RESULT lhs = GetMaximumDistance(root->pLeft); 
        RESULT rhs = GetMaximumDistance(root->pRight); 
      
        RESULT result; 
        result.nMaxDepth = max(lhs.nMaxDepth + 1, rhs.nMaxDepth + 1); 
        result.nMaxDistance = max(max(lhs.nMaxDistance, rhs.nMaxDistance), lhs.nMaxDepth + rhs.nMaxDepth + 2); 
        return result; 
    }
    void Link(NODE* nodes, int parent, int left, int right) 
    { 
        if (left != -1) 
            nodes[parent].pLeft = &nodes[left];  
      
        if (right != -1) 
            nodes[parent].pRight = &nodes[right]; 
    } 
      
    void main() 
    { 
        // P. 241 Graph 3-12 
        NODE test1[9] = { 0 }; 
        Link(test1, 0, 1, 2); 
        Link(test1, 1, 3, 4); 
        Link(test1, 2, 5, 6); 
        Link(test1, 3, 7, -1); 
        Link(test1, 5, -1, 8); 
        cout << "test1: " << GetMaximumDistance(&test1[0]).nMaxDistance << endl; 
      
        // P. 242 Graph 3-13 left 
        NODE test2[4] = { 0 }; 
        Link(test2, 0, 1, 2); 
        Link(test2, 1, 3, -1); 
        cout << "test2: " << GetMaximumDistance(&test2[0]).nMaxDistance << endl; 
      
        // P. 242 Graph 3-13 right 
        NODE test3[9] = { 0 }; 
        Link(test3, 0, -1, 1); 
        Link(test3, 1, 2, 3); 
        Link(test3, 2, 4, -1); 
        Link(test3, 3, 5, 6); 
        Link(test3, 4, 7, -1); 
        Link(test3, 5, -1, 8); 
        cout << "test3: " << GetMaximumDistance(&test3[0]).nMaxDistance << endl; 
      
        // P. 242 Graph 3-14 
        // Same as Graph 3-2, not test 
      
        // P. 243 Graph 3-15 
        NODE test4[9] = { 0 }; 
        Link(test4, 0, 1, 2); 
        Link(test4, 1, 3, 4); 
        Link(test4, 3, 5, 6); 
        Link(test4, 5, 7, -1); 
        Link(test4, 6, -1, 8); 
        cout << "test4: " << GetMaximumDistance(&test4[0]).nMaxDistance << endl; 
    }


     

    计算 result 的代码很清楚;nMaxDepth 就是左子树和右子树的深度加1;nMaxDistance 则取 A 和 B 情况的最大值。

    为了减少 NULL 的条件测试,进入函数时,如果节点为 NULL,会传回一个 empty 变量。比较奇怪的是 empty.nMaxDepth = -1,目的是让调用方 +1 后,把当前的不存在的 (NULL) 子树当成最大深度为 0。

    除了提高了可读性,这个解法的另一个优点是减少了 O(节点数目) 大小的侵入式资料,而改为使用 O(树的最大深度) 大小的栈空间。这个设计使函数完全没有副作用(side effect)。

     

  • 相关阅读:
    《DSP using MATLAB》 示例 Example 9.12
    《DSP using MATLAB》示例 Example 9.11
    《DSP using MATLAB》示例 Example 9.10
    《DSP using MATLAB》示例Example 9.9
    《DSP using MATLAB》示例 Example 9.8
    《DSP using MATLAB》示例Example 9.7
    《DSP using MATLAB》示例 Example 9.6
    《DSP using MATLAB》示例Example 9.5
    《DSP using MATLAB》示例 Example 9.4
    (转载)【C++11新特性】 nullptr关键字
  • 原文地址:https://www.cnblogs.com/secbook/p/2655065.html
Copyright © 2011-2022 走看看