Skip to content

Commit 5c50c33

Browse files
author
Mohamed Ayman
committed
apply OOP principles to LCA
1 parent ffe13e9 commit 5c50c33

File tree

2 files changed

+108
-56
lines changed

2 files changed

+108
-56
lines changed

include/LCA.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*******************************************************************************
2+
*
3+
*
4+
* /\ | _ _ ._ o _|_ |_ ._ _ _
5+
* /--\ | (_| (_) | | |_ | | | | | _>
6+
* _|
7+
*
8+
* LCA Finding using Binary Lifting and Dynamic Programming
9+
*
10+
* Features:
11+
* 1. Answers Query about LCA of two nodes in O(log N)
12+
* where N is the total number of nodes in a tree.
13+
*
14+
* https://en.wikipedia.org/wiki/Lowest_common_ancestor
15+
* http://www.csegeek.com/csegeek/view/tutorials/algorithms/trees/tree_part12.php
16+
******************************************************************************/
17+
18+
#ifndef LCA_H
19+
#define LCA_H
20+
#include <vector>
21+
22+
class LCA
23+
{
24+
public:
25+
LCA(std::vector< std::pair<int,int> > edges);
26+
int lcaQuery(int a, int b);
27+
28+
private:
29+
int getMaxLog();
30+
void initDP();
31+
void dfs(int currentNode, int currentParent);
32+
std::vector< std::vector<int> > adjList, binaryLiftDp;
33+
std::vector<int> parent, nodeHeight;
34+
std::vector<bool> visited;
35+
int _numberOfNodes, _maxLog;
36+
};
37+
38+
#endif // LCA_H

src/lca_demo.cpp

Lines changed: 70 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
1+
#include "LCA.h"
12
#include <cstdio>
23
#include <vector>
4+
#include <iostream>
5+
/**
6+
*Constructor is initialized with a Adjacency List that
7+
*describe a tree and If It doesn't describe a tree it asserts failure.
8+
*/
39

4-
const int MAX_NODE = 5000;
5-
const int MAX_LOG = 20;
6-
7-
int numberOfNodes, maxLog;
8-
std::vector< std::vector<int> > adjList;
9-
int parent[MAX_NODE], nodeHeight[MAX_NODE];
10-
bool visited[MAX_NODE];
11-
int binaryLiftDp[MAX_NODE][MAX_LOG];
10+
LCA::LCA(std::vector< std::pair<int,int> > edges): _numberOfNodes(edges.size() + 1), _maxLog(getMaxLog())
11+
{
12+
//First we initialize the needed vectors
13+
parent.resize(_numberOfNodes);
14+
nodeHeight.resize(_numberOfNodes);
15+
visited.resize(_numberOfNodes);
16+
adjList.resize(_numberOfNodes);
17+
binaryLiftDp = std::vector< std::vector<int> >(_numberOfNodes, std::vector<int>(_maxLog));
18+
/**Construction of the Adjacency List to increase
19+
*The efficiency of the tree traversal to O(V + E).
20+
*/
21+
for(auto edge : edges){
22+
adjList[edge.first].push_back(edge.second);
23+
adjList[edge.second].push_back(edge.first);
24+
}
25+
//Initialize the Dynamic programming Vector.
26+
initDP();
27+
}
1228

13-
void dfs(int currentNode, int currentParent)
29+
/**
30+
*DFS is used to find the parent and the height of each node
31+
*allowing the use of Binary Lifting.
32+
*/
33+
void LCA::dfs(int currentNode, int currentParent)
1434
{
1535
visited[currentNode] = true;
1636
parent[currentNode] = currentParent;
@@ -25,79 +45,73 @@ void dfs(int currentNode, int currentParent)
2545
}
2646
}
2747

