求解二叉樹中兩個結點的最低公共父結點


一,問題描述

構建一棵二叉樹(不一定是二叉查找樹),求出該二叉樹中某兩個結點的最低公共父結點。借用一張圖如下:

Binary Tree

結點8 和 結點5 的最低公共父結點為 結點2

 

二,二叉樹的構建

與 求二叉樹中第K層結點的個數 文章中的第二點:二叉樹構建相同

 

三,求解最低公共父結點的算法實現

有兩種思路,一種是通過中序遍歷和后序遍歷。由於中序遍歷是先左子樹中的結點,再訪問根,再訪問右子樹中結點,因此這兩個結點的公共父結點一定處於這兩個結點之間。

如:中序遍歷:8, 4, 9, 2, 5, 1, 6, 3, 7     結點2處於結點8 和 結點5 之間,也就是說:結點8 和 結點5 的最低公共父結點在 [8~5]之間的候選結點,這里為{4,9,2}中取

后序遍歷是先訪問左右子樹中的結點,最后再訪問根。故這兩個結點的最低公共父結點一定處於 結點8 和 結點5 之后的結點,且是第一個出現在{4,9,2}中的那個結點。

后序遍歷:8, 9, 4, 5, 2, 6, 7, 3, 1        8->9->4->5 這之后的結點,才可能是 結點8 和 結點5 的父結點。

 

另一種方法則是:遞歸,首先從樹根開始考慮:

①結點A 和 結點B 要么都在樹根的左子樹中;②要么都在樹根的右子樹中;③要么一個在左子樹中,一個在右子樹中。

這是一個分治算法,對於情況①和②,可以繼續遞歸分解。對於情況③屬於代碼第10行判斷,復雜度為O(1)

遞歸表達式可表示為:T(N)=2T(N/2)+O(1),解得T(N)=O(N)

對於③,最低公共父結點為樹根。

對於①,可以進一步判斷,從樹根的左孩子結點考慮:

1)結點A 和 結點B 要么都在樹根的左子孩子 的 左子樹中;2)要么都在樹根的左孩子 的 右子樹中;3) 要么一個在樹根的左孩子的 左子樹中,一個在樹根的左孩子 的 右子樹中。

對於②,可以進一步判斷,從樹根的右孩子的結點考慮:

1)結點A 和 結點B 要么都在樹根的右子孩子 的 左子樹中;2)要么都在樹根的右孩子 的 右子樹中;3) 要么一個在樹根的右孩子的 左子樹中,一個在樹根的右孩子 的 右子樹中。

下面代碼實現遞歸求解最低公共父結點。

 

四,代碼實現(node1 node2 都是二叉樹中的結點)

 1     /**
 2      * 求解node1 和 node2 的最低公共父結點
 3      * @param node1
 4      * @param node2
 5      * @return 最低公共父結點
 6      */
 7     public BinaryNode<T> commonNode(BinaryNode<T> node1, BinaryNode<T> node2, BinaryNode<T> root){
 8         if(root == null)
 9             return null;
10         if(node1.element == root.element || node2.element == root.element)
11             return root;
12         /*
13          * 若 left==null, node1,node2 都不在 root.left子樹中
14          * 若right==null,node1,node2 都不在root.right子樹中
15          */
16         BinaryNode<T> left = commonNode(node1, node2, root.left);
17         BinaryNode<T> right = commonNode(node1, node2, root.right);
18         
19         if(left != null && right != null)
20             return root;
21         return left == null ? right : left;
22     }

根據程序中的第8行和第10行的if語句,可知:

1)若 left==null, 則說明 node1,node2 都不在 root.left子樹中

2)若right==null,則說明 node1,node2 都不在root.right子樹中

 

3)當對於某個結點,當執行了第16,17行的遞歸后 ,left 和 right 都不為空,說明node1 在 該結點.left子樹中,node2 在 該結點.right子樹中

故第19-20行,返回 該結點 作為公共父結點

例如,求結點8 和 結點5 的最低公共父結點:遞歸調用過程如下:

a)commNode(8,5,1)==2

b1)      commNode(8,5,2)==2

c1)             commNode(8,5,4)==8

d1)                      commNode(8,5,8)==8

d2)                      commNode(8,5,9)==null

c2)             commNode(8,5,5)==5

b2)      commNode(8,5,3)==null

 

a)生成了 b1)  b2) 兩個遞歸調用,其中 b2)為空,因為結點8,結點5 不在以3為根的子樹中

b1)生成了 c1)   c2)兩個遞歸調用,其中 c2) 是commNode(8,5,5),根據程序第10行if,返回5,而c1)又生成了 d1)  d2)兩個遞歸調用

其中,d1) 返回8,d2)返回null, 故執行到第21行語句,return 不空的那個left/right,也就是 d1) 返回的結點8

 

由於 c1)返回了5, c2)返回了8,都不為空,執行到第19-20行,返回它們的root,即,結點4和結點5的公共父結點:結點2

由於 b1) 生成了 c1)  c2)   故 b1) 的值是結點2    又因為 b2) 為null

故 a) 最終是 b1) 的值,即為結點2

可把該方法放到求二叉樹中第K層結點的個數 中 的完整代碼給出的程序中進行測試。

 

五,參考資料

How to find the lowest common ancestor of two nodes in any binary tree?

 

附:求解二叉查找樹的最低公共祖先結點:https://www.cnblogs.com/hapjin/p/5770596.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM