微软等数据结构+算法面试100题(20)--二叉树公共父节点

题目:二叉树的结点定义如下:

struct TreeNode
{
    int m_nvalue;
    TreeNode* m_pLeft;
    TreeNode* m_pRight;
};


输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。

分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。

 

第一变种是二叉树是一种特殊的二叉树:查找二叉树。
也就是树是排序过的,位于左子树上的结点都比父结点小,而位于右子树的结点都比父结点大。

 

/*
第一变种是二叉树是一种特殊的二叉树:查找二叉树。
也就是树是排序过的,位于左子树上的结点都比父结点小,而位于右子树的结点都比父结点大。
*/

/*
二叉排序树插入一个节点
*/
void InsertNode(TreeNode* &root,int value)
{
	if(root==NULL)
	{
		root=new TreeNode(value);
	}
	else
	{
		TreeNode *node=new TreeNode(value);
		TreeNode *p=root;
		while(p)
		{
			if(value>p->data)
			{
				if(p->right!=NULL)
					p=p->right;
				else
				{p->right=node;return;}
			}
			else
			{
				if(p->left!=NULL)
					p=p->left;
				else
				{p->left=node;return;}
			}
		}
	}
}
//创建一个二叉查找树
void MakeSearchTree(TreeNode* &root)
{
	int value=0;
	while(cin>>value)
		InsertNode(root,value);
}
/*
将数组中的数插入到二叉排序树中
*/
void MakeSearchTree(TreeNode* &root,int p[],int len)
{
	for(int i=0;i<len;i++)
		InsertNode(root,p[i]);
}

/*
测试生成的二叉排序树
*/
void MakeSearchTreeTest()
{
	TreeNode* root=NULL;
	cout<<"make search tree "<<endl;
	MakeSearchTree(root);
	cout<<"the tree : "<<endl;
	MidOrderTraverse(root);
	cout<<endl;
	cout<<"the tree : "<<endl;
	LevelOrderTraverse1(root);
	cout<<endl;
}

//在二叉查找树中查找等于value的节点。
TreeNode* FindNode(TreeNode* root,int value)
{
	if(root==NULL)
		return NULL;
	while(root!=NULL)
	{
		if(root->data==value)
			return root;
		else if(root->data>value)
			root=root->left;
		else
			root=root->right;
	}
	return NULL;
}
//在二叉查找树中查找node1和node2的公共父节点
TreeNode* CommonParent(TreeNode* root,TreeNode* node1,TreeNode* node2)
{
	int value1=node1->data,value2=node2->data;

	while(root!=NULL)
	{
		if((root->data>value1)&&(root->data>value2))
			root=root->left;
		else if((root->data<value1)&&(root->data<value2))
			root=root->right;
		else
			return root;
	}
	return NULL;
}

void CommonParentTest()
{
	int p[]={8,4,15,2,6,10,19,1,3,5,7,9,17,18,25};
	cout<<"nodes  : ";
	int len=sizeof(p)/sizeof(int);
	ShowArray(p,len);

	TreeNode* root=NULL;
	cout<<"make search tree "<<endl;
	MakeSearchTree(root,p,len);
	cout<<"the tree : "<<endl;
	MidOrderTraverse(root);
	cout<<endl;
	cout<<"the tree : "<<endl;
	LevelOrderTraverse1(root);
	cout<<endl;

	cin.clear();
	int value=0;
	cout<<"node1 value : ";
	cin>>value;
	TreeNode *node1=FindNode(root,value);
	cout<<"node2 value : ";
	cin>>value;
	TreeNode *node2=FindNode(root,value);
	cout<<"find common parent : "<<endl;
	TreeNode *node=CommonParent(root,node1,node2);
	cout<<"common parent : "<<node->data<<endl;
	cout<<"parent left chilren : "<<node->left->data<<endl;
	cout<<"parent right chilren : "<<node->right->data<<endl;
}


第二个变种是树不一定是二叉树,每个结点都有一个指针指向它的父结点。于是我们可以从任何一个结点出发,
得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点。

 

如果不是这两种特殊情况,二是一般的二叉树,如何求两个节点的公共父节点?

 

方法一:

/*
判断node是不是在以root为根节点的树中
*/
bool IsInTree(TreeNode* root,TreeNode* node)
{
	if(root==node)
		return true;
	bool found=false;
	if(root->left!=NULL)
		found=IsInTree(root->left,node);
	if(!found&&root->right)
		found=IsInTree(root->right,node);
	return found;
}
//求node1和node2的公共父节点
TreeNode* GetCommonParent(TreeNode* root,TreeNode* node1,TreeNode* node2)
{
	if(root==NULL)
		return NULL;
	bool node1left=IsInTree(root->left,node1);
	bool node2left=IsInTree(root->left,node2);
	bool node1right=IsInTree(root->right,node1);
	bool node2right=IsInTree(root->right,node2);
	if((node1left&&node2right)||(node1right&&node2left))
		return root;
	if(node1left&&node2left)
		return GetCommonParent(root->left,node1,node2);
	if(node1right&&node2right)
		return GetCommonParent(root->right,node1,node2);
}


方法二:

 

//求出root到node的路径,root为根的树中没有node时。返回false
bool GetNodePath(TreeNode* root,TreeNode* node,vector<int> &path)
{
	if(root==node)
		return true;
	path.push_back(root->data);
	bool found=false;
	if(root->left!=NULL)
		found=GetNodePath(root->left,node,path);
	if(!found&&root->right!=NULL)
		found=GetNodePath(root->right,node,path);
	if(!found)
		path.pop_back();
	return found;
}
//在一个二叉树中找到节点等于value的node节点
TreeNode* FindTreeNode(TreeNode* root,int value)
{
	if(root->data==value)
		return root;
	TreeNode *res=NULL;
	if(root->left!=NULL)
		res=FindTreeNode(root->left,value);
	if(res==NULL&&root->right!=NULL)
		res=FindTreeNode(root->right,value);
	return res;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值