นี่คือสองวิธีใน c # (.net) (ทั้งสองที่กล่าวถึงข้างต้น) สำหรับการอ้างอิง:
เวอร์ชันเรียกซ้ำของการค้นหา LCA ในไบนารีทรี (O (N) - เป็นอย่างมากที่แต่ละโหนดถูกเยี่ยมชม) (ประเด็นหลักของการแก้ปัญหาคือ LCA คือ(a)โหนดเดียวในไบนารีต้นไม้ที่องค์ประกอบทั้งสองอยู่ด้านข้างของ subtrees (ซ้าย) และขวา) คือ LCA (b)และมันก็ไม่สำคัญว่าโหนดใดที่อยู่ข้างใดข้างหนึ่ง - เริ่มแรกฉันพยายามเก็บข้อมูลนั้นและเห็นได้ชัดว่าฟังก์ชั่นวนซ้ำกลายเป็นสับสนมากเมื่อฉันรู้ว่ามันกลายเป็นสง่ามาก
การค้นหาทั้งสองโหนด (O (N)) และการติดตามเส้นทาง (ใช้พื้นที่พิเศษ - ดังนั้น # 1 น่าจะดีกว่าแม้จะคิดว่าพื้นที่นั้นอาจไม่สำคัญถ้าต้นไม้ไบนารีมีความสมดุลเพราะการใช้หน่วยความจำเพิ่มเติมจะอยู่ใน O (เข้าสู่ระบบ (N))
เพื่อให้มีการเปรียบเทียบเส้นทาง (essentailly คล้ายกับคำตอบที่ยอมรับ - แต่เส้นทางจะถูกคำนวณโดยสมมติว่าตัวชี้โหนดไม่ปรากฏในโหนดต้นไม้ไบนารี)
เพื่อความสมบูรณ์ ( ไม่เกี่ยวข้องกับคำถาม ) LCA ใน BST (O (บันทึก (N))
การทดสอบ
recursive:
private BinaryTreeNode LeastCommonAncestorUsingRecursion(BinaryTreeNode treeNode,
int e1, int e2)
{
Debug.Assert(e1 != e2);
if(treeNode == null)
{
return null;
}
if((treeNode.Element == e1)
|| (treeNode.Element == e2))
{
//we don't care which element is present (e1 or e2), we just need to check
//if one of them is there
return treeNode;
}
var nLeft = this.LeastCommonAncestorUsingRecursion(treeNode.Left, e1, e2);
var nRight = this.LeastCommonAncestorUsingRecursion(treeNode.Right, e1, e2);
if(nLeft != null && nRight != null)
{
//note that this condition will be true only at least common ancestor
return treeNode;
}
else if(nLeft != null)
{
return nLeft;
}
else if(nRight != null)
{
return nRight;
}
return null;
}
โดยที่เวอร์ชันเรียกซ้ำแบบส่วนตัวด้านบนถูกเรียกใช้โดยวิธีการสาธารณะดังต่อไปนี้:
public BinaryTreeNode LeastCommonAncestorUsingRecursion(int e1, int e2)
{
var n = this.FindNode(this._root, e1);
if(null == n)
{
throw new Exception("Element not found: " + e1);
}
if (e1 == e2)
{
return n;
}
n = this.FindNode(this._root, e2);
if (null == n)
{
throw new Exception("Element not found: " + e2);
}
var node = this.LeastCommonAncestorUsingRecursion(this._root, e1, e2);
if (null == node)
{
throw new Exception(string.Format("Least common ancenstor not found for the given elements: {0},{1}", e1, e2));
}
return node;
}
โซลูชันโดยการติดตามเส้นทางของทั้งสองโหนด:
public BinaryTreeNode LeastCommonAncestorUsingPaths(int e1, int e2)
{
var path1 = new List<BinaryTreeNode>();
var node1 = this.FindNodeAndPath(this._root, e1, path1);
if(node1 == null)
{
throw new Exception(string.Format("Element {0} is not found", e1));
}
if(e1 == e2)
{
return node1;
}
List<BinaryTreeNode> path2 = new List<BinaryTreeNode>();
var node2 = this.FindNodeAndPath(this._root, e2, path2);
if (node1 == null)
{
throw new Exception(string.Format("Element {0} is not found", e2));
}
BinaryTreeNode lca = null;
Debug.Assert(path1[0] == this._root);
Debug.Assert(path2[0] == this._root);
int i = 0;
while((i < path1.Count)
&& (i < path2.Count)
&& (path2[i] == path1[i]))
{
lca = path1[i];
i++;
}
Debug.Assert(null != lca);
return lca;
}
โดยที่ FindNodeAndPath ถูกกำหนดเป็น
private BinaryTreeNode FindNodeAndPath(BinaryTreeNode node, int e, List<BinaryTreeNode> path)
{
if(node == null)
{
return null;
}
if(node.Element == e)
{
path.Add(node);
return node;
}
var n = this.FindNodeAndPath(node.Left, e, path);
if(n == null)
{
n = this.FindNodeAndPath(node.Right, e, path);
}
if(n != null)
{
path.Insert(0, node);
return n;
}
return null;
}
BST (LCA) - ไม่เกี่ยวข้อง (สำหรับการอ้างอิงให้สำเร็จ)
public BinaryTreeNode BstLeastCommonAncestor(int e1, int e2)
{
//ensure both elements are there in the bst
var n1 = this.BstFind(e1, throwIfNotFound: true);
if(e1 == e2)
{
return n1;
}
this.BstFind(e2, throwIfNotFound: true);
BinaryTreeNode leastCommonAcncestor = this._root;
var iterativeNode = this._root;
while(iterativeNode != null)
{
if((iterativeNode.Element > e1 ) && (iterativeNode.Element > e2))
{
iterativeNode = iterativeNode.Left;
}
else if((iterativeNode.Element < e1) && (iterativeNode.Element < e2))
{
iterativeNode = iterativeNode.Right;
}
else
{
//i.e; either iterative node is equal to e1 or e2 or in between e1 and e2
return iterativeNode;
}
}
//control will never come here
return leastCommonAcncestor;
}
ทดสอบหน่วย
[TestMethod]
public void LeastCommonAncestorTests()
{
int[] a = { 13, 2, 18, 1, 5, 17, 20, 3, 6, 16, 21, 4, 14, 15, 25, 22, 24 };
int[] b = { 13, 13, 13, 2, 13, 18, 13, 5, 13, 18, 13, 13, 14, 18, 25, 22};
BinarySearchTree bst = new BinarySearchTree();
foreach (int e in a)
{
bst.Add(e);
bst.Delete(e);
bst.Add(e);
}
for(int i = 0; i < b.Length; i++)
{
var n = bst.BstLeastCommonAncestor(a[i], a[i + 1]);
Assert.IsTrue(n.Element == b[i]);
var n1 = bst.LeastCommonAncestorUsingPaths(a[i], a[i + 1]);
Assert.IsTrue(n1.Element == b[i]);
Assert.IsTrue(n == n1);
var n2 = bst.LeastCommonAncestorUsingRecursion(a[i], a[i + 1]);
Assert.IsTrue(n2.Element == b[i]);
Assert.IsTrue(n2 == n1);
Assert.IsTrue(n2 == n);
}
}