樹:二叉樹的公共祖父節點

1.如果這棵二叉樹是二叉查找樹,那麼記錄根節點到x和y節點的路徑問題變得很簡單,藉助於二叉查找樹的性質,藉助BST的查找過程,很簡單便可以做到。

void find1(TreeNode* root,TreeNode* p,vector<TreeNode*> &v)  
{  
     if(root == p)  
     {  
         v.push_back(root);   
         return ;  
     }  
     if(p->val > root->val)  
     {  
         v.push_back(root);  
         find1(root->right,p,v);   
     }   
     else  
     {  
         v.push_back(root);  
         find1(root->left,p,v);   
     }  
}

-------------------------------------------------------------------------------------------


2.若一棵樹是普通的二叉樹,則二叉排序樹在查找方面的特性不能應用。在普通二叉樹中,尋找從根節點到任意節點的路徑不像是在BST中那麼簡單,我們先要解決這個問題。


用vector存儲路徑,然後確定當前節點相同,下一個節點不相同的節點。

bool findP(TreeNode *root,TreeNode *p,vector<TreeNode*> &v)//遞歸查找,路徑記錄在v中  
{  
     if(p==NULL || root == NULL)  
     return false;  
     v.push_back(root);  
     if(root == p)  
     return true;  
     if(root->left != NULL && findP(root->left,p,v) == true )  
     {  
         return true;  
     }  
     if(root->right != NULL && findP(root->right,p,v) == true)  
     {  
        return true;  
     }  
     v.pop_back();//在該子樹上查找失敗,則刪除這個根節點  
     return false;  
}

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)   
{  
      if(root == NULL || p == NULL || q == NULL)  
      {  
              return NULL;  
      }  
      vector<TreeNode *> v1;  
      findP(root,p,v1);  
      vector<TreeNode*> v2;  
      findP(root,q,v2);  
      int len = v1.size()<v2.size()?v1.size():v2.size();  
      int i = 0;  
      for(i = 0;i<len-1;i++)  
      {  
          if(v1[i] == v2[i] && v1[i+1]!=v2[i+1])  
          break;  
      }  
      return v1[i];  
}


-------------------------------------------------------------------------------------------

假如有父親指針:這種情況比較簡單,計算兩個結點的深度,再把深度大的向上移,移到同一深度。在同時向上移動,直到兩個結點相同,這樣便找到了父節點。這個算法時間複雜度爲O(N)。

struct Node  
{  
    int data;  
    Node* left;  
    Node* right;  
    Node* parent;  
    Node() :left(NULL), right(NULL), parent(NULL)  
    {}  
};  
int getDpeth(Node *n)//結點n到根節點深度  
{  
    int count = 0;  
    while (n)  
    {  
        ++count;  
        n = n->parent;  
    }  
    return count;  
}  
Node* findNearestCommonAncestor(Node* n1, Node* n2)  
{  
    int depth1 = getDpeth(n1);  
    int depth2 = getDpeth(n2);  
  
    //移動同一深度  
    while (depth1 > depth2)  
    {  
        n1 = n1->parent;  
        --depth1;  
    }  
    while (depth1 < depth2)  
    {  
        n2 = n2->parent;  
        --depth2;  
    }  
    //向上找  
    while (n1 != n2)  
    {  
        n1 = n1->parent;  
        n2 = n2->parent;  
    }  
    return n1;  
}


2、沒有父指針

首先從根節點開始向下找,如果根節點等於其中一個子節點,那麼根節點便是最近公共父結點。否則計算左子樹和右子樹中包含n1或n2的個數。如果左子樹包含n1、n2那麼最近公共父結點在左子樹,如果右子樹包含n1和n2,那麼在右子樹。如果左右子樹各包含一個,那麼最近公共父結點就是當前結點。如果二叉樹是平衡的,那麼算法複雜度爲O(logN)。最壞情況就是樹成了鏈表,算法時間負責度爲O(N^2)。

int countMatch(Node *current, Node* n1, Node* n2)  
{  
    if (current == NULL)  
        return 0;  
    int count = countMatch(current->left, n1, n2) + countMatch(current->right, n1, n2);  
    if (current == n1 || current == n2)  
        return 1 + count;  
    return count;     
}  
Node* findLCA(Node* root, Node* n1, Node* n2)  
{  
    if (root == NULL)  
        return NULL;  
    if (root == n1 || root == n2)  
        return root;  
    int count = countMatch(root->left, n1, n2);//左子樹包含n1和n2的個數  
    if (count == 1)  
        return root;//左子樹一個,右子樹肯定也有一個  
    else if (count == 2)//都在左子樹  
        return findLCA(root->left, n1, n2);  
    else//都在右子樹  
        return findLCA(root->right, n1, n2);  
}

優化解法:還有一種方法,從下向上找。如果找到n1或n2,就把它傳給它的父結點,如果向下到頭都沒有找到,那麼返回NULL。如果當前結點左右子樹都返回非NULL,那麼當前結點就是最近公共父結點。這樣只需要遍歷一遍,算法時間複雜度爲O(N)。

Node* findLCA(Node *root, Node* n1, Node* n2)  
{  
    if (root == NULL)//沒找到  
        return NULL;  
    if (root == n1 || root == n2)//找到  
        return root;  
    Node* L = findLCA(root->left, n1, n2);//左子樹  
    Node* R = findLCA(root->right, n1, n2);//右子樹  
    //當前結點左右子樹都找到了n1和n2,那麼這個結點就是LCA結點  
    if (L != NULL&R != NULL)  
        return root;  
    //否則是不爲NULL的結點,或者兩個都爲NULL  
    else  
        return L !=NULL ? L : R;  
}

以上

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