温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

树:二叉树的公共祖父节点

发布时间:2020-09-24 19:05:41 来源:网络 阅读:945 作者:q381989042 栏目:编程语言

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 depth2 = getDpeth(n1);  
    int depth3 = getDpeth(n2);  
  
    //移动同一深度  
    while (depth2 > depth3)  
    {  
        n1 = n1->parent;  
        --depth2;  
    }  
    while (depth2 < depth3)  
    {  
        n2 = n2->parent;  
        --depth3;  
    }  
    //向上找  
    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;  
}

以上

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI