求二叉树中任意两结点的距离

来源:互联网 发布:js中onchange 编辑:程序博客网 时间:2024/04/28 19:21

与该题的一道相似题为:求二叉树中结点的最长距离。两题看似有联系,但是做法不同。

首先回顾一下:如何求二叉树中两结点的最长距离,即两点之间边数。

分析:距离和深度之间存在必然联系。如果已知最长距离的两结点的最低公共根节点r,那么我们求r的左右子树深度相加即最长距离求出。如下图所示:


我们发现A和B是最长距离,他们的最低公共根节点为C,假如我们知道C的左右子树高度均为3,并且最长路径通过C,那么最长路径必定为3+3=6.因此,问题转化成求每个结点的左右子树深度,并取每个结点左右子树深度和的最大值即可。

因此我们采用Result结构体,记录以该结点为根的子树中距离最大值该结点的最大深度

本质还是动态规划思想。

代码如下:

[cpp] view plaincopyprint?
  1. struct BinaryTreeNode  
  2. {  
  3.     char m_chValue;  
  4.     BinaryTreeNode* m_pLeft;  
  5.     BinaryTreeNode* m_pRight;  
  6. };  
  7.   
  8. struct Result  
  9. {  
  10.     int nMaxDistance;  
  11.     int nMaxDepth;  
  12. };  
  13.   
  14. Result GetMaxDistance(BinaryTreeNode *& pRoot)  
  15. {  
  16.     if (!pRoot)  
  17.     {  
  18.         Result empty={-1,-1};  
  19.         return empty;  
  20.     }  
  21.     Result leftResult = GetMaxDistance(pRoot->m_pLeft);  
  22.     Result rightResult = GetMaxDistance(pRoot->m_pRight);  
  23. <span style="white-space:pre">  </span>  
  24.     Result result;  
  25.     result.nMaxDepth = 1+ max(leftResult.nMaxDepth, rightResult.nMaxDepth);  
  26.     result.nMaxDistance =max( max(leftResult.nMaxDistance, rightResult.nMaxDistance), (leftResult.nMaxDepth+rightResult.nMaxDepth+2) );  
  27.   
  28.     return result;  
  29. }  
建树代码参考:http://blog.csdn.net/zhaojinjia/article/details/9305251

[cpp] view plaincopyprint?
  1. // 输入:先序和中序的第一个指针和最后一个指针,    
  2. // 递归调用,每次缺点当前结点    
  3. BinaryTreeNode* ConstructCore(char* startPerorder, char* endPreorder, char* startInorder, char* endInorder)    
  4. {    
  5.     //先序第一个为根节点    
  6.     char rootValue = startPerorder[0];    
  7.     BinaryTreeNode* root = new BinaryTreeNode;    
  8.     root->m_chValue = rootValue;    
  9.     root->m_pLeft = root->m_pRight = NULL;    
  10.   
  11.     //递归退出条件    
  12.     if ( startPerorder==endPreorder )    
  13.     {    
  14.         if ( startInorder==endInorder && *startPerorder==*endInorder )    
  15.             return root;    
  16.         else    
  17.             throw std::exception("Invalid input."); //异常处理    
  18.     }    
  19.   
  20.     // 在中序遍历中找到根节点的值    
  21.     char* rootInorder = startInorder;    
  22.     while(rootInorder<=endInorder && *rootInorder!=rootValue)    
  23.         ++rootInorder;    
  24.   
  25.     //异常处理    
  26.     if ( rootInorder==endInorder && *rootInorder!=rootValue)    
  27.         throw std::exception("Invalid input.");    
  28.   
  29.     int leftLength = rootInorder - startInorder;    
  30.     char* leftPreorderEnd = startPerorder+leftLength;    
  31.     if ( leftLength > 0 )    
  32.     {    
  33.         //构建左子树    
  34.         root->m_pLeft = ConstructCore(startPerorder+1,leftPreorderEnd,startInorder, rootInorder-1);    
  35.     }    
  36.     if ( leftLength < endPreorder-startPerorder )    
  37.     {    
  38.         //构建右子树    
  39.         root->m_pRight = ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);    
  40.     }    
  41.   
  42.     return root;    
  43. }    
  44.   
  45. //根据先序和中序构建二叉树    
  46. BinaryTreeNode* Construct(char* preorder, char* inorder, char length)    
  47. {    
  48.     if(preorder==NULL || inorder==NULL || length <=0)    
  49.         return NULL;    
  50.   
  51.     return ConstructCore(preorder, preorder+length-1, inorder,inorder+length-1);    
  52. }    
  53.   
  54. int _tmain(int argc, _TCHAR* argv[])  
  55. {  
  56.       
  57.     char* pInorder = "abcdefghi";  
  58.     char* pPreorder = "ecbadhfgi";  
  59.     BinaryTreeNode* pRoot = Construct( pPreorder,pInorder,strlen(pInorder) );  
  60.       
  61.     Result result = GetMaxDistance(pRoot);  
  62.     cout << "最大距离为:" << result.nMaxDistance <<endl;  
  63.     return 0;  
  64. }  


