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

来源:互联网 发布:淘宝孔雀舞服装 编辑:程序博客网 时间:2024/04/27 23:52

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

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

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


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

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

本质还是动态规划思想。

代码如下:

struct BinaryTreeNode{char m_chValue;BinaryTreeNode* m_pLeft;BinaryTreeNode* m_pRight;};struct Result{int nMaxDistance;int nMaxDepth;};Result GetMaxDistance(BinaryTreeNode *& pRoot){if (!pRoot){Result empty={-1,-1};return empty;}Result leftResult = GetMaxDistance(pRoot->m_pLeft);Result rightResult = GetMaxDistance(pRoot->m_pRight);Result result;result.nMaxDepth = 1+ max(leftResult.nMaxDepth, rightResult.nMaxDepth);result.nMaxDistance =max( max(leftResult.nMaxDistance, rightResult.nMaxDistance), (leftResult.nMaxDepth+rightResult.nMaxDepth+2) );return result;}
建树代码参考:http://blog.csdn.net/zhaojinjia/article/details/9305251

// 输入:先序和中序的第一个指针和最后一个指针,  // 递归调用,每次缺点当前结点  BinaryTreeNode* ConstructCore(char* startPerorder, char* endPreorder, char* startInorder, char* endInorder)  {  //先序第一个为根节点  char rootValue = startPerorder[0];  BinaryTreeNode* root = new BinaryTreeNode;  root->m_chValue = rootValue;  root->m_pLeft = root->m_pRight = NULL;  //递归退出条件  if ( startPerorder==endPreorder )  {  if ( startInorder==endInorder && *startPerorder==*endInorder )  return root;  else  throw std::exception("Invalid input."); //异常处理  }  // 在中序遍历中找到根节点的值  char* rootInorder = startInorder;  while(rootInorder<=endInorder && *rootInorder!=rootValue)  ++rootInorder;  //异常处理  if ( rootInorder==endInorder && *rootInorder!=rootValue)  throw std::exception("Invalid input.");  int leftLength = rootInorder - startInorder;  char* leftPreorderEnd = startPerorder+leftLength;  if ( leftLength > 0 )  {  //构建左子树  root->m_pLeft = ConstructCore(startPerorder+1,leftPreorderEnd,startInorder, rootInorder-1);  }  if ( leftLength < endPreorder-startPerorder )  {  //构建右子树  root->m_pRight = ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);  }  return root;  }  //根据先序和中序构建二叉树  BinaryTreeNode* Construct(char* preorder, char* inorder, char length)  {  if(preorder==NULL || inorder==NULL || length <=0)  return NULL;  return ConstructCore(preorder, preorder+length-1, inorder,inorder+length-1);  }  int _tmain(int argc, _TCHAR* argv[]){char* pInorder = "abcdefghi";char* pPreorder = "ecbadhfgi";BinaryTreeNode* pRoot = Construct( pPreorder,pInorder,strlen(pInorder) );Result result = GetMaxDistance(pRoot);cout << "最大距离为:" << result.nMaxDistance <<endl;return 0;}


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

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

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

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

步骤如下:

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

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

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

代码:

//在以pRoot为根的树中查找结点文本值分别为node1Val和node2Val的二者距离int GetDistanceBetNodes(BinaryTreeNode* pRoot, char node1Val, char node2Val){if(!pRoot)//如果是空return 0;vector<BinaryTreeNode*> path;BinaryTreeNode* pTempNode = pRoot;int i,nFindCount = 0;bool Tag[50];//记录栈中结点是否左右子树遍历玩,如果遍历完,置truememset(Tag,0,sizeof(bool)*50);char *pNodePath[2] = {NULL};//开辟一个指针数组,指向两个字符的路径while ( pTempNode || !path.empty() )//当所有结点都遍历完或者已经找到二者的路径则终止{while ( pTempNode ){path.push_back(pTempNode);//判断入栈元素是否与要查找的结点值相等,相等则赋值if ( pTempNode->m_chValue==node1Val || pTempNode->m_chValue==node2Val ){pNodePath[nFindCount] = new char[path.size()+1];for (i=0; i<(int)path.size(); i++){pNodePath[nFindCount][i] = path.at(i)->m_chValue;}pNodePath[nFindCount++][i] = '\0';if (nFindCount==2)break;}pTempNode = pTempNode->m_pLeft;}while ( !path.empty() && Tag[path.size()-1] == true )//如果栈顶元素左右子树已遍历完在遍历该结点{//cout << path.back()->m_chValue <<endl;Tag[path.size()-1] = false;//此时Tag[path.size()-1]对应位置没有元素,将它置初始值,方便下次对该位置元素做判断path.pop_back();}if ( !path.empty() ){Tag[path.size()-1] = true;pTempNode = path.back();pTempNode = pTempNode->m_pRight;}}//如果二者不全有值,距离默认为0if ( !(pNodePath[0]&&pNodePath[1]) )return 0;//遍历两结点路径字符串,不相同字符个数即二者的路径长度char *p1 = pNodePath[0];char *p2 = pNodePath[1];int distance = 0;while ( *p1!='\0' || *p2!='\0' ){if ( *p1 == *p2 ){p1++;p2++;}else{if (*p1 != '\0'){distance++;p1++;}if (*p2 != '\0'){distance++;p2++;}}}delete pNodePath[0];delete pNodePath[1];return distance;}int _tmain(int argc, _TCHAR* argv[]){char* pInorder = "abcdefghi";char* pPreorder = "ecbadhfgi";BinaryTreeNode* pRoot = Construct( pPreorder,pInorder,strlen(pInorder) );cout << GetDistanceBetNodes(pRoot, 'a', 'e') <<endl;return 0;}

扩展:

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


原创粉丝点击