日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序员面试100题之十六:二叉树中两个节点的最近公共父节点(最低的二叉树共同祖先)

發布時間:2024/7/5 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员面试100题之十六:二叉树中两个节点的最近公共父节点(最低的二叉树共同祖先) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這個問題可以分為三種情況來考慮:
情況一:root未知,但是每個節點都有parent指針

此時可以分別從兩個節點開始,沿著parent指針走向根節點,得到兩個鏈表,然后求兩個鏈表的第一個公共節點,這個方法很簡單,不需要詳細解釋的。

情況二:節點只有左、右指針,沒有parent指針,root已知
思路:有兩種情況,一是要找的這兩個節點(a, b),在要遍歷的節點(root)的兩側,那么這個節點就是這兩個節點的最近公共父節點;

二是兩個節點在同一側,則 root->left 或者 root->right 為 NULL,另一邊返回a或者b。那么另一邊返回的就是他們的最小公共父節點。

遞歸有兩個出口,一是沒有找到a或者b,則返回NULL;二是只要碰到a或者b,就立刻返回。

  • // 二叉樹結點的描述
  • typedef struct BiTNode
  • {
  • char data;
  • struct BiTNode lchild, rchild; // 左右孩子
  • }BinaryTreeNode;
  • // 節點只有左指針、右指針,沒有parent指針,root已知
  • BinaryTreeNode findLowestCommonAncestor(BinaryTreeNode root , BinaryTreeNode* a , BinaryTreeNode* b)
  • {
  • if(root == NULL)
  • return NULL;
  • if(root == a || root == b)
  • return root;
  • BinaryTreeNode* left = findLowestCommonAncestor(root->lchild , a , b);
  • BinaryTreeNode* right = findLowestCommonAncestor(root->rchild , a , b);
  • if(left && right)
  • return root;
  • return left ? left : right;
  • }

  • 情況三: 二叉樹是個二叉查找樹,且root和兩個節點的值(a, b)已知
  • // 二叉樹是個二叉查找樹,且root和兩個節點的值(a, b)已知
  • BinaryTreeNode* findLowestCommonAncestor(BinaryTreeNode* root , BinaryTreeNode* a , BinaryTreeNode* b)
  • {
  • char min , max;
  • if(a->data < b->data)
  • min = a->data , max = b->data;
  • else
  • min = b->data , max = a->data;
  • while(root)
  • {
  • if(root->data >= min && root->data <= max)
  • return root;
  • else if(root->data < min && root->data < max)
  • root = root->rchild;
  • else
  • root = root->lchild;
  • }
  • return NULL;
  • }






  • 1、二叉樹定義:

  • typedef struct BTreeNodeElement_t_ {
  • void *data;
  • } BTreeNodeElement_t;
  • typedef struct BTreeNode_t_ {
  • BTreeNodeElement_t *m_pElemt;
  • struct BTreeNode_t_ *m_pLeft;
  • struct BTreeNode_t_ *m_pRight;
  • } BTreeNode_t;


  • 2、查找二叉樹中兩個節點的最低祖先節點(或最近公共父節點等)

    ? ? 最低祖先節點就是從根節點遍歷到給定節點時的最后一個相同節點

    例如:

    ? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? ? ??? ??A

    ? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??B? ??? ??? ??? ??? ??? ? ? ??? ??? ??? ??? ??C

    ? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? D? ??? ??? ??? ??? ??? ? E? ??? ??? ??? ??? ???F? ??? ??? ??? ??? ??? ??? ??? ? G

    ? ??? ??? ??? ??? ??? ??? ??? ??? ? H? ??? ??? ? I? ??? ??? ? J? ??? ??? ? K? ??? ? L? ??? ? M? ??? ??? ??? ??? ??? ? N? ? O

    如上圖,H和J的最低祖先節點是B。

    因為從根節點A到H的鏈路為: ? A ? ? B ? ?D ? H

    從根節點A到J的鏈路為: ? A ? B ? ?E ? J

    查看鏈路節點可知,B是最后一個相同節點,也就是所謂的最近公共父節點或者說最低祖先節點。


    (1)遞歸方式

    如果給定pRoot是NULL,即空樹,則返回的公共節點自然就是NULL;

    如果給定pRoot與兩個節點中任何一個相同,說明,pRoot在就是所要找的兩個節點之一,則直接返回pRoot,表明在當前鏈路中找到至少一個節點;

    如果給定pRoot不是兩個節點中任何一個,則說明,需要在pRoot的左右子樹中重新查找,此時有三種情況:兩個節點都在左子樹上;兩個節點都在右子樹上;一個在左子樹,一個在右子樹上;具體來說,就是:

    ? ??? ? 情況一:如果左子樹查找出的公共節點是NULL,則表明從左子樹根節點開始到左子樹的所有葉子節點等所有節點中,沒有找到兩個節點中的任何一個,這就說明,這兩個節點不在左子樹上,不在左子樹,則必定在右子樹上;

    ? ??? ?情況二:如果右子樹查找的公共節點是NULL,說明在右子樹中無法找到任何一個節點,則兩個節點必定在左子樹上;

    ? ? ? ?情況三: 如果左右子樹查找的公共節點都不是NULL,說明左右子樹中各包含一個節點,則當前節點pRoot就是最低公共節點,返回就可以了。

    ? ? ? ?三種情況是互斥的, 只能是其中之一。

  • BTreeNode_t *GetLastCommonParent( BTreeNode_t *pRoot, BTreeNode_t *pNode1, BTreeNode_t *pNode2){
  • if( pRoot == NULL ) //說明是空樹,不用查找了,也就找不到對應節點,則返回NULL
  • return NULL;
  • if( pRoot == pNode1 || pRoot == pNode2 )//說明在當前子樹的根節點上找到兩個節點之一
  • return pRoot;
  • BTreeNode_t *pLeft = GetLastCommonParent( pRoot->m_pLeft, pNode1, pNode2); //左子樹中的查找兩個節點并返回查找結果
  • BTreeNode_t *pRight = GetLastCommonParent( pRoot->m_pRight, pNode1, pNode2);//右子樹中查找兩個節點并返回查找結果
  • if( pLeft == NULL )//如果在左子樹中沒有找到,則斷定兩個節點都在右子樹中,可以返回右子樹中查詢結果;否則,需要結合左右子樹查詢結果共同斷定
  • return pRight;
  • if ( pRight == NULL )//如果在右子樹中沒有找到,則斷定兩個節點都在左子樹中,可以返回左子樹中查詢結果;否則,需要結合左右子樹查詢結果共同斷定
  • return pLeft;
  • return pRoot;//如果在左右子樹中都找兩個節點之一,則pRoot就是最低公共祖先節點,返回即可。
  • }


  • (2)非遞歸方式:

  • BTreeNode_t *GetLastCommonParent(BTreeNode_t *pRoot, BTreeNode_t *pNode1, BTreeNode_t *pNode2){
  • if( pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
  • return NULL;
  • vector < BTreeNode_t *> vec1;//用來保存從根節點到指定節點的遍歷路徑,前序遍歷
  • vector <BTreeNode_t *> vec2;
  • stack <BTreeNode_t *> st;
  • bool findflag1 = false;
  • bool findflag2 = false;
  • BTreeNode_t *commonParent = NULL;
  • while( pRoot != NULL || !st.empty() ){
  • while( pRoot != NULL ){
  • if( findflag1 == false){//沒有找出所有的節點:從根節點到指定節點,在遍歷時繼續入棧
  • vec1.push_back( pRoot);
  • if( pRoot == pNode1)//找到,則設置標志位
  • findflag1 = true;
  • }
  • if( findflag2 == false ){
  • vec1.push_back( pRoot);
  • if( pRoot == pNode2 )
  • findflag2 = true;
  • }
  • if( findflag1 == true && findflag2 == true)//如果都已找到,則退出
  • break;
  • st.push( pRoot);
  • pRoot = pRoot->m_pLeft;
  • }
  • while( !st.empty()){
  • pRoot = st.top();
  • st.pop();
  • pRoot = pRoot->right;
  • if( findflag1 == false )//沒有找到全部路徑節點時,就需要將錯誤路徑節點退出
  • vec1.pop_back();
  • if( findflag2 == false )
  • vec2.pop_back();
  • }
  • if( findflag1 == true && findflag2 == true)//如果都已找到,則退出
  • break;
  • }
  • if( findflag1 == true && findflag2 == true){//在兩個遍歷路徑上查找最后一個相同的節點,就是最低公共祖先節點(最近公共父節點)
  • vector< BTreeNode_t *> ::iterator iter1 = vec1.begin();
  • vector< BTreeNode_t *> ::iterator iter2 = vec2.begin();
  • while( iter1 != vec1.end() && iter2 != vec2.end() ){
  • if( *iter1 == *iter2)
  • commonParent = *iter1;
  • else
  • break;
  • ++iter1;
  • ++iter2;
  • }
  • }
  • vec1.clear();
  • vec2.clear();
  • st.clear();
  • return commonParent;
  • }


  • </pre><pre>



    總結

    以上是生活随笔為你收集整理的程序员面试100题之十六:二叉树中两个节点的最近公共父节点(最低的二叉树共同祖先)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。