您的位置:首页 > 其它

求两个节点的最近公共祖先多种解法&&判断一个节点是否在二叉树中

2017-04-12 19:26 639 查看
#pragma  once
#include <iostream>
#include <cassert>
#include <stack>
#include <vector>
using namespace std;

template <typename T>
struct TreeNode
{
T _data;              //节点的数据
TreeNode<T>* _left;    //节点的左指针
TreeNode<T>* _right;   //节点的右指针

TreeNode(const T& data = T())
:_data(data)
,_left(NULL)
,_right(NULL)
{}
};

template <typename T>
class BinaryTree
{
public:
typedef TreeNode<T> Node;

BinaryTree()                               //无参构造函数
:_root(NULL)
{}
BinaryTree(T* a,size_t n,const T& invalid)   //构造函数
:_root(NULL)
{
assert(a);
size_t index = 0;
_root = _CreatTree(a,n,index,invalid);
}
~BinaryTree()      //析构函数
{
if (_root)
{
_Destroy(_root);
_root = NULL;
}
}
bool Find(const T& data)      //判断一个值为的节点是否在当前二叉树中
{
return _Find(_root,data);
}
Node* sameAncester(Node* n1,Node* n2)      //求两个节点的最近公共祖先
{
//return _sameAncester1(_root,n1,n2);
//return _sameAncester2(_root,n1,n2);
return _sameAncester3(_root,n1,n2);
}
protected:
Node* _CreatTree(T* a,size_t n,size_t& index,const T& invalid)    //建树
{
Node* root = NULL;
if (a[index] != invalid && index < n)
{
//以递归的方式前序创建二叉树
root = new Node(a[index]);
root->_left = _CreatTree(a,n,++index,invalid);
root->_right = _CreatTree(a,n,++index,invalid);
}
return root;
}
void _Destroy(Node* root)     //毁树
{
if (root)
{
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
root = NULL;
}
}
bool _Find(Node* root,const T& data)    //查找指定数据的节点
{
if (NULL == root)
{
return false;
}
else if (root->_data == data)
{
return true;
}
else
{
bool isIn = false;
if (root->_left && !isIn)
isIn = _Find(root->_left,data);
if (root->_right && !isIn)
isIn = _Find(root->_right,data);
return isIn;
}
}
Node* _sameAncester1(Node*& root,Node* n1,Node* n2)//求两个节点的最近公共祖先(时间复杂度:O(N^2))
{
assert(n1 && n2);
//保证两个节点都在当前树中,且当前树不为空
if (root && Find(n1->_data) && Find(n2->_data))
{
//其中一个节点为根节点,直接返回根节点
if (root->_data == n1->_data || root->_data == n2->_data)
{
return root;
}
//两个节点:1、都在左子树 2、都在右子树 3、一个在左子树,一个在右子树
else
{
Node* cur = root;
//在当前树的左子树去找n1和n2节点,如果没找到就一定在右子树
bool tmp1 = _Find(cur->_left,n1->_data);
bool tmp2 = _Find(cur->_left,n2->_data);
//n1和n2都在左子树
if (tmp1 && tmp2)
{
return _sameAncester1(cur->_left,n1,n2);
}
//n1和n2都在右子树
else if(!tmp1 && !tmp2)
{
return _sameAncester1(cur->_right,n1,n2);
}
//n1与n2一个在左子树一个在右子树
else
{
return root;
}
}
}
return NULL;
}
bool _GetPath2(Node* root,Node* cur,stack<Node*>& s)//在根为root的树中查找节点cur的路径
{
if (NULL == root || NULL == cur)//树为空
return false;
s.push(root);    //将当前节点入栈

if (cur->_data == root->_data)  //找到路径
{
return true;
}
if (_GetPath2(root->_left,cur,s))//在左子树中找路径
{
return true;
}
if (_GetPath2(root->_right,cur,s))//在右子树中找路径
{
return true;
}
s.pop();
return false;
}
Node* _sameAncester2(Node*& root,Node* n1,Node* n2)//求两个节点的最近公共祖先(时间复杂度:O(N))
{
//树为空
if (NULL == root)
{
return NULL;
}
stack<Node*> s1;
stack<Node*> s2;
//用栈s1和s2分别保存节点n1和节点n2的路径
_GetPath2(root,n1,s1);
_GetPath2(root,n2,s2);
//将多余的路径删除
while (s1.size() > s2.size())
{
s1.pop();
}
while(s1.size() < s2.size())
{
s2.pop();
}
//找s1与s2中不同的节点
while(s1.top() != s2.top())
{
s1.pop();
s2.pop();
}
return s1.top();
}
bool _GetPath3(Node* root,Node* cur,vector<Node*>& v)
{
if (NULL == root || NULL == cur)//树为空
return false;
v.push_back(root);

if (cur->_data == root->_data)  //找到路径
{
return true;
}
else
{
bool ret = false;
if (root->_left && !ret)//在左子树中找路径
{
ret = _GetPath3(root->_left,cur,v);
}
if (root->_right && !ret)//在右子树中找路径
{
ret = _GetPath3(root->_right,cur,v);
}
if (ret == false && v.size() != 0)//如果不是正确路径上的节点,就去除该节点
{
v.pop_back();
}
return ret;
}
}
Node* _sameAncester3(Node*& root,Node* n1,Node* n2)
{
//树为空
if (NULL == root)
{
return NULL;
}

//定义容器
vector<Node*> v1;
vector<Node*> v2;

//用容器v1和v2分别保存节点n1和节点n2的路径
_GetPath3(root,n1,v1);
_GetPath3(root,n2,v2);

////从下往上找
////定义指向查找节点的迭代器指针
//vector<Node*>::iterator it1 = --v1.end();
//vector<Node*>::iterator it2 = --v2.end();
////将多余的路径节点删除掉
//while(v1.size() > v2.size())
//{
//  --it1;          //相应的迭代器要向前移
//  v1.pop_back();
//}
//while(v2.size() > v1.size())
//{
//  --it2;          //相应的迭代器要向前移
//  v2.pop_back();
//}

////找v1与v2中不同的节点
//while(it1 >= v1.begin() && it2 >= v2.begin())
//{
//  if (*it1 == *it2)
//  {
//      return *it1;[这里写链接内容](http://m.blog.csdn.net/article/details?id=53672367%20%E2%80%9C%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E2%80%9D)
//  }
//  --it1;
//  --it2;
//}

//从上往下找
//定义指向查找节点的迭代器指针
vector<Node*>::iterator it1 = v1.begin();
vector<Node*>::iterator it2 = v2.begin();
//找v1与v2中不同的节点
while(it1 != v1.end() && it2 != v2.end())
{
if (*it1 != *it2)//找到第一个不相同的节点,返回前一个节点
{
return *(--it1);
}
++it1;
++it2;
}
//处理特殊情况,例如:v1:1->2->3    v2:1->2
if (it1 == v1.end() || it2 == v2.end())
return *(--it1);

return NULL;
}

private:
Node* _root;    //根节点
};

void Test()
{
int a1[] = {1,2,'#',3,'#','#',4,5,'#',6,'#',7,'#','#',8};
int a2 [10] = {1, 2, 3, '#', '#', 4, '#' , '#', 5, 6};
size_t n1 = sizeof(a1)/sizeof(a1[0]);
size_t n2 = sizeof(a2)/sizeof(a2[0]);

BinaryTree<int> bt1(a1,n1,'#');
BinaryTree<int> bt2(a2,n2,'#');
cout<<"2:"<<bt1.Find(2)<<endl;
cout<<"9:"<<bt1.Find(9)<<endl;
cout<<"7:"<<bt2.Find(7)<<endl;
cout<<"6:"<<bt2.Find(6)<<endl;

cout<<bt1.sameAncester(new TreeNode<int>(3),new TreeNode<int>(8))->_data<<endl;//不同子树
cout<<bt1.sameAncester(new TreeNode<int>(3),new TreeNode<int>(2))->_data<<endl;//左边
cout<<bt1.sameAncester(new TreeNode<int>(8),new TreeNode<int>(7))->_data<<endl;//右边
cout<<bt1.sameAncester(new TreeNode<int>(1),new TreeNode<int>(3))->_data<<endl;//其中一个是根

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  namespace 数据