Εδώ είναι δύο προσεγγίσεις σε C # (.net) (και τα δύο συζητούνται παραπάνω) για την αναφορά:
Αναδρομική εκδοχή της εύρεσης LCA σε δυαδικό δένδρο (O (N) - το περισσότερο το επισκέπτονται κάθε κόμβος) (κύρια σημεία του διαλύματος είναι LCA είναι (α) μόνο κόμβο σε δυαδικό δένδρο όπου αμφότερα τα στοιχεία κατοικούν εκατέρωθεν του υποδένδρων (αριστερά και δεξιά) είναι ΑΚΖ. (β) και επίσης, δεν έχει σημασία ποια κόμβου είναι παρούσα σε κάθε πλευρά - αρχικά προσπάθησαν να κρατήσουν αυτές τις πληροφορίες, και προφανώς η αναδρομική συνάρτηση γίνει τόσο συγκεχυμένη μία φορά το κατάλαβα, έγινε πολύ κομψό..
Ψάχνοντας τους δύο κόμβους (O (N)), καθώς και την παρακολούθηση των διαδρομών (χρησιμοποιεί περισσότερο χώρο - και έτσι, # 1 είναι ίσως ανώτερη παρ 'όλο που ο χώρος είναι μάλλον αμελητέα αν το δυαδικό δέντρο είναι καλά ισορροπημένη και, στη συνέχεια, επιπλέον κατανάλωση μνήμης θα είναι μόνο σε O (log (N)).
έτσι ώστε οι διαδρομές σύγκριση (essentailly παρόμοια με αποδεκτή απάντηση - αλλά οι διαδρομές υπολογίζονται με την παραδοχή κόμβο δείκτης δεν είναι παρών στο δυαδικό κόμβο του δένδρου)
Ακριβώς για την ολοκλήρωση ( που δεν σχετίζονται με ερώτηση ), ΑΚΖ στο BST (O (log (N))
δοκιμές
Αναδρομική:
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);
}
}