问题定义:给定一非二叉排序树,随意给出任意两个结点值,求二者的距离

分析:求两结点的距离,实际是找二者的从根到该结点的路径,路径找到,那么距离就有了。

例如:找结点值为a和d的距离,a的路径为ecba,d的路径为ecd。那么二者的路径就为abcd,距离就是3.

问题转化成如何求该结点到根节点的路径。我们可以后序遍历二叉树,同时用栈或数组保存当前路径,如果和结点值匹配的话,保存当前路径,直到找到两结点值路径为止。

步骤如下:

1:后序遍历先序处理获得该两个结点值的路径字符串;

2:比较两个路径字符串,不相同字符即二者的距离长度;

3:如果找不全两结点值,则距离为0。

代码:

[cpp] view plaincopyprint?
  1. //在以pRoot为根的树中查找结点文本值分别为node1Val和node2Val的二者距离  
  2. int GetDistanceBetNodes(BinaryTreeNode* pRoot, char node1Val, char node2Val)  
  3. {  
  4.     if(!pRoot)  //如果是空  
  5.         return 0;  
  6.     vector<BinaryTreeNode*> path;  
  7.     BinaryTreeNode* pTempNode = pRoot;  
  8.     int i,nFindCount = 0;     
  9.     bool Tag[50];       //记录栈中结点是否左右子树遍历玩,如果遍历完,置true  
  10.     memset(Tag,0,sizeof(bool)*50);    
  11.     char *pNodePath[2] = {NULL};    //开辟一个指针数组,指向两个字符的路径  
  12.       
  13.     while ( pTempNode || !path.empty() )    //当所有结点都遍历完或者已经找到二者的路径则终止  
  14.     {  
  15.         while ( pTempNode )  
  16.         {  
  17.             path.push_back(pTempNode);  
  18.               
  19.             //判断入栈元素是否与要查找的结点值相等,相等则赋值  
  20.             if ( pTempNode->m_chValue==node1Val || pTempNode->m_chValue==node2Val )  
  21.             {  
  22.                 pNodePath[nFindCount] = new char[path.size()+1];  
  23.                 for (i=0; i<(int)path.size(); i++)  
  24.                 {  
  25.                     pNodePath[nFindCount][i] = path.at(i)->m_chValue;  
  26.                 }  
  27.                 pNodePath[nFindCount++][i] = '\0';  
  28.                 if (nFindCount==2)  
  29.                     break;  
  30.             }  
  31.               
  32.             pTempNode = pTempNode->m_pLeft;  
  33.         }  
  34.         while ( !path.empty() && Tag[path.size()-1] == true )   //如果栈顶元素左右子树已遍历完在遍历该结点  
  35.         {  
  36.         //  cout << path.back()->m_chValue <<endl;  
  37.               
  38.             Tag[path.size()-1] = false;     //此时Tag[path.size()-1]对应位置没有元素,将它置初始值,方便下次对该位置元素做判断  
  39.             path.pop_back();  
  40.         }  
  41.         if ( !path.empty() )  
  42.         {  
  43.             Tag[path.size()-1] = true;  
  44.             pTempNode = path.back();  
  45.             pTempNode = pTempNode->m_pRight;  
  46.         }  
  47.     }  
  48.     //如果二者不全有值,距离默认为0  
  49.     if ( !(pNodePath[0]&&pNodePath[1]) )  
  50.         return 0;  
  51.       
  52.     //遍历两结点路径字符串,不相同字符个数即二者的路径长度  
  53.     char *p1 = pNodePath[0];  
  54.     char *p2 = pNodePath[1];  
  55.     int distance = 0;  
  56.     while ( *p1!='\0' || *p2!='\0' )  
  57.     {  
  58.         if ( *p1 == *p2 )  
  59.         {  
  60.             p1++;  
  61.             p2++;  
  62.         }  
  63.         else  
  64.         {  
  65.             if (*p1 != '\0')  
  66.             {  
  67.                 distance++;  
  68.                 p1++;  
  69.             }  
  70.             if (*p2 != '\0')  
  71.             {  
  72.                 distance++;  
  73.                 p2++;  
  74.             }  
  75.         }  
  76.     }  
  77.   
  78.     delete pNodePath[0];  
  79.     delete pNodePath[1];  
  80.   
  81.     return distance;  
  82. }  
  83.   
  84. int _tmain(int argc, _TCHAR* argv[])  
  85. {  
  86.       
  87.     char* pInorder = "abcdefghi";  
  88.     char* pPreorder = "ecbadhfgi";  
  89.     BinaryTreeNode* pRoot = Construct( pPreorder,pInorder,strlen(pInorder) );  
  90.       
  91.     cout << GetDistanceBetNodes(pRoot, 'a''e') <<endl;  
  92.     return 0;  
  93. }  

扩展:

那么,在一棵多叉树中同时找多个结点文本值的最低公共祖先结点,方法也是一样的。即后序遍历,先序处理

0 0
原创粉丝点击