算法实现: 在二叉树中找到两个节点的最近公共祖先

该题目来自一次面试。。。


/*
在二叉树中找到两个节点的最近公共祖先(进阶)
给定一棵二叉树,多次给出这棵树上的两个节点 o1 和 o2,请对于每次询问,找到 o1 和 o2 的最近公共祖先节点。
输入描述
第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。
以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)
第 n+2 行输入一个整数 m,表示询问的次数。
以下 m 行每行两个节点 o1 和 o2。
输出描述
对于每组询问每行输出一个整数表示答案。
示例1
输入
8 1
1 2 3
2 4 5
4 0 0
5 0 0
3 6 7
6 0 0
7 8 0
8 0 0
4
4 5
5 2
6 8
5 8

输出
2
2    这里貌似有错误,2,5的共同祖先应该是 1
3
1
*/

#include
#include
#include
#include
#include
#include
using namespace std;

template struct BinaryTreeNode{
    T _fa;
    BinaryTreeNode *lch,*rch;
    //指向父节点,root->nullptr
    BinaryTreeNode *_parent;
    BinaryTreeNode(const T &data):_fa(data),lch(nullptr),rch(nullptr),_parent(nullptr)
    {
        //
    }
    
    ~BinaryTreeNode()
    {
        delete lch;
        lch = nullptr;
        delete rch;
        rch = nullptr;
    }
};

template using Node = BinaryTreeNode;


template class BinaryTree
{
public:
    Node *_root;
    int32_t _MaxNodes = 0;
    int32_t _CurrentNodes = 0;
    BinaryTree():_root(nullptr)
       {
       //
    }
    
    Node* CreateBinaryTree(int32_t MaxNodes,const T &RootData);
    
    Node* AddBinaryTreeNode(const T &parent,const T &lch,const T &rch);
    
    Node* Find(Node *root,const T &x);
    
    void GetPath(const T &x,std::vector &v);
    
    const std::tuple GetPublicAncestor(const T &o1,std::vector &v);        
    const std::tuple GetPublicAncestor(const T &o1,const T &o2);
    
    void PrevOrderOutput(const Node *root,std::vector &v);
};

template Node* BinaryTree::CreateBinaryTree(int32_t MaxNodes,const T &RootData)
{
    Node* root = new BinaryTreeNode(RootData);
    assert(root != nullptr);   
    this->_root = root;
    _MaxNodes = MaxNodes;
    return root;
}


template Node* BinaryTree::AddBinaryTreeNode(const T &parent,const T &lch,const T &rch)
{
    if(lch == 0 && rch == 0)
    {
        return nullptr;
    }
    
    if(_CurrentNodes >= _MaxNodes)
    {
        return nullptr;
    }
    
    //找到父节点
    Node* p = Find(this->_root,parent);
    if(p == nullptr)
    {
        return nullptr;
    }
    
    //update or add left node
    if(p->lch == nullptr)
    {
        if(lch != 0)
        {
            p->lch = new BinaryTreeNode(lch);            
            assert(p->lch);
            p->lch->_parent = p;
            _CurrentNodes++;            
        }                
    }
    else
    {
        p->lch->_fa = lch;
    }
    
     //update or add right node
    if(p->rch == nullptr)
    {
        if(rch != 0)
        {
            p->rch = new BinaryTreeNode(rch);            
            assert(p->rch);
            p->rch->_parent = p;
            _CurrentNodes++;
        }                
    }
    else
    {
        p->rch->_fa = rch;
    }    
        
    return p;
}

template Node* BinaryTree::Find(Node *root,const T &x)  
{  
    if(root == nullptr)
    {
        return nullptr;
    }
    
    Node* target = nullptr; 
     
    Node* cur = root;   
    if (cur->_fa == x)  
    {  
        target = cur;  
    }  
    else  
    {  
        target = cur->lch == nullptr ? nullptr : Find(cur->lch,x);
        if (target == nullptr)  
        {  
            target = cur->rch == nullptr ? nullptr : Find(cur->rch,x);  
        }  
    }  
    return target;
}

