算法實現: 在二叉樹中找到兩個節點的最近公共祖先

該題目來自一次面試。。。


/*
在二叉樹中找到兩個節點的最近公共祖先(進階)
給定一棵二叉樹,多次給出這棵樹上的兩個節點 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 <iostream>
#include <cstdlib>
#include <cassert>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;

template<typename T> 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 <typename T> using Node = BinaryTreeNode<T>;


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

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


template<typename T> Node<T>* BinaryTree<T>::AddBinaryTreeNode(const T &parent,const T &lch,const T &rch)
{
    if(lch == 0 && rch == 0)
    {
        return nullptr;
    }
    
    if(_CurrentNodes >= _MaxNodes)
    {
        return nullptr;
    }
    
    //找到父節點
    Node<T>* 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<T>(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<T>(rch);            
            assert(p->rch);
            p->rch->_parent = p;
            _CurrentNodes++;
        }                
    }
    else
    {
        p->rch->_fa = rch;
    }    
        
    return p;
}

template<typename T> Node<T>* BinaryTree<T>::Find(Node<T> *root,const T &x)  
{  
    if(root == nullptr)
    {
        return nullptr;
    }
    
    Node<T>* target = nullptr; 
     
    Node<T>* 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<typename T> void BinaryTree<T>::GetPath(const T &x,std::vector<T> &v)
{
    Node<T>* node = Find(this->_root,x);
    while(nullptr != node && nullptr != (node = node->_parent))
    {
        v.push_back(node->_fa);
    }        
}

template<typename T> const std::tuple<bool,T> BinaryTree<T>::GetPublicAncestor(const T &o1,const T &o2)
{
    std::vector<T> v1,v2;
    GetPath(o1,v1);
    GetPath(o2,v2);    
    
    for(typename std::vector<T>::iterator r1 = v1.begin();r1 != v1.end();++r1)
    {
        typename std::vector<T>::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<typename T> const std::tuple<bool,T> BinaryTree<T>::GetPublicAncestor(const T &o1,std::vector<T> &v)
{
    //實現 略
    return std::make_tuple(true,_root->_fn);
}
        

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

void TestGetPath(int32_t node,BinaryTree<int32_t> &bt)
{
    std::vector<std::int32_t> 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<<endl;
}


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


// 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<int32_t> bt;
    Node<int32_t> *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<std::int32_t> v;
    bt.PrevOrderOutput(root,v);
    for(auto e : v)
    {
        std::cout<<e<<" ";
    }
    std::cout<<endl;
    
    //查找公共父節點
    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);   
                                       
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章