This post is about computing the nearest common ancestor. It is the result of a month or so of reading papers and implementation. Although there has been a lot of research into the problem, there are no implementations online of the two main algorithms presented. Worse, examples in the papers are practically useless. For example, the Alstrup-Gavoille-Kaplan-Rauhe (AGKR) algorithm was first described in a technical report in August 2001, but it did not contain an example. In 2002, it was presented at a conference but again it did not contain an example. Finally, in 2004, it was published in a peer-reviewed journal and contained an example, albeit still incomplete.
Nearest common ancestor
Imagine meeting another person who has the same last name as you and suggests the possibility that you are related. You and your acquaintance create your own family trees and ask whether you have any common ancestors. If you are related, which relative is the most recent common ancestor? This is the problem of the nearest common ancestor (NCA), which is also known as the least common ancestor, or lowest common ancestor, first presented by Aho et al. [1].
The nearest common ancestor problem begins with a rooted general tree, G = (V, E, r â V), and two nodes in the tree. The set of ancestors of node is the set of nodes in the parent chain that starts at the node and ends at the root. The set of ancestors a(x) of a node x â V is
a(x) = (x = r) ? {x} : {x} ⪠a(Parent(x))
The proper ancestors of a node is the set of nodes in the parent chain that starts at the parent of the node and ends at the root, i.e., the set of ancestors for the node but not including the node itself. The set of proper ancestors p(x) of a node x âV is
p(x) = (x = r) ? â… : {Parent(x)} ⪠p(Parent(x))
The set of common ancestors ca(x, y) of node x, y âV is
ca(x, y) = a(x) â© a(y)
The nearest common ancestor nca(x, y) = w if w is a common ancestor of x and y with maximal depth d(w). So, if ca(x, y) is the set of nodes v1, v2, v3, …, vk, then vk is the least common ancestor if d(v1) < d(v2) < d(v3) < … < d(vk).
nca(x, y) = vk where vk â ca(x, y) = { v1, v2, v3, …, vk } and d(vn) < d(vk) for n ≠k
In Figure 1, the ancestors of e is the set {a, b, e}, and the ancestors of m is the set {a, d, m}. The proper ancestors of e is the set {a, b}, and the proper ancestors of m is the set {a, d}. The common ancestors of nodes e and m is {a}; the nearest common ancestor of nodes e and m is node a.
The nearest common ancestor problem has many different applications: compiler construction [1], string search algorithms [2], and evolutionary trees [3]. It also has applications in graph drawing in the Walker algorithm [4] and planarity testing [5, 6], which we will discuss later on.
Figure 1. A rooted general tree with ancestors of two leafs.
Simple solution for the nearest common ancestor
The simplest solution to the nearest common ancestor problem is computed using two stacks. In a loop, the ancestors for one node are pushed onto one stack. In a second loop, the ancestors for the other node are pushed onto the other stack. Finally, the top entries of each stack are popped and compared. If the top entries are the same, then the ancestors are the same, and we note the ancestor in a temporary variable. However, if the top entries differ, the nearest common ancestor has been found, and it is retained in the temporary variable.
While this algorithm works fine for many applications, the issue can become probative in computational time when the nearest common ancestor is computed for many different node pairings. Â It computes the nearest common ancestor in O(n) time.
Implementation in C#
1Â Â Â Â public Vertex NcaNaive(Vertex x, Vertex y)
2Â Â Â Â {
3Â Â Â Â Â Â Â Â Stack<Vertex> s1 = new Stack<Vertex>();
4Â Â Â Â Â Â Â Â Stack<Vertex> s2 = new Stack<Vertex>();
5Â Â Â Â Â Â Â Â Vertex lca = null;
6
7Â Â Â Â Â Â Â Â do
8Â Â Â Â Â Â Â Â {
9Â Â Â Â Â Â Â Â Â Â Â Â s1.Push(x);
10Â Â Â Â Â Â Â Â Â Â Â x = x.Parent;
11Â Â Â Â Â Â Â } while (x != null);
12Â Â Â Â Â Â Â do
13Â Â Â Â Â Â Â {
14Â Â Â Â Â Â Â Â Â Â Â s2.Push(y);
15Â Â Â Â Â Â Â Â Â Â Â y = y.Parent;
16Â Â Â Â Â Â Â } while (y != null);
17Â Â Â Â Â Â Â while (s1.Top() == s2.Top())
18Â Â Â Â Â Â Â {
19Â Â Â Â Â Â Â Â Â Â Â lca = s1.Pop();
20Â Â Â Â Â Â Â Â Â Â Â s2.Pop();
21Â Â Â Â Â Â Â }
22Â Â Â Â Â Â Â return lca;
23Â Â Â }
Each â€do-while†block (lines 7-11 and 12-16) computes a list of ancestors in order from a node to the root of the tree. The â€while†block at the end of the method (lines 17-21) compares each list of ancestors, processing each node from the root to the children until there is a difference in the ancestor list. The last node that is equal is the nearest common ancestor, and is the temporary variable lca.
Schieber-Vishkin solution for the nearest common ancestor
The Schieber-Vishkin algorithm is probably the first solution for the nearest common ancestor that is considered efficient, simple, and understandable. It is an extension of an earlier but more complicated solution by Harel and Tarjan [7]. It computes the nearest common ancestor in O(1) time after preprocessing the tree once in O(n) time. Both of these solutions are based on the reduction of the tree into a complete binary tree that has been labeled with an inorder numbering, and is also known as a â€sideways heap†[8]. The complete binary tree has several interesting properties which we will now illustrate by example (see Figure 2).
Figure 2. A full binary tree of 31 nodes, inorder numbering.
The first property concerns the node inorder numbering and the depth of the node in the complete binary tree. If the label of a particular node in represented as a binary integer, the level of the node in the tree can be determined by the position of the rightmost 1-bit in the label. In Figure 2, node 19 has the binary representation 10011, and it is a leaf node because the rightmost 1-bit is in the 1’s position. Node 20 has the binary representation 10100, and it is two levels up from the leaves of the tree because the rightmost 1-bit is in the 4’s position. We define the height of a node relative to the leaves of the tree, height(v) as the following function:
height(v) = ⌠log2(v & –v) ⌋
where & is the bitwise-and binary operator, and ⌠x ⌋ is the integer floor function.
Using this formula, height(3) = ⌠log2(00011 & -00011) ⌋ = ⌠log2(00011 & -11101) ⌋ = ⌠log2(00001) ⌋ = 0 (i.e., it is a leaf node).  The height(20) = ⌠log2(10100 & -10100) ⌋ = ⌠log2(10100 & -01100) ⌋ = ⌠log2(00100) ⌋ = 2 (i.e., two nodes up from a leaf node).
A second property concerns the ancestor of a node and the difference in the height between the node and its ancestor. Given a node v and the difference in the height h, the ancestor is
a(v, h) = ((v >> h) | 1) << h
Several other examples: the ancestor of node 3 with height h = 4 is a(3,0) = ((3 >> 4) | 1) << 4 = ((0) | 1) << 4 = 1 << 4 = 16; the ancestor of node 3 (00011) with height h = 1 is a(3,1) = ((3 >> 1) | 1) << 1 = ((1) | 1) << 1 = 1 << 1 = 2; and, the ancestor of node 3 with height h = 0 is a(3,0) = ((3 >> 0) | 1) << 0 = ((3) | 1) << 0 = 3 << 0 = 3.
Because of these two properties, it is possible to compute the nearest common ancestor for two nodes in the complete binary tree for any two nodes x and y using the following formula:
Let h = ⌠log2(x & –y) ⌋ where the label for x is less than or equal to the label for y, then
NCAcbt(x, y) = ((x >> h) | 1) << h
We now turn our attention back to the nearest common ancestor problem for a general tree. Given a tree T = (V, E, r âV), the Schieber-Vishkin algorithm requires the following functions to be computed in a preprocessing step:
1)Â Â Â Â Â Preorder: V â’ â„•
Function Preorder(v) maps nodes of the tree into integers that are the preorder numbers of the nodes in the tree.
2)Â Â Â Â Â Max: V â’ â„•
Function Max(v) maps nodes of the tree into the maximum preorder number of a node in the subtree for v.
3)Â Â Â Â Â Inlabel: V â’ â„•
Function Inlabel(v), known as the inlabel of a node, maps nodes of the tree into integer labels which correspond to the inorder numbers for nodes in the complete binary tree. Function Inlabel(v) is defined as:
Inlabel(v) = ⌠log2(Preorder(v) & – Max(v)) ⌋
4)Â Â Â Â Â Ascendant: V â’ â„•
Function Ascendant(v), known as the ascendant of a node, maps nodes of the tree into integers. The ascendant is a bit map defined according to the following expression:
Ascendant(v) = Ascendant(Parent(v)) | (Inlabel(v) & -Inlabel(v)), where Ascendant(r) = 0
The idea of the Ascendant(v) mapping is that it encodes the inlabel numbers of all ancestors of node v. A 1-bit in Ascendant(v) encodes the height of an ancestor of the node; a 0-bit indicates there is no ancestor at that level in the complete binary tree.
5)Â Â Â Â Â Head:Â â„• Â â’ V
Function Head(v), known as the head of a node, maps an integer label that is the result of a simple calculation for the nearest common ancestor in the complete binary tree into a node in the general tree. Function Head(v) is defined as:
Head(x) = v such that Inlabel(v) ≠Inlabel(Parent(v)) ⩠Inlabel(v) = x
Another way to understand this definition is that Head(x) is the node in the general tree that has the node that is an ancestor of x but has a different inlabel value as x.
The Inlabel(v) relationship maps a node in the general tree to a node in the complete binary tree. It is important to understand that the mapping Inlabel(v) is not a unique mapping, i.e., two nodes in the general tree can map to the same node in the complete binary tree. In order to uniquely identify the nearest common ancestor of two nodes in the general tree, Ascendant(v), and Head(v) are needed. Inlabel(v) maintains two properties which are crucial for the algorithm to compute the nearest common ancestor. First, Inlabel(v) partitions paths in the general tree, which are known as inlabel paths. All of these paths partition the general tree into distinct paths. This property is known as the path-partition property. Second, a node d that is a descendant of node p in the general tree map to nodes Inlabel(d) and Inlabel(p) in the complete binary tree, respectively, such that Inlabel(d) is a descendant of (or the same as) Inlabel(p). This is known as the descendance-preservation property.
The preprocessing step can be done in two passes over the general tree in a depth-first search. During the traversal, the values for Preorder(v), Max(v), Inlabel(v), and Head(v) are computed. Preorder(v) can be computed using a global variable for the node visited, incremented after associating the value with the node. Max(v) is computed after traversing a node’s entire subtree, associating the value of the global variable (minus 1 since it is post-incremented).  After computing Preorder(v) and Max(v), Inlabel(v) can then be computed using its definition because all dependencies have been computed. Head(v) can be computed in a couple different ways. However, one method is to assign the node to an array indexed by the Inlabel(v) value. As the depth-first search returns, the array entry is replaced with nodes in a particular inlabel path higher up in the general tree. In the second pass, function Ascendant(v) can be computed, using information from the previous pass (using Ascendant(Parent(v)) and Inlabel(v)).
The nearest common ancestor is computed in the following algorithm.
// Let x and y be the two nodes in the general tree.
// Compute the height of the nearest common ancestor in the complete binary tree:
let height(x,y) = ⌠log2(Inlabel(x) & -Inlabel(y)) ⌋
// Note, if Inlabel(x) is greater than Inlabel(y), then reverse the assignments of x and y.
// Compute the true height of the nearest common ancestor in the general tree:
let k = Ascendant(x) & Ascendant(y) & (1 << height(x, y)), and trueheight(x, y) = ⌠log2(k & -k) ⌋.
// Compute two candidates for the nearest common ancestor.
let j = ((Inlabel(x) >> trueheight(x, y)) | 1) << trueheight(x, y).
if j = Inlabel(x) then let xË = x
else
let L = ⌠log2(Ascendant(x) & ((1 << trueheight(x, y)) - 1) âŒ
xÌ‚ = Parent(Head((Inlabel(x) >> L) | 1) << L))Â
if j = Inlabel (y) then let Å· Â = y
else
let L = ⌠log2(Ascendant(y) & ((1 << trueheight(x, y)) - 1) ⌋
Å· = Parent(Head((Inlabel(y) >> L) | 1) << L))Â
let NCASV(x,y) = z, where z = xif Preorder( x̂ ) < Preorder( ŷ ), else ŷ.
asd
Implementation in C#
1Â Â Â using System;
2Â Â Â using System.Collections.Generic;
3Â Â Â using System.Text;
4
5Â Â Â namespace GeneralTreeLayout
6Â Â Â {
7Â Â Â Â Â Â Â class NCA
8Â Â Â Â Â Â Â {
9Â Â Â Â Â Â Â Â Â Â Â Tree tree;
10Â Â Â Â Â Â Â Â Â Â Dictionary<Vertex, int> Preorder;
11Â Â Â Â Â Â Â Â Â Â Dictionary<Vertex, int> Inlabel;
12Â Â Â Â Â Â Â Â Â Â Dictionary<Vertex, int> Ascendant;
13Â Â Â Â Â Â Â Â Â Â Dictionary<int, Vertex> Head;
14
15Â Â Â Â Â Â Â Â Â Â public NCA(Tree t)
16Â Â Â Â Â Â Â Â Â Â {
17Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.tree = t;
18Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Preorder = new Dictionary<Vertex, int>();
19Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Inlabel = new Dictionary<Vertex, int>();
20Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Ascendant = new Dictionary<Vertex, int>();
21Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Head = new Dictionary<int, Vertex>();
22Â Â Â Â Â Â Â Â Â Â }
23
24Â Â Â Â Â Â Â Â Â Â public void Preprocess()
25Â Â Â Â Â Â Â Â Â Â {
26Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.PreorderTraverse(this.tree.Root);
27Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeAscendants(this.tree.Root, 0);
28Â Â Â Â Â Â Â Â Â Â }
29
30Â Â Â Â Â Â Â Â Â Â int number = 1;
31
32Â Â Â Â Â Â Â Â Â Â public void PreorderTraverse(Vertex vertex)
33Â Â Â Â Â Â Â Â Â Â {
34Â Â Â Â Â Â Â Â Â Â Â Â Â Â int low = number;
35Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Preorder.Add(vertex, number++);
36Â Â Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge edge in vertex.Successors)
37Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
38Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.PreorderTraverse(edge.To);
39Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
40Â Â Â Â Â Â Â Â Â Â Â Â Â Â int high = number - 1;
41Â Â Â Â Â Â Â Â Â Â Â Â Â Â int lh = (high & -low);
42Â Â Â Â Â Â Â Â Â Â Â Â Â Â int h = this.FloorLog2((uint)lh);
43Â Â Â Â Â Â Â Â Â Â Â Â Â Â int inlabel = ((high >> h) | 1) << h;
44Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Inlabel.Add(vertex, inlabel);
45Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (!this.Head.ContainsKey(inlabel))
46Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Head.Add(inlabel, vertex);
47Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
48Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Head[inlabel] = vertex;
49Â Â Â Â Â Â Â Â Â Â }
50
51Â Â Â Â Â Â Â Â Â Â void ComputeAscendants(Vertex vertex, int pascendant)
52Â Â Â Â Â Â Â Â Â Â {
53Â Â Â Â Â Â Â Â Â Â Â Â Â Â int inlabel = this.Inlabel[vertex];
54Â Â Â Â Â Â Â Â Â Â Â Â Â Â int lsb = inlabel & -inlabel;
55Â Â Â Â Â Â Â Â Â Â Â Â Â Â int ascendant = pascendant | lsb;
56Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Ascendant.Add(vertex, ascendant);
57Â Â Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge edge in vertex.Successors)
58Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
59Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeAscendants(edge.To, ascendant);
60Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
61Â Â Â Â Â Â Â Â Â Â }
62
63Â Â Â Â Â Â Â Â Â Â public Vertex ComputeNCA(Vertex x, Vertex y)
64Â Â Â Â Â Â Â Â Â Â {
65Â Â Â Â Â Â Â Â Â Â Â Â Â Â int inlabelx = this.Inlabel[x];
66Â Â Â Â Â Â Â Â Â Â Â Â Â Â int inlabely = this.Inlabel[y];
67Â Â Â Â Â Â Â Â Â Â Â Â Â Â int xy = (inlabely & -inlabelx);
68Â Â Â Â Â Â Â Â Â Â Â Â Â Â int ch = FloorLog2((uint)xy);
69Â Â Â Â Â Â Â Â Â Â Â Â Â Â int ancestor = ((inlabely >> ch) | 1) << ch;
70Â Â Â Â Â Â Â Â Â Â Â Â Â Â int ax = this.Ascendant[x];
71Â Â Â Â Â Â Â Â Â Â Â Â Â Â int ay = this.Ascendant[y];
72Â Â Â Â Â Â Â Â Â Â Â Â Â Â int k = ax & ay & -(1 << ch);
73Â Â Â Â Â Â Â Â Â Â Â Â Â Â int th = FloorLog2((uint)(k & -k));
74Â Â Â Â Â Â Â Â Â Â Â Â Â Â int j = ((inlabelx >> th) | 1) << th;
75Â Â Â Â Â Â Â Â Â Â Â Â Â Â Vertex xhat = null;
76Â Â Â Â Â Â Â Â Â Â Â Â Â Â Vertex yhat = null;
77Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (j == inlabelx)
78Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xhat = x;
79Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
80Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
81Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int l = this.FloorLog2((uint)( ax & ((1 << th) - 1)));
82Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int anc = ((inlabelx >> l) | 1) << l;
83Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xhat = this.Head[anc].Parent;
84Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
85Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (j == inlabely)
86Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â yhat = y;
87Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
88Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
89Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int l = this.FloorLog2((uint)( ay & ((1 << th) - 1)));
90Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int anc = ((inlabely >> l) | 1) << l;
91Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â yhat = this.Head[anc].Parent;
92Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
93Â Â Â Â Â Â Â Â Â Â Â Â Â Â Vertex z = null;
94Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (this.Preorder[xhat] <= this.Preorder[yhat])
95Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â z = xhat;
96Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
97Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â z = yhat;
98Â Â Â Â Â Â Â Â Â Â Â Â Â Â return z;
99Â Â Â Â Â Â Â Â Â Â }
100
101Â Â Â Â Â Â Â Â Â int FloorLog2(uint v)
102Â Â Â Â Â Â Â Â Â {
103Â Â Â Â Â Â Â Â Â Â Â Â Â uint x = 0;
104Â Â Â Â Â Â Â Â Â Â Â Â Â while ((v = (v >> 1)) != 0)
105Â Â Â Â Â Â Â Â Â Â Â Â Â {
106Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â x++;
107Â Â Â Â Â Â Â Â Â Â Â Â Â }
108Â Â Â Â Â Â Â Â Â Â Â Â Â return (int)x;
109Â Â Â Â Â Â Â Â Â }
110Â Â Â Â Â }
111Â }
Example
Figure 3. Finding the nearest common ancestor using the Schieber-Vishkin algorithm.
(a)
(b)
(c)
Consider the example tree displayed in Figure 3(a). Compute the nearest common ancestor of node F and node N.
First, label each node in the tree using a preorder numbering (line 26, and line 32 through 49). These results are shown in Table 1. For each node, the method PreorderTraverse also calculates the Inlabel(v) values. The Head(v) mapping is also calculated. These results are shown in Table 2.
Table 1. Shrieber-Vishkin computation for Figure 3
Node v | P(v) | M(v) | I(v) | A(v) |
A | 1 | 18 | 16 | 16 |
B | 2 | 18 | 16 | 16 |
C | 3 | 6 | 4 | 20 |
D | 7 | 12 | 8 | 24 |
E | 13 | 18 | 16 | 16 |
F | 4 | 4 | 4 | 20 |
G | 5 | 5 | 5 | 21 |
H | 6 | 6 | 6 | 22 |
I | 8 | 11 | 8 | 24 |
J | 12 | 12 | 12 | 28 |
K | 14 | 17 | 16 | 16 |
L | 18 | 18 | 18 | 18 |
M | 9 | 9 | 9 | 25 |
N | 10 | 10 | 10 | 26 |
O | 11 | 11 | 11 | 25 |
P | 15 | 15 | 15 | 17 |
Q | 16 | 16 | 16 | 16 |
R | 17 | 17 | 17 | 17 |
Table 2. Shrieber-Vishkin head(x) for Figure 3
Complete binary tree node x | H(x) |
4 | C |
5 | G |
6 | H |
9 | M |
10 | N |
11 | O |
8 | D |
12 | J |
15 | P |
16 | A |
17 | R |
18 | L |
This method uses the function FloorLog2(v), which calculates the expression ⌠log2(v) ⌋. (Note, there are several other ways to compute the expression that are faster than the one show here). Next, the Ascendant mapping is computed (line  27 and lines 51 through 61).
The function ComputeNCA computes the nearest common ancestor (lines 63 through 99). For nodes F and N, the height of the nearest common ancestor in the complete binary tree is height(F, N) = ⌠log2(Inlabel(F) & –Inlabel(N)) ⌋ = 4. The true height is first found via k = Ascendant(F) & Ascendant(N) & (1 << height(F,  N)) = 20 & 26 & (1 << 4) = 10100 & 11010 & 10000 = 10000 = 16. Then trueheight(F, N) = ⌠log2(16 & -16) ⌋ = 3. Notice that the height in the general tree is different from the height in the complete binary tree. Next, compute the candidates for the NCA. Let j = ((Inlabel(F) >> trueheight(F, N)) | 1) << trueheight(F, N) = ((4 >> 3) | 1) << 3 = 16.  The results of computing  and  both are node B. So, NcaSV(F, N) = B.
Alstrup-Gavoille-Kaplan-Rauhe solution for the nearest common ancestor
The Alstrup-Gavoille-Kaplan-Rauhe (AGKR) algorithm [9, 10] is another solution to the nearest common ancestor problem, and is similar to the Schieber-Vishkin algorithm. After preprocessing the general tree in O(n) time, the solution can be computed in O(1) time. The main difference between the AGKR algorithm and the Schieber-Vishkin algorithm is that the Schieber-Vishkin algorithm maps the general tree into a complete binary tree, whereas the AGKR algorithm does not.  Instead, the AGKR algorithm is based on the computation of a common prefix between the labels of the two nodes in the general tree.
The AGKR algorithm creates labels for each node in the general tree by partitioning the nodes and edges by classify each as either light or heavy, a scheme that was introduced by Harel and Tarjan [7]. A heavy node is a node has the greatest subtree size of all its siblings. For each internal node v, we pick a child w of v, where size(w) = max{size(z) | z âchildren(v)} and classify w as heavy.  All other nodes are light nodes. All nodes that have no siblings are light nodes, and the root is defined to be a light node. A heavy path is an edge from a node of any class to a node of heavy class. All other paths are light paths.
Given a tree T = (V, E, r âV), the AGKR algorithm defines the following functions:
1)Â Â Â Â Â Size: V â’ â„•
Function Size(v) returns the size of the entire subtree of a node.
2)Â Â Â Â Â IsHeavy: V â’ bool
Function IsHeavy(v) partitions nodes of the general tree into heavy (denoted by true) or light (denoted by false):
IsHeavy(v) = true if |Children(Parent(v))| > 1 and [ †c âChildren(Parent(v)), where c ≠v and Size(c) ≤ Size(v)], else false.
In other words, a node v is function heavy if there is exists a sibling of v, and all siblings of v have a subtree size less than the subtree size for v.
3)Â Â Â Â Â Apex: V â’ V
Function Apex(v) finds the apex of a node (see below).
4)Â Â Â Â Â LightLabel: V â’ â„•
Function LightLabel(v) returns the light label for a node. The light label of a node is:
LightLabel(v) = Size(v)
5)Â Â Â Â Â HeavyLabel: V â’ â„•
Function HeavyLabel(v) returns the heavy label for a node. Â The heavy label of a node is:
HeavyLabel(v) = Size(v) – Size(h), where h à Children(v) and IsHeavy(h) = true
6)Â Â Â Â Â FullLabel: V â’ â„•
Function FullLabel(v) maps nodes of the tree into integer labels. Labels for the node are binary strings that are aligned to the leftmost (most significant) bit of an integer. The integer labels are scaled to the appropriate size so that they fit into an appropriate integer unit on a machine (e.g., 32-bit unsigned integers).
7)Â Â Â Â Â Mask: V â’ â„•
Function Mask(v) maps nodes of the tree into integer masks. The mask is a binary string that corresponds to the label FullLabel(v) and notes portions of the label that are either light or heavy, explained below.
8)Â Â Â Â Â Reverse:Â â„• â’ V
Function Reverse(v) maps an integer that is the result of a simple calculation for the nearest common ancestor into a node in the tree. The mapping should always exist, since the two nodes in the nearest common ancestor problem are in the tree.
In the preprocessing step, the AGKR algorithm first classifies nodes and edges of the tree as either light or heavy, a scheme that was introduced by Harel and Tarjan [7]. A heavy node is a node that must have at least one sibling and the node has the greatest subtree size of all its siblings.  All other nodes are light nodes. The nearest ancestor a of a node v in which node a is light and node v is heavy is known as an apex node.  The sequence of heavy nodes from the apex node is known as a heavy path. The heavy path starts at a light node, called the apex. Using this partitioning, two types of labels are constructed for each node: a heavy label, and a light label. The heavy and light labels are encoded in binary strings by considering the labels in a sequence:
a)      For heavy label encoding, the sequence is formed from the heavy labels for nodes in the heavy path. For example, the heavy labels for the heavy path A->B->C are encoded by considering the labels in sequence: HeavyLabel(A), HeavyLabel(B), HeavyLabel(C). There is only one encoding for each heavy label because the heavy node can belong only to one heavy path. The encoding for heavy labels of light nodes is the empty string.
b)     For light label encoding, the sequence is formed from the light labels for sibling nodes that are light nodes. For example, supposed the children of node A are B, C, and D. Node C is a heavy node, and nodes B and D are light nodes. The sequence for encoding the light labels is: LightLabel(B), LightLabel(D). The encoding for light labels of heavy nodes is the empty string.
The encoding is calculated as follows:
1)Â Â Â Â Â Create a sequence yi, I = 1 to k, from the integer values, either from the heavy labels, or the light children of a node. For example: heavy labels for heavy chain of nodes A->B->D->I->M are 1, 11, 2, 3, 1 (see Figure 4).
2)     Compute si = ①yj, j=1 .. i, and i=1 .. k-1, s0 = 0. From the example in the previous step, si = 0, 1, 12, 14, 17, 18.
3)     Compute fi = ⌠log2(yi) ⌋, i = 1 .. k.  From the example in the previous steps, fi = 0, 1, 8, 2, 2, 1.
4)Â Â Â Â Â Compute zi, i = 0 .. k:
zi = (si-1 mod 2fi = 0) ? si-1 : si-1 – (si-1 mod 2fi) + 2fi
From the example in the previous steps, zi = 0, 0, 8, 12, 14, 17.
5)     Compute m = max(zi) for all i = 0 .. k. From the example in the previous steps, m = 17.
6)     Compute w = ⌠log2(m) ⌋ + 1. From the example in the previous steps, w = 5.
7)     Compute encoding ei = (zi >> fi) encoded with w – fi bits, i = 1 .. k. From the example in the previous steps, the encodings for the labels in step 1 are 00000, 01, 0110, 0111, 10001.
We define functions EncodedHeavyLabel(v) and EncodedLightLabel(v) as the encoded heavy and light labels for node v, respectively.
Computing the NCA.
Each label for a node uniquely identifies all of the edges from the root to the node. The encodings constructed are a combination of the labels down a â€heavy†path in the tree and across the â€light†edges for siblings of a node.  For any node, the encoding is defined as
FullLabel(v) = FullLabel(Parent(Apex(v)) · EncodedLightLabel(Apex(v)) · EncodedHeavyLabel(v)
Given two nodes x and y that are in the tree the NCA is computed by computing the bitwise-AND between the two full labels and noting the location of the first difference from the left end of the labels. The difference between the two labels can occur either within a light substring or within a heavy substring.
If the difference occurs in the light label substrings, then let FullLabel(x) = L0 H0 L1 H1 L2 H2 …Li-1 Hi-1 Li … and FullLabel(y) = L0 H0 L1 H1 L2 H2 …Li-1 Hi-1 L’i …, where Li ¹ L’I. Then FullLabel(NCA(x, y)) = L0 H0 L1 H1 L2 H2 …Li-1 Hi-1.
If the difference occurs in the heavy label substrings, then let FullLabel(x) = L0 H0 L1 H1 L2 H2 …Li-1 Hi-1 Li Hi … and FullLabel(y) = L0 H0 L1 H1 L2 H2 …Li-1 Hi-1 Li H’i …, where Hi ¹ H’I. Then FullLabel(NCA(x, y)) = L0 H0 L1 H1 L2 H2 …Li-1 Hi-1 min(H1, H’1). Note that the last substring of the label for the NCA is the minimum substring via alphabetic ordering.
Mask(v) is used to indicate which bits in the label are part of the heavy or light substrings. The NCA is computed by the expression Reverse(FullLabel(NCA(x, y))).
Implementation in C#
1Â Â using System;
2Â Â using System.Collections.Generic;
3Â Â using System.Linq;
4Â Â using System.Text;
5
6Â Â namespace GeneralTreeLayout
7Â Â {
8Â Â Â Â Â Â class Alstrup : NCA
9
10Â Â Â Â Â Â Â Â Â Dictionary<Vertex, int> Number;
11Â Â Â Â Â Â Â Â Â List<Vertex> heavy;
12Â Â Â Â Â Â Â Â Â List<Vertex> light;
13Â Â Â Â Â Â Â Â Â Dictionary<Vertex, Vertex> apex;
14Â Â Â Â Â Â Â Â Â List<Vertex> UniqueApex;
15Â Â Â Â Â Â Â Â Â Dictionary<Vertex, int> hlabel;
16Â Â Â Â Â Â Â Â Â Dictionary<Vertex, int> llabel;
17Â Â Â Â Â Â Â Â Â Dictionary<Vertex, String> lightLabelEncodingString;
18Â Â Â Â Â Â Â Â Â Dictionary<Vertex, String> heavyLabelEncodingString;
19Â Â Â Â Â Â Â Â Â Dictionary<Vertex, String> labelEncodingString;
20Â Â Â Â Â Â Â Â Â Dictionary<Vertex, uint> labelEncodingBinary;
21Â Â Â Â Â Â Â Â Â Dictionary<Vertex, uint> kEncodingBinary;
22
23Â Â Â Â Â Â Â Â Â public Alstrup(Tree t)
24Â Â Â Â Â Â Â Â Â Â Â Â Â : base(t)
25Â Â Â Â Â Â Â Â Â {
26Â Â Â Â Â Â Â Â Â Â Â Â Â this.Number = new Dictionary<Vertex,int>();
27Â Â Â Â Â Â Â Â Â Â Â Â Â this.heavy = new List<Vertex>();
28Â Â Â Â Â Â Â Â Â Â Â Â Â this.light = new List<Vertex>();
29Â Â Â Â Â Â Â Â Â Â Â Â Â this.apex = new Dictionary<Vertex, Vertex>();
30Â Â Â Â Â Â Â Â Â Â Â Â Â this.UniqueApex = new List<Vertex>();
31Â Â Â Â Â Â Â Â Â Â Â Â Â this.hlabel = new Dictionary<Vertex, int>();
32Â Â Â Â Â Â Â Â Â Â Â Â Â this.llabel = new Dictionary<Vertex, int>();
33Â Â Â Â Â Â Â Â Â Â Â Â Â this.lightLabelEncodingString = new Dictionary<Vertex, string>();
34Â Â Â Â Â Â Â Â Â Â Â Â Â this.heavyLabelEncodingString = new Dictionary<Vertex, string>();
35Â Â Â Â Â Â Â Â Â Â Â Â Â this.labelEncodingString = new Dictionary<Vertex, string>();
36Â Â Â Â Â Â Â Â Â Â Â Â Â this.labelEncodingBinary = new Dictionary<Vertex, uint>();
37Â Â Â Â Â Â Â Â Â Â Â Â Â this.kEncodingBinary = new Dictionary<Vertex, uint>();
38Â Â Â Â Â Â Â Â Â }
39
40Â Â Â Â Â Â Â Â Â override public void Preprocess()
41Â Â Â Â Â Â Â Â Â {
42Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeSize(this.tree.Root);
43Â Â Â Â Â Â Â Â Â Â Â Â Â this.light.Add(this.tree.Root);
44Â Â Â Â Â Â Â Â Â Â Â Â Â this.Partition(this.tree.Root);
45Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeApex(this.tree.Root, this.tree.Root);
46Â Â Â Â Â Â Â Â Â Â Â Â Â foreach (Vertex v in this.UniqueApex)
47Â Â Â Â Â Â Â Â Â Â Â Â Â {
48Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeHeavyLabels(v);
49Â Â Â Â Â Â Â Â Â Â Â Â Â }
50Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeLightLabels(this.tree.Root);
51Â Â Â Â Â Â Â Â Â Â Â Â Â foreach (Vertex v in this.UniqueApex)
52Â Â Â Â Â Â Â Â Â Â Â Â Â {
53Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.EncodeHeavyLabels(v);
54Â Â Â Â Â Â Â Â Â Â Â Â Â }
55Â Â Â Â Â Â Â Â Â Â Â Â Â this.lightLabelEncodingString.Add(this.tree.Root, "");
56Â Â Â Â Â Â Â Â Â Â Â Â Â this.EncodeLightLabels(this.tree.Root);
57Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeFullLabels(this.tree.Root);
58Â Â Â Â Â Â Â Â Â }
59
60Â Â Â Â Â Â Â Â Â private int ComputeSize(Vertex v)
61Â Â Â Â Â Â Â Â Â {
62Â Â Â Â Â Â Â Â Â Â Â Â Â // Count the number of children in the whole subtree.
63Â Â Â Â Â Â Â Â Â Â Â Â Â int sum = 1;
64Â Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
65Â Â Â Â Â Â Â Â Â Â Â Â Â {
66Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Vertex c = e.To;
67Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sum += this.ComputeSize(c);
68Â Â Â Â Â Â Â Â Â Â Â Â Â }
69Â Â Â Â Â Â Â Â Â Â Â Â Â this.Number.Add(v, sum);
70Â Â Â Â Â Â Â Â Â Â Â Â Â return sum;
71Â Â Â Â Â Â Â Â Â }
72
73Â Â Â Â Â Â Â Â Â private void ComputeBinaryLabels(Vertex v, String s)
74Â Â Â Â Â Â Â Â Â {
75Â Â Â Â Â Â Â Â Â Â Â Â Â // Convert s into a binary and create a binary for h/l substring
76Â Â Â Â Â Â Â Â Â Â Â Â Â // boundaries.
77Â Â Â Â Â Â Â Â Â Â Â Â Â uint bin = 0;
78Â Â Â Â Â Â Â Â Â Â Â Â Â uint hl = 0;
79Â Â Â Â Â Â Â Â Â Â Â Â Â uint hlbin = 0;
80Â Â Â Â Â Â Â Â Â Â Â Â Â int len = 0;
81Â Â Â Â Â Â Â Â Â Â Â Â Â for (int i = 0; ; ++i)
82Â Â Â Â Â Â Â Â Â Â Â Â Â {
83Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (i == s.Length)
84Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
85Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (s[i] == '1')
86Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
87Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bin = bin << 1;
88Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bin |= 1;
89Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â len++;
90Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hlbin = hlbin << 1;
91Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hlbin |= hl;
92Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
93Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (s[i] == '0')
94Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
95Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bin = bin << 1;
96Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â len++;
97Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hlbin = hlbin << 1;
98Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hlbin |= hl;
99Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
100Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (s[i] == 'L')
101Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
102Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hl = 0;
103Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
104Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (s[i] == 'H')
105Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
106Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hl = 1;
107Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
108Â Â Â Â Â Â Â Â Â Â Â Â }
109Â Â Â Â Â Â Â Â Â Â Â Â // Shift binaries all the way to the MSB, and
110Â Â Â Â Â Â Â Â Â Â Â Â // set up hl to note end of label.
111Â Â Â Â Â Â Â Â Â Â Â Â int diff = 32 - len;
112Â Â Â Â Â Â Â Â Â Â Â Â hl = (hl == 0) ? (uint)1 : (uint)0;
113Â Â Â Â Â Â Â Â Â Â Â Â for (int i = 0; i < diff; ++i)
114Â Â Â Â Â Â Â Â Â Â Â Â {
115Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bin = bin << 1;
116Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hlbin = hlbin << 1;
117Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hlbin |= hl;
118Â Â Â Â Â Â Â Â Â Â Â Â }
119Â Â Â Â Â Â Â Â Â Â Â Â this.labelEncodingBinary.Add(v, bin);
120Â Â Â Â Â Â Â Â Â Â Â Â this.kEncodingBinary.Add(v, hlbin);
121Â Â Â Â Â Â Â Â }
122
123Â Â Â Â Â Â Â Â private void ComputeFullLabels(Vertex v)
124Â Â Â Â Â Â Â Â {
125Â Â Â Â Â Â Â Â Â Â Â Â // Compute the labelEncodingString for a node v.
126Â Â Â Â Â Â Â Â Â Â Â Â Vertex ap = this.apex[v];
127Â Â Â Â Â Â Â Â Â Â Â Â Vertex parent = ap.Parent;
128Â Â Â Â Â Â Â Â Â Â Â Â String t = "";
129Â Â Â Â Â Â Â Â Â Â Â Â if (parent != null)
130Â Â Â Â Â Â Â Â Â Â Â Â {
131Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (this.labelEncodingString.ContainsKey(parent))
132Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â t = this.labelEncodingString[parent];
133Â Â Â Â Â Â Â Â Â Â Â Â }
134Â Â Â Â Â Â Â Â Â Â Â Â String ll = "";
135Â Â Â Â Â Â Â Â Â Â Â Â if (this.lightLabelEncodingString.ContainsKey(ap))
136Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ll = this.lightLabelEncodingString[ap];
137Â Â Â Â Â Â Â Â Â Â Â Â String hl = "";
138Â Â Â Â Â Â Â Â Â Â Â Â if (this.heavyLabelEncodingString.ContainsKey(v))
139Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hl = this.heavyLabelEncodingString[v];
140Â Â Â Â Â Â Â Â Â Â Â Â String total = t + "L" + ll + "H" + hl;
141Â Â Â Â Â Â Â Â Â Â Â Â this.labelEncodingString.Add(v, total);
142Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeBinaryLabels(v, total);
143Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
144Â Â Â Â Â Â Â Â Â Â Â Â {
145Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeFullLabels(e.To);
146Â Â Â Â Â Â Â Â Â Â Â Â }
147Â Â Â Â Â Â Â Â }
148
149Â Â Â Â Â Â Â Â private void Partition(Vertex v)
150Â Â Â Â Â Â Â Â {
151Â Â Â Â Â Â Â Â Â Â Â Â // Find child with max size.
152Â Â Â Â Â Â Â Â Â Â Â Â int maxsize = 0;
153Â Â Â Â Â Â Â Â Â Â Â Â Vertex max = null;
154Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
155Â Â Â Â Â Â Â Â Â Â Â Â {
156Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Vertex to = e.To;
157Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int value = this.Number[to];
158Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (value > maxsize)
159Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
160Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxsize = value;
161Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â max = to;
162Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
163Â Â Â Â Â Â Â Â Â Â Â Â }
164Â Â Â Â Â Â Â Â Â Â Â Â if (max != null)
165Â Â Â Â Â Â Â Â Â Â Â Â {
166Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.heavy.Add(max);
167Â Â Â Â Â Â Â Â Â Â Â Â }
168Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
169Â Â Â Â Â Â Â Â Â Â Â Â {
170Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (e.To != max)
171Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
172Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.light.Add(e.To);
173Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
174Â Â Â Â Â Â Â Â Â Â Â Â }
175Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
176Â Â Â Â Â Â Â Â Â Â Â Â {
177Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.Partition(e.To);
178Â Â Â Â Â Â Â Â Â Â Â Â }
179Â Â Â Â Â Â Â Â }
180
181Â Â Â Â Â Â Â Â private void ComputeApex(Vertex v, Vertex a)
182Â Â Â Â Â Â Â Â {
183Â Â Â Â Â Â Â Â Â Â Â Â if (this.light.Contains(v))
184Â Â Â Â Â Â Â Â Â Â Â Â {
185Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // A light node is an apex by definition.
186Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.UniqueApex.Add(v);
187Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.apex.Add(v, v);
188Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â a = v;
189Â Â Â Â Â Â Â Â Â Â Â Â }
190Â Â Â Â Â Â Â Â Â Â Â Â else
191Â Â Â Â Â Â Â Â Â Â Â Â {
192Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.apex.Add(v, a);
193Â Â Â Â Â Â Â Â Â Â Â Â }
194Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
195Â Â Â Â Â Â Â Â Â Â Â Â {
196Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Vertex c = e.To;
197Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeApex(c, a);
198Â Â Â Â Â Â Â Â Â Â Â Â }
199Â Â Â Â Â Â Â Â }
200
201Â Â Â Â Â Â Â Â private void ComputeHeavyLabels(Vertex v)
202Â Â Â Â Â Â Â Â {
203Â Â Â Â Â Â Â Â Â Â Â Â int size = this.Number[v];
204Â Â Â Â Â Â Â Â Â Â Â Â int h = 0;
205Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
206Â Â Â Â Â Â Â Â Â Â Â Â {
207Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (this.heavy.Contains(e.To))
208Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
209Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â h = this.Number[e.To];
210Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeHeavyLabels(e.To);
211Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
212Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
213Â Â Â Â Â Â Â Â Â Â Â Â }
214Â Â Â Â Â Â Â Â Â Â Â Â size -= h;
215Â Â Â Â Â Â Â Â Â Â Â Â this.hlabel.Add(v, size);
216Â Â Â Â Â Â Â Â }
217
218Â Â Â Â Â Â Â Â private void ComputeLightLabels(Vertex v)
219Â Â Â Â Â Â Â Â {
220Â Â Â Â Â Â Â Â Â Â Â Â if (this.light.Contains(v))
221Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.llabel.Add(v, this.Number[v]);
222Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
223Â Â Â Â Â Â Â Â Â Â Â Â {
224Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.ComputeLightLabels(e.To);
225Â Â Â Â Â Â Â Â Â Â Â Â }
226Â Â Â Â Â Â Â Â }
227
228Â Â Â Â Â Â Â Â private void EncodeHeavyLabels(Vertex a)
229Â Â Â Â Â Â Â Â {
230Â Â Â Â Â Â Â Â Â Â Â Â List<Vertex> hp = this.GetHP(a);
231Â Â Â Â Â Â Â Â Â Â Â Â List<int> hpHLabel = this.GetHeavyLabels(hp);
232Â Â Â Â Â Â Â Â Â Â Â Â List<String> b = IntegerAlphabeticEncoding.Encoding(hpHLabel);
233Â Â Â Â Â Â Â Â Â Â Â Â for (int i = 0; i < hp.Count; ++i)
234Â Â Â Â Â Â Â Â Â Â Â Â {
235Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.heavyLabelEncodingString.Add(hp[i], b[i]);
236Â Â Â Â Â Â Â Â Â Â Â Â }
237Â Â Â Â Â Â Â Â }
238
239Â Â Â Â Â Â Â Â private List<Vertex> GetHP(Vertex v)
240Â Â Â Â Â Â Â Â {
241Â Â Â Â Â Â Â Â Â Â Â Â if (!this.UniqueApex.Contains(v))
242Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â throw new Exception("Not an apex.");
243Â Â Â Â Â Â Â Â Â Â Â Â List<Vertex> list = new List<Vertex>();
244Â Â Â Â Â Â Â Â Â Â Â Â list.Add(v);
245Â Â Â Â Â Â Â Â Â Â Â Â Vertex next = null;
246Â Â Â Â Â Â Â Â Â Â Â Â do
247Â Â Â Â Â Â Â Â Â Â Â Â {
248Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â next = null;
249Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
250Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
251Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (this.heavy.Contains(e.To))
252Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
253Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â next = e.To;
254Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â list.Add(next);
255Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
256Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
257Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
258Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â v = next;
259Â Â Â Â Â Â Â Â Â Â Â Â } while (next != null);
260Â Â Â Â Â Â Â Â Â Â Â Â return list;
261Â Â Â Â Â Â Â Â }
262
263Â Â Â Â Â Â Â Â private List<int> GetHeavyLabels(List<Vertex> list)
264Â Â Â Â Â Â Â Â {
265Â Â Â Â Â Â Â Â Â Â Â Â // Convert a list of vertices into a list of heavy labels.
266Â Â Â Â Â Â Â Â Â Â Â Â List<int> newlist = new List<int>();
267Â Â Â Â Â Â Â Â Â Â Â Â foreach (Vertex v in list)
268Â Â Â Â Â Â Â Â Â Â Â Â {
269Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â newlist.Add(this.hlabel[v]);
270Â Â Â Â Â Â Â Â Â Â Â Â }
271Â Â Â Â Â Â Â Â Â Â Â Â return newlist;
272Â Â Â Â Â Â Â Â }
273
274Â Â Â Â Â Â Â Â private void EncodeLightLabels(Vertex v)
275Â Â Â Â Â Â Â Â {
276Â Â Â Â Â Â Â Â Â Â Â Â List<Vertex> lightvertices = new List<Vertex>();
277Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
278Â Â Â Â Â Â Â Â Â Â Â Â {
279Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (this.light.Contains(e.To))
280Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
281Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â lightvertices.Add(e.To);
282Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
283Â Â Â Â Â Â Â Â Â Â Â Â }
284Â Â Â Â Â Â Â Â Â Â Â Â List<int> lightlabels = this.GetLightLabels(lightvertices);
285Â Â Â Â Â Â Â Â Â Â Â Â List<String> labels = IntegerAlphabeticEncoding.Encoding(lightlabels);
286Â Â Â Â Â Â Â Â Â Â Â Â this.AssociateLLabels(lightvertices, labels);
287Â Â Â Â Â Â Â Â Â Â Â Â foreach (Edge e in v.Successors)
288Â Â Â Â Â Â Â Â Â Â Â Â {
289Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.EncodeLightLabels(e.To);
290Â Â Â Â Â Â Â Â Â Â Â Â }
291Â Â Â Â Â Â Â Â }
292
293Â Â Â Â Â Â Â Â private List<int> GetLightLabels(List<Vertex> list)
294Â Â Â Â Â Â Â Â {
295Â Â Â Â Â Â Â Â Â Â Â Â // Convert a list of vertices into a list of light labels.
296Â Â Â Â Â Â Â Â Â Â Â Â List<int> newlist = new List<int>();
297Â Â Â Â Â Â Â Â Â Â Â Â foreach (Vertex v in list)
298Â Â Â Â Â Â Â Â Â Â Â Â {
299Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â newlist.Add(this.llabel[v]);
300Â Â Â Â Â Â Â Â Â Â Â Â }
301Â Â Â Â Â Â Â Â Â Â Â Â return newlist;
302Â Â Â Â Â Â Â Â }
303
304Â Â Â Â Â Â Â Â private void AssociateLLabels(List<Vertex> vertices, List<String> labels)
305Â Â Â Â Â Â Â Â {
306Â Â Â Â Â Â Â Â Â Â Â Â for (int i = 0; i < vertices.Count; ++i)
307Â Â Â Â Â Â Â Â Â Â Â Â {
308Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â this.lightLabelEncodingString.Add(vertices[i], labels[i]);
309Â Â Â Â Â Â Â Â Â Â Â Â }
310Â Â Â Â Â Â Â Â }
311
312Â Â Â Â Â Â Â Â override public Vertex ComputeNCA(Vertex x, Vertex y)
313Â Â Â Â Â Â Â Â {
314Â Â Â Â Â Â Â Â Â Â Â Â // NCA label to be found.
315Â Â Â Â Â Â Â Â Â Â Â Â uint ncalabel = 0;
316Â Â Â Â Â Â Â Â Â Â Â Â uint ncak = 0;
317
318Â Â Â Â Â Â Â Â Â Â Â Â // Get labels for each vertex.
319Â Â Â Â Â Â Â Â Â Â Â Â uint xs = this.labelEncodingBinary[x];
320Â Â Â Â Â Â Â Â Â Â Â Â uint ys = this.labelEncodingBinary[y];
321
322Â Â Â Â Â Â Â Â Â Â Â Â // Get heavy/light masks for each vertex.
323Â Â Â Â Â Â Â Â Â Â Â Â // These are needed to know whether the first difference
324Â Â Â Â Â Â Â Â Â Â Â Â // in the labels is on a heavy label substring, or a light
325Â Â Â Â Â Â Â Â Â Â Â Â // label substring.
326Â Â Â Â Â Â Â Â Â Â Â Â uint xk = this.kEncodingBinary[x];
327Â Â Â Â Â Â Â Â Â Â Â Â uint yk = this.kEncodingBinary[y];
328
329Â Â Â Â Â Â Â Â Â Â Â Â // Compute the common prefix and the location
330Â Â Â Â Â Â Â Â Â Â Â Â // of the first difference from the left.
331Â Â Â Â Â Â Â Â Â Â Â Â int h = Bithacks.FloorLog2(xs ^ ys);
332Â Â Â Â Â Â Â Â Â Â Â Â int hk = Bithacks.FloorLog2(xk ^ yk);
333Â Â Â Â Â Â Â Â Â Â Â Â if (h == 0)
334Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â h = hk;
335Â Â Â Â Â Â Â Â Â Â Â Â if (h == 0)
336Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return x;
337Â Â Â Â Â Â Â Â Â Â Â Â uint v = (uint)(1 << h);
338Â Â Â Â Â Â Â Â Â Â Â Â uint commonprefix = (xs >> h) << h;
339
340Â Â Â Â Â Â Â Â Â Â Â Â // Compute if the bit that is different is heavy or light
341Â Â Â Â Â Â Â Â Â Â Â Â // in either of the two labels.
342Â Â Â Â Â Â Â Â Â Â Â Â // ... or both!
343Â Â Â Â Â Â Â Â Â Â Â Â bool xheavy = (xk & v) != 0;
344Â Â Â Â Â Â Â Â Â Â Â Â bool yheavy = (yk & v) != 0;
345
346Â Â Â Â Â Â Â Â Â Â Â Â // Count number of heavy/light changes in each label.
347Â Â Â Â Â Â Â Â Â Â Â Â // We need to know the first actual difference.
348Â Â Â Â Â Â Â Â Â Â Â Â int xcount = 0;
349Â Â Â Â Â Â Â Â Â Â Â Â {
350Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int i = 31;
351Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (; i >= h; --i)
352Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
353Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bool hv = (xk & (1 << i)) != 0;
354Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (hv)
355Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
356Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xcount++;
357Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (; i >= h; --i)
358Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if ((xk & (1 << i)) == 0)
359Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
360Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xcount++;
361Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
362Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
363Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
364Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
365Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
366Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xcount++;
367Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (; i >= h; --i)
368Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if ((xk & (1 << i)) != 0)
369Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
370Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xcount++;
371Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
372Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
373Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
374Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
375Â Â Â Â Â Â Â Â Â Â Â Â }
376Â Â Â Â Â Â Â Â Â Â Â Â int ycount = 0;
377Â Â Â Â Â Â Â Â Â Â Â Â {
378Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int i = 31;
379Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (; i >= h; --i)
380Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
381Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bool hv = (yk & (1 << i)) != 0;
382Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (hv)
383Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
384Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ycount++;
385Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (; i >= h; --i)
386Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if ((yk & (1 << i)) == 0)
387Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
388Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ycount++;
389Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
390Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
391Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
392Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
393Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
394Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ycount++;
395Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (; i >= h; --i)
396Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if ((yk & (1 << i)) != 0)
397Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
398Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ycount++;
399Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
400Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
401Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
402Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
403Â Â Â Â Â Â Â Â Â Â Â Â }
404
405Â Â Â Â Â Â Â Â Â Â Â Â // Determine which is different, the L bits or the H bits.
406Â Â Â Â Â Â Â Â Â Â Â Â int j;
407Â Â Â Â Â Â Â Â Â Â Â Â bool xboundary, yboundary;
408Â Â Â Â Â Â Â Â Â Â Â Â for (j = h + 1; j <= 31; j++)
409Â Â Â Â Â Â Â Â Â Â Â Â {
410Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // Are we on a boundary between the heavy/light labels?
411Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint vm1 = (uint)(1 << j);
412Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xboundary = ((xk & vm1) != 0 ? !xheavy : xheavy);
413Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â yboundary = ((yk & vm1) != 0 ? !yheavy : yheavy);
414Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (xboundary || yboundary)
415Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
416Â Â Â Â Â Â Â Â Â Â Â Â }
417
418Â Â Â Â Â Â Â Â Â Â Â Â // Determine what kind of boundary.
419Â Â Â Â Â Â Â Â Â Â Â Â uint k;
420Â Â Â Â Â Â Â Â Â Â Â Â bool isheavy;
421Â Â Â Â Â Â Â Â Â Â Â Â if (xcount < ycount)
422Â Â Â Â Â Â Â Â Â Â Â Â {
423Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â k = xk;
424Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â isheavy = xheavy;
425Â Â Â Â Â Â Â Â Â Â Â Â }
426Â Â Â Â Â Â Â Â Â Â Â Â else
427Â Â Â Â Â Â Â Â Â Â Â Â {
428Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â k = yk;
429Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â isheavy = yheavy;
430Â Â Â Â Â Â Â Â Â Â Â Â }
431
432Â Â Â Â Â Â Â Â Â Â Â Â if (!isheavy)
433Â Â Â Â Â Â Â Â Â Â Â Â {
434Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // L bits differ.
435Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // back up before L.
436Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint xmask = (uint)-(1 << j);
437Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncalabel = xs & xmask;
438Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncak = xk & xmask;
439Â Â Â Â Â Â Â Â Â Â Â Â }
440Â Â Â Â Â Â Â Â Â Â Â Â else
441Â Â Â Â Â Â Â Â Â Â Â Â {
442Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // H bits differ.
443Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // First, back up before H.
444Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncalabel = xs & (uint)-(1 << j);
445
446Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // move forward picking alphabetic minimum H bits
447Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // until next L.
448Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint xsm = xs;
449Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint ysm = ys;
450Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint xmask;
451Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint ymask;
452Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
453Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // Find specific masks to get prefix plus heavy label.
454Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // Scan ahead for 0-bit.
455Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int i;
456Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (i = Bithacks.FloorLog2((uint)v); ; --i)
457Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
458Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if ((xk & (1 << i)) == 0)
459Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
460Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
461Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â i++; // backup.
462Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // get mask of all 1's up to heavy label and apply to the label.
463Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xmask = (uint)-(1 << i);
464Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â xsm &= xmask;
465Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
466Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
467Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // Find specific masks to get prefix plus heavy label.
468Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // Scan ahead for 0-bit.
469Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int i;
470Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (i = Bithacks.FloorLog2((uint)v); ; --i)
471Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
472Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if ((yk & (1 << i)) == 0)
473Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
474Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
475Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â i++; // backup.
476Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // get mask of all 1's up to heavy label and apply to the label.
477Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ymask = (uint)-(1 << i);
478Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ysm &= ymask;
479Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
480Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â // Got two labels, pick the one that is alphabetic.
481Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (xsm < ysm)
482Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
483Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncalabel = xsm;
484Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncak = xk & xmask;
485Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
486Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else
487Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
488Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncalabel = ysm;
489Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ncak = yk & ymask;
490Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
491Â Â Â Â Â Â Â Â Â Â Â Â }
492
493Â Â Â Â Â Â Â Â Â Â Â Â Vertex found = null;
494Â Â Â Â Â Â Â Â Â Â Â Â foreach (KeyValuePair<Vertex, uint> match in this.labelEncodingBinary)
495Â Â Â Â Â Â Â Â Â Â Â Â {
496Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (match.Value == ncalabel)
497Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
498Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (this.kEncodingBinary[match.Key] == ncak)
499Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â {
500Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â found = match.Key;
501Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
502Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
503Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
504Â Â Â Â Â Â Â Â Â Â Â Â }
505Â Â Â Â Â Â Â Â Â Â Â Â return found;
506Â Â Â Â Â Â Â Â }
507Â Â Â Â }
508 }
509
Example
Figure 4. Finding the nearest common ancestor using the Alstrup-Gavoille-Kaplan-Rauhe algorithm.
Consider the example tree displayed in Figure 4. Compute the nearest common ancestor of nodes F and N.
In a series of passes over the tree, the algorithm performs preprocessing (lines 40-58): Size(v) at lines 42 and 60-71; IsHeavy(v) at lines 43, 44, and 149-179; Apex(v) at lines 45 and 181-199; HeavyLabel(v) at lines 46-49 and 201-216; LightLabel(v) at lines 50 and 218-226; EncodeHeavyLabel(v) at lines 51-54 and 228-272; EncodeLightLabel(v) at lines 56 and 274-310; and FullLabel(v) at lines 57 and 73-147. The results of the computation are displayed in Table 3.
The NCA for nodes F and N is now computed (lines 312-508). The full labels for the two nodes are found (lines 326 and 327). FullLabel(F) = 580016. FullLabel(N) = 700016. FullLabel(NCA(F, N)) = FullLabel(F) & FullLabel(N) = 580016 & 700016 = 500016. Mask(F) = D80016. Mask(N) = F40016. The most significant bit that is different is bit 13 (bit 0 is the least significant bit, bit 15 is the most significant), found at line 331. This bit corresponds to a bit difference in the heavy label substring of FullLabel(N) but in the light label substring of FullLabel(F) (lines 343-344). The number of heavy/light substring boundary crossings is next counted starting from the left edge of each full label, xcount = 2, ycount = 1 (lines 348-403). The bit that is different is on a heavy/light substring boundary for FullLabel(N), but not for FullLabel(F). All this information leads one to conclude that the bit that is different is in the heavy label substring of FullLabel(N). In this case, the minimum between the two heavy label substrings must be chosen (lines 441-491). The labels are computed and compared (line 481) and the FullLabel(NCA(F, N)) = 400016. Therefore, NCA(F, N) = Reverse(FullLabel(NCA(F, N))) = Reverse(4000) = B (line 500).
Table 3. Alstrup-Gavoille-Kaplan-Rauhe computation for Figure 4.
Node, v | Size(v) | Class(v) | Light label(v) | Encoded Light label(v) | Heavy label(v) | Encoded Heavy label(v) | Label definition | Full Label with light and heavy boundary indicators | Full Label (16-bit value) | Heavy/light regions (16-bit value) |
A | 18 | L | 18 | e | 1 | 00000 | L(A).H(A) | LH00000 | 0000 | F800 |
B | 17 | H | – | 11 | 01 | L(A).H(B) | LH01 | 4000 | C000 | |
C | 4 | L | 4 | 0 | 3 | 0 | L(A).H(B).L(C).H(C) | LH01L0H0 | 4000 | D000 |
D | 6 | H | – | 2 | 0110 | L(A).H(D) | LH0110 | 6000 | F000 | |
E | 6 | L | 6 | 1 | 2 | 00 | L(A).H(B).L(E).H(E) | LH01L1H00 | 6000 | D800 |
F | 1 | H | – | 1 | 11 | L(A).H(B).L(C).H(F) | LH01L0H11 | 5800 | D800 | |
G | 1 | L | 1 | 0 | 1 | 0 | L(A).H(B).L(C).H(C).L(G).H(G) | LH01L0H0L0H0 | 4000 | D400 |
H | 1 | L | 1 | 1 | 1 | 0 | L(A).H(B).L(C).H(C).L(H).H(H) | LH01L0H0L1H0 | 4800 | D400 |
I | 4 | H | – | 3 | 0111 | L(A).H(I) | LH0111 | 7000 | F000 | |
J | 1 | L | 1 | 0 | 1 | 0 | L(A).H(D).L(J).H(J) | LH0110L0H0 | 6000 | F400 |
K | 4 | H | – | 3 | 01 | L(A).H(B).L(E).H(K) | LH01L1H01 | 6800 | D800 | |
L | 1 | L | 1 | 0 | 1 | 0 | L(A).H(B).L(E).H(E).L(L).H(L) | LH01L1H00L0H0 | 6000 | Da00 |
M | 1 | H | – | 1 | 10001 | L(A).H(M) | LH10001 | 8800 | F800 | |
N | 1 | L | 1 | 0 | 1 | 0 | L(A).H(I).L(N).H(N) | LH0111L0H0 | 7000 | F400 |
O | 1 | L | 1 | 1 | 1 | 0 | L(A).H(I).L(O).H(O) | LH0111L1H0 | 7800 | F400 |
P | 1 | H | – | 1 | 101 | L(A).H(B).L(E).H(P) | LH01L1H101 | 7400 | Dc00 | |
Q | 1 | L | 1 | 0 | 1 | 0 | L(A).H(B).L(E).H(K).L(Q).H(Q) | LH01L1H01L0H0 | 6800 | Da00 |
R | 1 | L | 1 | 1 | 1 | 0 | L(A).H(B).L(E).H(K).L(R).H(R) | LH01L1H01L1H0 | 6c00 | Da00 |
References
[1] Aho, A., Hopcroft, J. and Ullman, J. On finding lowest common ancestors in trees. SIAM J. Comput., 51976), 115-132.
[2] Gusfield, D. Algorithms on Stings, Trees, and Sequences: Computer Science and Computational Biology. ACM SIGACT News, 28, 4 1997), 41-60.
[3] Farach, M., Kannan, S. and Warnow, T. A robust model for finding optimal evolutionary trees. Algorithmica, 13, 1 1995), 155-179.
[4] Walker II, J. A Node-positioning Algorithm for General Trees. Software – Practice and Experience, 20, 7 1990), 685-705.
[5] Di Battista, G. and Tamassia, R. On-line planarity testing. SIAM Journal on Computing, 251996), 956-997.
[6] Westbrook, J. Fast incremental planarity testing. Springer, City, 1992.
[7] Harel, D. and Tarjan, R. Fast algorithms for finding nearest common ancestors. SIAM Journal on Computing, 131984), 338.
[8] Knuth, D. Combinatorial Algorithms. City, 2008.
[9] Alstrup, S., Gavoille, C., Kaplan, H. and Rauhe, T. Nearest common ancestors: A survey and a new distributed algorithm. ACM New York, NY, USA, City, 2002.
[10] Alstrup, S., Gavoille, C., Kaplan, H. and Rauhe, T. Nearest common ancestors: A survey and a new algorithm for a distributed environment. Theory of Computing Systems, 37, 3 2004), 441-456.