28-
int getMaxLog(){
48+
/**
49+
*Used to Calculate the Log to the base of two
50+
*for the number of the nodes to create the sparse table
51+
*used in binary Lifting.
52+
*/
53+
int LCA::getMaxLog(){
2954
int curValue = 1;
3055
int curLog = 1;
31-
while(curValue < numberOfNodes) curValue *= 2, curLog++;
56+
while(curValue < _numberOfNodes) curValue *= 2, curLog++;
3257
return curLog;
3358
}
3459

35-
void initializeDP()
60+
void LCA::initDP()
3661
{
37-
nodeHeight[-1] = -1;
38-
maxLog = getMaxLog();
3962
dfs(0, -1);
40-
for(int i = 0; i < numberOfNodes; i++) binaryLiftDp[i][0] = parent[i];
41-
for(int i = 1; i <= maxLog; i++)
63+
for(int i = 0; i < _numberOfNodes; i++) binaryLiftDp[i][0] = parent[i];
64+
for(int i = 1; i <= _maxLog; i++)
4265
{
43-
for(int j = 0; j < numberOfNodes; j++)
66+
for(int j = 0; j < _numberOfNodes; j++)
4467
{
45-
if(binaryLiftDp[j][i - 1] + 1)
68+
/**
69+
* Since the ith parent of the current node is equal to
70+
* the ith / 2 parent to the ith /2 parent of the current node
71+
* That's why the Recurrence relation is described as follow
72+
*/
73+
if(binaryLiftDp[j][i - 1] != -1)
4674
binaryLiftDp[j][i] = binaryLiftDp[binaryLiftDp[j][i - 1]][i - 1];
4775
else binaryLiftDp[j][i] = -1;
4876
}
4977
}
5078
}
5179

52-
int LCA(int a, int b)
80+
int LCA::lcaQuery(int a, int b)
5381
{
82+
/**
83+
* First Both nodes must have same height
84+
* So we will rise the node with the deeper height up in
85+
* the tree to where they're equal.
86+
*/
5487
if(nodeHeight[a] < nodeHeight[b]) std::swap(a,b);
55-
for(int i = maxLog; i >= 0; i--)
88+
for(int i = _maxLog; i >= 0; i--)
5689
{
5790
if(binaryLiftDp[a][i] + 1 && nodeHeight[binaryLiftDp[a][i]] >= nodeHeight[b])
5891
a = binaryLiftDp[a][i];
5992
}
60-
if(!(a - b)) return a;
61-
for(int i = maxLog; i >= 0; i--)
93+
/**
94+
* If the node Lower is the LCA then return it.
95+
* Else keep moving both nodes up as much as they aren't the same
96+
* until it's only 1 node left which is the direct parent of both of them
97+
*/
98+
if(a == b) return a;
99+
for(int i = _maxLog; i >= 0; i--)
62100
{
63101
if(binaryLiftDp[a][i] + 1 && binaryLiftDp[a][i] - binaryLiftDp[b][i])
64102
a = binaryLiftDp[a][i], b = binaryLiftDp[b][i];
65103
}
66104
return parent[a];
67105
}
68106

69-
void buildTree()
70-
{
71-
printf("Enter number of nodes of the tree: ");
72-
scanf("%d", &numberOfNodes);
73-
adjList.resize(numberOfNodes, std::vector<int> ());
74-
for(int i = 0; i < numberOfNodes - 1; i++)
75-
{
76-
int firstNode, secondNode;
77-
printf("Enter the two nodes to be connected: ");
78-
scanf("%d %d", &firstNode, &secondNode);
79-
adjList[firstNode].push_back(secondNode);
80-
adjList[secondNode].push_back(firstNode);
81-
}
82-
}
83-
84-
void answerQueries()
85-
{
86-
int queryCount;
87-
printf("Enter the number of queries: ");
88-
scanf("%d", &queryCount);
89-
for(int i = 0; i < queryCount; i++)
90-
{
91-
int firstNode, secondNode;
92-
printf("Enter the two nodes : ");
93-
scanf("%d %d", &firstNode, &secondNode);
94-
printf("%d\n", LCA(firstNode, secondNode));
95-
}
96-
}
97-
98-
int main()
99-
{
100-
buildTree();
101-
initializeDP();
102-
answerQueries();
107+
int main(){
108+
std::vector< std::pair<int,int> > edges;
109+
edges.push_back({0,1});
110+
edges.push_back({1,2});
111+
edges.push_back({2,3});
112+
edges.push_back({1,4});
113+
LCA* l = new LCA(v);
114+
std::cout << l->lcaQuery(0,1) << endl;
115+
std::cout << l->lcaQuery(3,4) << endl;
116+
std::cout << l->lcaQuery(3,2) << endl;
103117
}

0 commit comments

Comments
 (0)