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)。

     

  • 相关阅读:
    Ajax缓存处理
    单例模式
    正则表达式基础
    springmvc请求参数的绑定和获取
    springmvc返回视图(解析)
    RequestMapping请求映射方式
    springmvc注解基本入门
    springmvc简介
    Mybatis入门-动态sql
    Mybatis映射配置文件Mapper.xml详解
  • 原文地址:https://www.cnblogs.com/secbook/p/2655065.html
Copyright © 2011-2022 走看看