template void BinaryTree::GetPath(const T &x,std::vector &v)
{
    Node* node = Find(this->_root,x);
    while(nullptr != node && nullptr != (node = node->_parent))
    {
        v.push_back(node->_fa);
    }        
}

template const std::tuple BinaryTree::GetPublicAncestor(const T &o1,const T &o2)
{
    std::vector v1,v2;
    GetPath(o1,v1);
    GetPath(o2,v2);    
    
    for(typename std::vector::iterator r1 = v1.begin();r1 != v1.end();++r1)
    {
        typename std::vector::iterator r2 = std::find(v2.begin(),v2.end(),*r1);
        if(r2 != v2.end())
        {
            return std::make_tuple(true,*r2);
        }
    }
    
    T Value;
    return std::make_tuple(false,Value);
}

//通过传入第一个节点列表, 再查找遍历过程中判断,感觉接口侵入性太强
template const std::tuple BinaryTree::GetPublicAncestor(const T &o1,std::vector &v)
{
    //实现 略
    return std::make_tuple(true,_root->_fn);
}
        

template void BinaryTree::PrevOrderOutput(const Node *root,std::vector &v)
{
    if (root != nullptr)
    {
        v.push_back(root->_fa);
        PrevOrderOutput(static_cast*>(root->lch),v);
        PrevOrderOutput(static_cast*>(root->rch),v);
    }
}

void TestGetPath(int32_t node,BinaryTree &bt)
{
    std::vector v;
    bt.GetPath(node,v);
    std::cout << "node " << node << " path size :" << v.size() << " list is :"; 
    for_each(v.begin(),v.end(),[](int32_t i){ std::cout << i << " "; });
    std::cout< }


void TestGetPublicAncestor(int32_t o1,int32_t o2,BinaryTree &bt)
{
    std::tuple ancestor = bt.GetPublicAncestor(o1,o2);
    if(std::get<0>(ancestor))
    {
        std::cout<< o1 << "," << o2 << " ancestor is :" << std::get<1>(ancestor) <     }
    else
    {
         std::cout<< o1 << "," << o2 << " ancestor is : root nullptr" <     }
}


// g++ binary_tree.cpp -g -o binary_tree
// CentOS Linux release 8.1.1911 (Core) 
// gcc (GCC) 8.3.1 20190507 (Red Hat 8.3.1-4)

int32_t main(int32_t argc, char *argv[])
{
    //构建二叉树
    /**********************************
                  1
            2           3
         4     5     6      7 
                        8
    ***********************************/ 
    BinaryTree bt;
    Node *root = bt.CreateBinaryTree(8,1);
    bt.AddBinaryTreeNode(1,2,3);
    bt.AddBinaryTreeNode(2,4,5);
    bt.AddBinaryTreeNode(4,0,0);
    bt.AddBinaryTreeNode(5,0,0);
    bt.AddBinaryTreeNode(3,6,7);
    bt.AddBinaryTreeNode(6,0,0);
    bt.AddBinaryTreeNode(7,8,0);
    bt.AddBinaryTreeNode(8,0,0);
    
    //验证树结构
    std::vector v;
    bt.PrevOrderOutput(root,v);
    for(auto e : v)
    {
        std::cout<     }
    std::cout<     
    //查找公共父节点
    TestGetPublicAncestor(4,5,bt);
    TestGetPublicAncestor(5,2,bt);
    TestGetPublicAncestor(6,8,bt);
    TestGetPublicAncestor(5,8,bt);
    TestGetPublicAncestor(1,8,bt);
    
     
    //验证获取父节点功能
    TestGetPath(5,bt);    
    TestGetPath(8,bt);
    TestGetPath(1,bt);
    TestGetPath(7,bt);   
                                       
}


 

你可能感兴趣的:(二叉树,c++)