#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
/*
问题:设计并实现一个算法,找出二叉树中某两个结点的第一个共同祖先。不得将额外的结点储存在另外的数据结构中。
注意:这不一定是二叉查找树。
分析:一种方式是根据结点,向上遍历,得到从当前结点到根节点的一个链表,设长链表的长度为L1,设短链表的长度为L2,
将两个链表中较长的链表先走L1-L2步,然后寻找共同结点。
问题中说明:不得将结点额外存储。而采用链表的方式是需要额外存储结构的。如果不能用额外存储结构只能用这样的方式。
O(n^2)方法,设两个结点分别为n1,n2,
遍历n1,设当前结点为c,如果n1!=n2,令n2=n2->parent,
输入:
7(元素个数) 2(待寻找共同祖先的第一个结点的值) 5(待寻找共同祖先的第二个结点的值)
6 3 9 1 4 2 5(所有各个结点的值)
d(表示当前第1个结点有两个孩子,后续跟两个孩子结点下标) 2 3
d 4 5
z(表示当前第i个结点没有孩子结点)
r(表示当前第i个结点只有一个右孩子结点,后面跟该右孩子结点下标) 6
r 7
z
z
7 2 9
6 3 9 1 4 2 5
d 2 3
d 4 5
z
r 6
r 7
z
z
输出:
3(共同祖先的值,如果没有,返回NULL)
6
*/
typedef struct TreeNode
{
TreeNode* _pLeft;
TreeNode* _pRight;
TreeNode* _pParent;
int _value;
}TreeNode;
const int MAXSIZE = 10000;
int g_index;
TreeNode g_treeNodeArray[MAXSIZE];
TreeNode* createTreeNode()
{
++g_index;
g_treeNodeArray[g_index]._pLeft = g_treeNodeArray[g_index]._pRight = g_treeNodeArray[g_index]._pParent = NULL;
return &g_treeNodeArray[g_index];
}
//建树
void buildTree(vector<int>& vecData)
{
int size = vecData.size();
g_index = 0;
if(vecData.empty())
{
return;
}
string childFlag;
int leftChild, rightChild;
for(int i = 1 ; i <= size ; i++ )
{
cin >> childFlag;
g_treeNodeArray[i]._value = vecData.at(i-1);
if("d" == childFlag)
{
cin >> leftChild >> rightChild;
g_treeNodeArray[i]._pLeft = &g_treeNodeArray[leftChild];
g_treeNodeArray[leftChild]._pParent = &g_treeNodeArray[i];
g_treeNodeArray[i]._pRight = &g_treeNodeArray[rightChild];
g_treeNodeArray[rightChild]._pParent = &g_treeNodeArray[i];
}
else if("r" == childFlag)
{
cin >> rightChild;
g_treeNodeArray[i]._pRight = &g_treeNodeArray[rightChild];
g_treeNodeArray[rightChild]._pParent = &g_treeNodeArray[i];
}
else if("l" == childFlag)
{
cin >> leftChild;
g_treeNodeArray[i]._pLeft = &g_treeNodeArray[leftChild];
g_treeNodeArray[leftChild]._pParent = &g_treeNodeArray[i];
}
}
}
//根据结点值找到指定结点,如果同时出现多个结点的值与给定值相同,就返回最先找到的结点
TreeNode* findNode(TreeNode* head , int value)
{
if(NULL == head)
{
return NULL;
}
if(value == head->_value)
{
return head;
}
TreeNode* leftChild = NULL;
TreeNode* rightChild = NULL;
if(head->_pLeft)
{
leftChild = findNode(head->_pLeft , value);
}
//在左子树找到,就直接返回结果;否则,递归查找右子树
if(leftChild != NULL)
{
return leftChild;
}
else
{
if(head->_pRight)
{
return findNode(head->_pRight , value);
}
else
{
return NULL;
}
}
}
//寻找根节点
TreeNode* findRoot(TreeNode* node)
{
if(NULL == node)
{
return NULL;
}
if(NULL == node->_pParent)
{
return node;
}
else
{
return findRoot(node->_pParent);
}
}
//寻找两个结点的最近公共祖先,不使用额外的数据结构存放结点
TreeNode* findCommonAncestor(TreeNode* node1 , TreeNode* node2)
{
TreeNode* tempNode2 = node2;
TreeNode* tempNode1 = node1;
while(tempNode2)
{
//遍历第一个结点链表,看是否找到与当前结点相同的结点
while(tempNode1)
{
if(tempNode1->_value == tempNode2->_value)
{
return tempNode1;
}
else
{
tempNode1 = tempNode1->_pParent;
}
}
//到这里就是把结点1所在链表的所有结点都遍历完,且没有找到共同祖先,此时就应该使得结点2等于结点2的父节点
tempNode2 = tempNode2->_pParent;
tempNode1 = node1;
}
//如果最终没有找到共同祖先,返回空
return NULL;
}
void process()
{
int nodeNum ;
int firstValue;
int secondValue;
int value;
vector<int> vecData;
while(cin >> nodeNum >> firstValue >> secondValue)
{
vecData.clear();
for(int i = 0 ; i < nodeNum ; i++)
{
cin >> value;
vecData.push_back( value );
}
//输入完成接下来需要建树
buildTree(vecData);
//建树完成后,就是寻找共同父节点
TreeNode* root = findRoot(&g_treeNodeArray[1]);
TreeNode* node1 = findNode(root , firstValue);
TreeNode* node2 = findNode(root , secondValue);
TreeNode* ancestorNode = findCommonAncestor(node1 , node2);
if(ancestorNode)
{
cout << ancestorNode->_value << endl;
}
else
{
cout << "NULL" << endl;
}
}
}
int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}