问题11:求二叉树的镜像
递归解法:
(1)如果二叉树为空,返回空
(2)如果二叉树非空,分别求左子树和右子树的镜像,然后交换左右子树
BinaryTreeNode* Mirror(BinaryTreeNode* pRoot)
{
if(pRoot==NULL)
return NULL;
BinaryTreeNode* pLeft=Mirror(pRoot->m_pLeft);//求左子树镜像
BinaryTreeNode* pRight=Mirror(pRoot->m_pRight);//求右子树镜像
//交换左右子树
pRoot->m_pLeft=pRight;
pRoot->m_pRight=pLeft;
return pRoot;
}
问题12:求二叉树中两个节点的最低公共祖先
递归解法:
(1)如果两个节点分别在左子树和右子树,返回根节点
(2)如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树
bool FindNode(BinaryTreeNode* pRoot,BinaryTreeNode* pNode)
{
if(pRoot==NULL ||pNode==NULL)
return false;
if(pRoot==pNode)
return true;
bool Found=FindNode(pRoot->m_pLeft,pNode);
if(!Found)
Found=FindNode(pRoot->m_pRight,pNode);
return Found;
}
BinaryTreeNode* GetLastCommonParent(BianryTreeNode* pRoot,BinaryTreeNode* pNode1,BinaryTreeNode* pNode2)
{
if(FindNode(pRoot->m_pLeft,pNode1))
{
if(FindNode(pRoot->m_pRight,pNode2))
return pRoot;
else
{
return GetLastCommonParent(pRoot->m_pLeft,pNode1,pNode2);
}
}
else
{
if(FindeNode(pRoot->m_pLeft,pNode2))
return pRoot;
else
{
return GetLastCommonParent(pRoot->m_pRight,pNode1,pNode2);
}
}
}
递归解法效率低,有很多重复的遍历。
非递归解法:
首先求根节点到两个节点的路径,然后比较两个路径中的节点,
最后一个相同的节点就是二叉树中两个节点的最低公共祖先
bool FindPath(BinaryTreeNode* pRoot,BinaryTreeNode* pNode,list<BinaryTreeNode*> &path)
{
if(pRoot==NULL)
return false;
if(pRoot==pNode)
{
path.push_back(pRoot);
return true;
}
path.push(pRoot);
bool Found=false;
Found=FindPath(pRoot->m_pLeft,pNode,path);
if(!Found)
Found=FindPath(pRoot->m_pRight,pNode,path);
if(!Found)
path.pop_back();
return Found;
}
BinaryTreeNode* GetLastCommonParent(BinaryTreeNode* pRoot,BinaryTreeNode* pNode1,BianryTreeNode* pNode2)
{
if(pRoot==NULL||pNode1==NULL||pNode2==NULL)
return NULL:
list<BinaryTreeNode*> path1,path2;
bool FoundLeft=FindPath(pRoot,pNode1,path1);
bool FoundRight=FindPath(pRoot,pNode2,path2);
BinaryTreeNode* pLast=NULL;
if(FondLeft && FoundRight)
{
list<BinaryTreeNode*>::const_iterator iter1=path1.begin();
list<BinaryTreeNode*>::const_iterator iter2=path2.begin();
while(iter1!=path1.end() &&iter2!=path2.end())
{
if(*iter1==*iter2)
{
pNode=*iter;
iter1++;
iter2++;
}
else
break;
}
return pNode;
}
return NULL;
}
问题13:求二叉树节点的最大距离
即二叉树中相距最远的两个节点之间的距离
递归解法:
(1)如果二叉树为空,返回0,同时记录左子树和右子树的深度都为0
(2)如果二叉树不为空,最大距离要么是左子树中两个节点间的最大距离,要么是右子树中两节点间的最大距离,要么是左子树到根节点的最大距离+右子树到根节点的最大距离,同时记录左子树和右子树中节点到根节点的最大距离
int GetMaxDistance(BinaryTreeNode* pRoot,int& maxLeft,int& maxRight)
{
//maxLeft为左子树中距离根节点的最远距离
//maxRight为右子树中距离根节点的最远距离
if(pRoot==NULL)
{
maxLeft=0;
maxRight=0;
return 0;
}
int maxLL,maxLR,maxRL,maxRR;
int maxDistLeft,maxDistRight;
if(pRoot->m_pLeft!=NULL)
{
maxDistLeft=GetMaxDistance(pRoot->m_pLeft,maxLL,maxLR);
maxLeft=max(maxLL,maxLR)+1;
}
else
{
maxDistLeft=0;
maxLeft=0;
}
if(pRoot->m_pRight!=NULL)
{
maxDistRight=GetMaxDistance(pRoot->m_pRight,maxRL,maxRR);
maxRight=max(maxRL,maxRR)+1;
}
else
{
maxDistRight=0;
maxRight=0;
}
return max(max(maxLeft,maxRight),maxDistLeft+maxDistRight);
}
问题14:由前序遍历和中序遍历重建二叉树
二叉树的谦虚遍历中,第一元素总是树的根节点的值。中序遍历序列中,位于根节点左边的数为树的左子树节点,
位于根节点的右边的数为树的右子树节点
递归解法:
(1)如果前序遍历或者中序遍历为空,或者节点个数小于等于0,返回空
(2)创建根节点。前序遍历中的第一个数为根节点,在中序遍历中找到根节点的位置,可分别得到左子树和右子树的前序遍历和中序遍历,重建左右子树
BinaryTreeNode* ReBuildBinaryTree(int *pPreOrder,int *pInOrder,int NodeNum)
{
if(pPreOrder==NULL||pInOrder==NULL || NodeNum<=0)
return NULL;
BinaryTreeNode* pRoot=new BinaryTreeNode;
pRoot->m_nValue=pPreOrder[0];
pRoot->m_pLeft=NULL;
pRoot->m_pRight=NULL;
//在中序遍历序列中找到根节点的位子,根节点左边的节点为左子树,右边的数为右子树
int rootPoistionInOrder=-1;
for(int i=0;i<NodeNum;i++)
{
if(pPreOreder[0]==pInOreder[i])
{
rootPositionInOrder=i;
break;
}
}
if(rootPostionInOrder==-1)
throw std::exception("Invalid input");
//重建左子树
int nodeNumLeft=rootPositionInOrder;
int* pPreOrderLeft=pPreOrder+1;
int* pInOrderLeft=pInOrder;
pRoot->m_pLeft=ReBuildBinaryTree(pPreOrderLeft,pInOrderLeft,nodeNumLeft);
//重建右子树
int nodeNumRight=NodeNum-rootPositionInOrder-1;
int* pPreOrderRight=pPreOrder+rootPositionInOrder+1;
int* pInOrderRight=pInOrder+rootPositionInOrder+1;
pRoot->m_Right=ReBuildBinaryTree(pPreOrderRight,pInOrderRight,nodeNumRight);
return pRoot;
}
问题15:判断二叉树是不是完全二叉树 ( 有点难)
若二叉树的深度为h,则除第h层外,其他层(1~h-1)的节点都达到了最大个数
在第h层,所有的节点都连续集中在最左边,这就是完全二叉树
如下算法:按层遍历(从上到下,从左到右)二叉树,若遇到二叉树左子树为空,则右子树必须为空,如后续遍历左右子树不为空,则不是完全二叉树
bool IsCompleteBinaryTree(BinaryTreeNode* pRoot)
{
if(pRoot==NULL)
return false;
queue<BinaryTreeNode*> q;
q.push(pRoot);
bool mustHaveNoChild=false;
bool result=true;
while(!q.empty())
{
BinaryTreeNode* pNode=q.front();
q.pop();
if(!mustHaveNoChild)//已经出现了空子树节点,后面出现的必须为叶子节点(左右子树为空)
{
if(pNode->m_pLeft!=NULL &&pNode->m_pRight!=NULL)
{
result=false;
break;
}
}
else
{
if(pNode->m_pLeft!=NULL && pNode->m_pRight!=NULL)
{
q.push(pNode->m_pLeft);
q.push(pNode->m_pRight);
}
else if(pNode->m_pLeft!=NULL &&pNode->m_pRight==NULL)
{
mustHaveNoChild=true;
q.push(pNode->m_pLeft);
}
else if(pNode->m_pLeft==NULL && pNode->m_pRight!=NULL)
{
result=false;
break;
}
else
{
mustHaveNoChild=true;
}
}
}
return result;
}