已知在二叉链表表示的二叉树中,root为根结点,p,q,为二叉树中两个结点,试编写算法求距离他们最近的共同祖先
先举几个实例来分析一下
得出结论:1.当这两个节点在某个节点的左右子树中时,这个节点为这两个节点的最近共同祖先。2.其中一个节点为另一个节点的祖先的情况,那么这个节点的双亲就是他俩的最近共同祖先。
不管是哪种情况,都需要判断的是,一个节点是否为某一节点的子孙。
假设两个节点分别为节点A,节点B。当前节点为C
分别计算C结点左子树,右子树中节点A,B存在的个数。若左子树中节点个数=右子树中节点个数=1,那么当前结点即为最近祖先。如果左子树中节点个数=2,判断左子树根节点是否为节点A,B中的一个,如果是,那么当前结点C即为最近公共祖先。如果不是,递归,当前结点C变为C的左孩子。右子树同理。
评价:感觉好麻烦啊,一点也不简洁优雅,代码都懒得敲了
遍历左子树和右子树,假如左子树中含有A,那么返回A.含有B,则返回B。看哪个子树返回了节点就继续遍历哪个子树。如果左右子树都返回节点,那么这个就是最近公共祖先。
注意这里必须用scanf才能读入空格,不能用cin
nodePtr create()
{
char ch;
nodePtr a;
scanf("%c",&ch);
if(ch == ' ')
{
return NULL;
}
else
{
a = new node;
a->ch = ch;
a->left = create();
a->right = create();
return a;
}
}
void traverse(nodePtr a, char p, char q, int &k)
{
if(a == NULL)
{
return;
}
else
{
if(a->ch == p || a->ch == q)
{
k++;
}
traverse(a->left, p, q, k);
traverse(a->right, p, q, k);
}
}
如果当前结点为节点中的一个,那么当前结点为最近公共祖先。如果当前结点左右子树中各有一个节点,那么当前结点为最近公共祖先。如果两个节点都在当前结点的左子树或者右子树中,那么他们的最近公共祖先可能在左子树或者右子树中。递归寻找即可
nodePtr find(nodePtr a, char p, char q)
{
int left = 0, right = 0;
traverse(a->left, p, q, left);//找到左子树中节点个数
traverse(a->right, p, q, right);//找到右子树中节点个数
cout<<"left:"<<left<<endl;
cout<<"right:"<<right<<endl;
if(a->ch == p || a->ch == q)//如果当前结点为其中一个
{
return a;//返回当前结点
}
else if(left == right)//如果当前结点左右子树各有一个节点,返回当前结点
{
return a;
}
else
{
//如果两个节点都在左子树中,那么在左子树中找,反之,在右子树中找
if(left == 2)
{
find(a->left, p, q);
}
else
{
find(a->right, p, q);
}
}
}
#include
#include
using namespace std;
typedef struct node{
char ch;
struct node *left;
struct node *right;
}node, *nodePtr;
nodePtr create();//创建一棵二叉树
nodePtr find(nodePtr a, char p, char q);//找a树中p,q的最近祖先
void traverse(nodePtr a, char p, char q, int &k);//遍历a树,看有没有p,q
void print(nodePtr a);//打印二叉树
void destroy(nodePtr a);//删除二叉树
int main()
{
nodePtr a = create();//创建二叉树
char p, q;
cin>>p;
cin>>q;
nodePtr b = find(a, p, q);//找a树中p,q的最近祖先
cout<<b->ch;
destroy(a);//释放空间
return 0;
}
nodePtr create()
{
char ch;
nodePtr a;
scanf("%c",&ch);
if(ch == ' ')
{
return NULL;
}
else
{
a = new node;
a->ch = ch;
a->left = create();
a->right = create();
return a;
}
}
nodePtr find(nodePtr a, char p, char q)
{
int left = 0, right = 0;
traverse(a->left, p, q, left);//找到左子树中节点个数
traverse(a->right, p, q, right);//找到右子树中节点个数
cout<<"left:"<<left<<endl;
cout<<"right:"<<right<<endl;
if(a->ch == p || a->ch == q)//如果当前结点为其中一个
{
return a;//返回当前结点
}
else if(left == right)//如果当前结点左右子树各有一个节点,返回当前结点
{
return a;
}
else
{
//如果两个节点都在左子树中,那么在左子树中找,反之,在右子树中找
if(left == 2)
{
find(a->left, p, q);
}
else
{
find(a->right, p, q);
}
}
}
void traverse(nodePtr a, char p, char q, int &k)
{
if(a == NULL)
{
return;
}
else
{
if(a->ch == p || a->ch == q)
{
k++;
}
traverse(a->left, p, q, k);
traverse(a->right, p, q, k);
}
}
void print(nodePtr a)
{
if(a == NULL)
{
cout<<" ";
return ;
}
else
{
cout<<a->ch;
print(a->left);
print(a->right);
}
}
void destroy(nodePtr a)
{
if(a == NULL)
{
return;
}
else
{
destroy(a->left);
destroy(a->right);
delete a;
}
}
/*
1.ABDH EI CF GJ |
*/