I am making a recursive decent parser with this grammar.
Expr -> Term ( '+' | '-' ) Expr | Term
Term -> Number ( '*' | '/' ) Term | Number
Number -> any valid Java double
And My getTerm Method looks like this.
private static BTree getTerm(Tokenizer tokens)
{
String tokenHold = "";
BTree result = new BTree(getNumber(tokens).getElement());
System.out.println("VALUE of result : " + result.toString());
while(tokens.hasToken() && ("*/".indexOf(tokens.peekToken()) != -1)){
BTree newTree = null;
boolean isMulti = false;
boolean isDiv = false;
if(tokens.peekToken().equals("*")){
isMulti = true;
}
if(tokens.peekToken().equals("/")){
isDiv = true;
}
if(isMulti) {
newTree = new BTree( "*" );
}
else if(isDiv){
newTree = new BTree( "/" );
}
tokenHold = tokens.nextToken();
newTree.addLeftTree(result);
newTree.addRightTree(getTerm(tokens));
result = newTree;
}
System.out.println("Expression of result : " + result.toString());
return result;
}
It returns to the getExpr method which looks like
private static BTree getExpr(Tokenizer tokens)
{
String tokenHold = "";
BTree result = new BTree(getTerm(tokens).getElement());//consumes term
System.out.println("Expression of result in getExpr: " + result.toString());
while(tokens.hasToken() && ("+-".indexOf(tokens.peekToken()) != -1)){
BTree newTree = null;
boolean isAdd = false;
boolean isSub = false;
if(tokens.peekToken().equals("+")){isAdd = true;}
if(tokens.peekToken().equals("-")){isSub = true;}
if(isAdd){ newTree = new BTree( "+" );}
else if(isSub){ newTree = new BTree( "-" );}
tokenHold = tokens.nextToken();
newTree.addRightTree(result);
newTree.addLeftTree(getTerm(tokens)); // old tree on the right
result = newTree;
}
return result;
}
Constructors for the BTree
public BTree(String element)
{
this.element = element;
left = null;
right = null;
}
public BTree(String element, BTree left, BTree right)
{
this.element = element;
this.left = left;
this.right = right;
}
When I input this syntax 4 / 2 / 2 . The getTerm Method has the correct values being returned " (/ 4 (/ 2 2)) " but the getExpr only see's "/". I have sat and tried to figure out my issue but I think I might have a fundamental miss understanding of how these two methods are passing arguments. I also have a feeling it is because of the recursion. I will answer this question myself if I figure it out myself. Thanks in advance.
Alright I finally figured it out.
in my getExpr method I was using a constructor that I didn't include in the original question for the Binary Tree it looks like this
public BTree(String element)
{
this.element = element;
left = null;
right = null;
}
I should have been using the constructor that had both the left and right child of the tree. This constructor looks like this.
public BTree(String element, BTree left, BTree right)
{
this.element = element;
this.left = left;
this.right = right;
}
Because I was not using the correct constructor when passing this value from the getTerm method to getExpr method I lost some of the information and thus was only getting the root. I am new to binary tree's / Recursion / AST and sometimes forget the BIG picture when working with these tools.
Related
Two weeks ago I've finished an implementation of a splay tree that allows basic functions, like insert, delete, find key and and obtain the sum of a range of elements of the three. You can find this implementation here as reference for this question or out of curiosity.
As an extra task (its optional and its past due, I'm solving this not for a grade but because I believe its a useful data structure not easy to "Google about it"), I was asked to implement a Rope data structure to manipulate strings so if the string is "warlock" and the keys given are 0 2 2, then the string would be "lowarck" (0 2 is substring "war", "lock" is whats left after removing "war" and you insert it after 2nd char so turns into "lo"+"war"+"ck").
This is just one query but it can be up to 100k queries for a 300k character long string, so a naive solution wouldnt work.
My first doubt is about initializing the tree( For the ones who have read the gist,I'll use Node instead of Vertex in order to be easy to understand for most).
This is the Node class and the NodePair class:
class Node {
char key;
int size;
Node left;
Node right;
Node parent;
Node(char key, int size, Node left, Node right, Node parent) {
this.key = key;
this.size = size;
this.left = left;
this.right = right;
this.parent = parent;
}
}
class NodePair {
Node left;
Node right;
NodePair() {
}
NodePair(Node left, Node right) {
this.left = left;
this.right = right;
}
}
After that, I create the tree this way:
StringBuffer sb = new StringBuffer(br.readLine());
Node left=null;
for (int i=0;i<sb.length();i++){
root=new Vertex(sb.charAt(i), i+1, left, null, null);
if (i!=sb.length()-1){
left=root;
}
}
This creates a very unbalanced tree where the first char of the string (as node.key) has node.size 1 and is the leftmost child; and the last char of the string is the root with size=sb.length().
I am not completely sure if this is correctly initialized. I did an inorder traversal print with key and size and I got the whole string in size order, which is what I expected.
After that I have modified the Update method from this:
void update(Node v) {
if (v == null) return;
v.sum = v.key + (v.left != null ? v.left.sum : 0) + (v.right != null ? v.right.sum : 0);
if (v.left != null) {
v.left.parent = v;
}
if (v.right != null) {
v.right.parent = v;
}
}
To this: (based on CLRS chapter 14.1)
void update(Node v) {
if (v == null) return;
v.size = 1 + (v.left != null ? v.left.size : 0) + (v.right != null ? v.right.size : 0);
if (v.left != null) {
v.left.parent = v;
}
if (v.right != null) {
v.right.parent = v;
}
}
Then the find method, from the original:
NodePair find(Node root, int key) {
Node v = root;
Node last = root;
Node next = null;
while (v != null) {
if (v.key >= key && (next == null || v.key < next.key)) {
next = v;
}
last = v;
if (v.key == key) {
break;
}
if (v.key < key) {
v = v.right;
} else {
v = v.left;
}
}
root = splay(last);
return new NodePair(next, root);
}
to this:(Based in the Order Statistics-SELECT of CLRS Chapter 14.1)
Node find(Node r, int k){
int s = r.left.size + 1;
if (k==s) return r;
else if (k < s) {
return find(r.left,k);
}
return find(r.right,k-s);
}
However I already have a problem at this point since, as you can see, the original find returns a NodePair while this method returns a Node.
The explanation of the NodePair according to instructors is:
Returns pair of the result and the new root.If found, result is a
pointer to the node with the given key.Otherwise, result is a pointer
to the node with the smallest bigger key (next value in the order). If
the key is bigger than all keys in the tree, then result is null.
This complicates my split method since it uses Find method to look for the node to split.
Besides this, I'm obtaining NullPointerException at this find method and from other students I understand that to avoid other error we should use a non-recursive version, so basically I need to implement a non-recursive version of OS-Select that returns a NodePair as the previous find method or modify my split method which is:
NodePair split(Node root, int key) {
NodePair result = new NodePair();
NodePair findAndRoot = find(root, key);
root = findAndRoot.right;
result.right = findAndRoot.left;
if (result.right == null) {
result.left = root;
return result;
}
result.right = splay(result.right);
result.left = result.right.left;
result.right.left = null;
if (result.left != null) {
result.left.parent = null;
}
update(result.left);
update(result.right);
return result;
}
As you can see, the find method is assigned to the NodePair findAndRoot.
I believe that besides the OS-Select conversion to non-recursive my main problem is to understand the way NodePair is used by the previous find method and split method.
Finally, this is my implementation of the method to receive the tree and keys and manipulate them:
Node stringManip(Node v, int i, int j, int k){
Node left;
Node right;
NodePair middleRight =split(v,j+1);
left=middleRight.left;
right=middleRight.right;
NodePair leftMiddle = split(left,i);
Node start = leftMiddle.left;
Node substr = leftMiddle.right;
Node tmp = merge(start, right);
NodePair pairString = split(tmp,k+1);
Vertex fLeft =pairString.left;
Vertex fRight = pairString.right;
root = merge(merge(fLeft,substr),fRight);
root = splay(root);
update(root);
return root;
}
As you must realize from my code, I'm a beginner with only have 5 months that started learning to program and I picked Java, so from the info I've gathered I get that this type of data structure is more in the intermediate-expert level (I'm already surprise I was capable of implementing the previous splay tree.
So please, consider my beginner level in your answer.
PD: Here's a pseudocode version of the nonrecursive OS-Select, still having NullPointerException..
OS-SELECT(x, i)
while x != null
r <- size[left[x]]+1
if i = r
then return x
elseif i < r
x = left[x]
else
x = right[x]
i = i - r
I have a function that receives a binary expression tree and returns a String with the expression in-order. The only "problem" is that the resulting expression have too many parentheses,
e.g.: The function returns (a + (b * c)), but it can be reduced to a + b * c.
It is defined with the binary operators +, -, *, /, and the unary operator _ (negative).
What I really want to know is if I can modify the already existing function to reduce the number of parentheses in an efficient way, or create another function that operates with the String of the in-order expression.
The function is as follows:
private static String infijo(ArbolB t){
String s = "";
if (t != null) {
String info = String.valueOf(t.info);
if ("+-*/".contains(info)) s += "(";
if ("_".contains(info)) s += "-(";
s += infijo(t.left) + (info.equals("_") ? "" : info) + infijo(t.right);
if ("+-*/_".contains(String.valueOf(t.info))) s += ")";
}
return s;
}
Where ArbolB is a binary tree defined by:
public class ArbolB {
ArbolB right;
ArbolB left;
Object info;
public ArbolB(Object info, ArbolB right, ArbolB left){
this.info = info;
this.right = right;
this.left = left;
}
}
After writing this whole thing out, I realized that I didn't really answer your question properly (my solution ignores PEMDAS and just matches pairs, d'oh!). So, take from this what you can... I'm not throwing it out :P
I think you COULD solve this either way, but here would be my preferred method, using and trusting what you already have. There's probably a good way to use nodes to do this, but why not use what you have, right?
Starting from the point where you have your expression as a string (e.g. "((2*2) + _(3+3))" you could try something like:
public string RemoveUnnecessaryParens(string expression)
{
readonly string openParen = "(";
readonly string closeParen = ")";
// char array would also work for this
// multiple ways to track "balance" of parens, lets use int
int unclosedParenCount = 0;
string toReturn = "";
// iterate through the expression
for (int i = 0; i < expression.Length; i++)
{
string current = expression.Substring(i,1);
if (openParen == current)
unclosedParenCount++;
else if (closedParen == current)
unclosedParenCount--;
else
toReturn += current;
if (unclosedParenCount < 0) throw new UnbalancedExpressionException(); // One more close than open! Uh oh!
}
if (0 != unclosedParenCount) throw new UnbalancedExpressionException(); // One more open than close at the end! Uh oh!
else return toReturn;
}
Make sense?
Well, after thinking it a while, I got to a solution myself, by adding a priority function for determining when parentheses were necessary, and a variable that indicates if the operation was on the left or the right side of the formula, this because a-b+c don't need parentheses, but c+(a-b) do need them.
private static String infijo(ArbolB t, int priority, boolean right) {
String s = "";
int oP = 0;
if (t != null) {
String info = String.valueOf(t.info);
int pi = priority(info);
if ("+-*/".contains(info)) {
/* this only adds parentheses if the operation has higher priority or if the
operation on the right side should be done before the one on the left side*/
if ("+-*/".contains(info)) {
if (pi/2 < priority/2) s += "(";
else s += pi/2 == priority/2 && pi != priority && right ? "(" : "";
oP = priority; //stores the old priority
priority= pi; //priority of the new operator
}
}
if ("_".contains(info)) {
s += "-";
oP = priority;
priority = pi;
}
s += infijo(t.left, priority, false) + (info.equals("_") ? "" : info)
+ infijo(t.right, priority, true);
if ("+-*/".contains(info)) {
// adds the closing parentheses following the same rules as for the opening ones
if (priority / 2 < oP / 2) s += ")";
else s += priority / 2 == oP / 2 && priority != oP && right ? ")" : "";
}
}
return s;
}
private static int priority(String op) {
if ("_".contains(op)) return 4;
if ("/".contains(op)) return 3;
if ("*".contains(op)) return 2;
if ("-".contains(op)) return 1;
return 0;
}
#Override
public String toString() {
ArbolB f = getFormula(); //this returns the Binary Expression Tree
return infijo(f, Integer.MIN_VALUE, false);
}
As it is said in the title I am trying to create a code which converts a postfix notation to an expression tree. Here you can check the constructor :
public byte type; // 0 : operator, 1: operand (a number)
public char operator; // One of '+', '-', '*', '/'
public int operand; // A number
ExpressionTreeNode(byte type){this.type = type; left=right=null;}
and Here is my code :
public static ExpressionTreeNode Postfix2ExpressionTree(String postfixExpr){
Stack s = new Stack<Object>();
ExpressionTreeNode root = new ExpressionTreeNode((byte) 0);
root.operator = postfixExpr.charAt(postfixExpr.length()-1);
String number = "";
for(int i = 0;i<postfixExpr.length()-1;i++){
if(Character.isDigit(postfixExpr.charAt(i)) == true){
number = number + postfixExpr.charAt(i);
if(Character.isDigit(postfixExpr.charAt(i+1)) == false){
ExpressionTreeNode node = new ExpressionTreeNode((byte) 1);
node.operand = Integer.valueOf(number);
node.right = null;
node.left = null;
s.push(node);
number = "";
}
}
if(i == postfixExpr.length()-2){
root.right = (ExpressionTreeNode) s.pop();
root.left =(ExpressionTreeNode) s.pop();
s.push(root);
break;
}
else {
if(postfixExpr.charAt(i) == '+' || postfixExpr.charAt(i) == '*' || postfixExpr.charAt(i) == '-' || postfixExpr.charAt(i) == '/' ){
ExpressionTreeNode node = new ExpressionTreeNode((byte)0);
node.operand = postfixExpr.charAt(i);
node.right = (ExpressionTreeNode) s.pop();
node.left = (ExpressionTreeNode) s.pop();
s.push(node);
}
}
}
return (ExpressionTreeNode) s.pop();
}
I check every character one by one with charAt() method. Simply
1-push every operand into the stack
2-when operator is encountered pop two operand from the stack and assign them to right and left of operator then push the new node to the stack.
3- and finally I push the root to the stack then return it.
No error occurs when I try to run but also it is not working in the right way too. I checked the code many times but I couldn't solve it.If anyone sees the mistake and help me , that would be great.
A postfix expression is parsed from left to right - don't look at postfixExpr.length()-1 before you are there.
Do not create and handle a root node in any special way. It will be top of the stack after the parse.
Here's an error:
node.operand = postfixExpr.charAt(i);
This must be stored in node.operator.
This is how I would implement it:
public interface Entry {
int evaluate();
}
public class Value implements Entry {
private int value;
public Value( int value ){
this.value = value;
}
public int evaluate(){
return value;
}
}
public class Operation implements Entry {
private char operator;
private Entry left;
private Entry right;
public Operation( char operator, Entry left, Entry right ){
this.operator = operator;
this.left = left;
this.right = right;
}
public int evaluate(){
int l = left.evaluate();
int r = right.evaluate();
switch(operator){
case '+':
return l + r;
case '-':
return l - r;
case '*':
return l * r;
case '/':
return l / r;
}
throw new IllegalStateException( "operator " + operator );
}
}
public class Parser {
private Stack<Entry> stack = new Stack<>();
Pattern pat = Pattern.compile( "[-+*/]" );
Scanner scanner;
public void parse( String ex ){
scanner = new Scanner( ex );
while( scanner.hasNext() ){
while( scanner.hasNextInt() ){
stack.push( new Value( scanner.nextInt() ) );
}
while( scanner.hasNext( pat ) ){
char op = scanner.next( pat ).charAt( 0 );
Entry right = stack.pop();
Entry left = stack.pop();
stack.push( new Operation( op, left, right ) );
}
}
}
public Entry get(){
return stack.pop();
}
}
There is absolutely no error handling, so think about adding that.
As a programming exercise I need to rewrite some existing methods and classes that make up a binary tree. (The method signatures and constructors have to stay the same). Somehow I don't really seem to understand what I have done here.
Does the toString method have to public because it overwrites the Object class's toString method? And how can I avoid the nulls from being returned?
Here is the code I have come to so far:
Tree Class
Node root = null;
void addNode(int val) {
Node newNode = new Node(val);
root = newNode.addNode(root, val);
}
Node Class
Node(int val) {
val = val;
left = null;
right = null;
}
Node addNode(Node focusNode, int newNodeVal) {
if (focusNode == null)
return this;
if (newNodeVal == focusNode.val)
return focusNode;
if (newNodeVal < focusNode.val)
focusNode.left = this.addNode(focusNode.left, newNodeVal);
else
focusNode.right = this.addNode(focusNode.right, newNodeVal);
return focusNode;
}
public String toString() {
return this.left + " " + this.val + " " + this.right;
}
Use a StringBuilder to store the String representation of the node and append the data of the children nodes only in the specific node is not null. Here's an example using infix navigation on the nodes:
public String toString() {
StringBuilder sb = new StringBuilder();
if (this.left != null) {
sb.append(this.left);
sb.append(' ');
}
sb.append(this.val);
if (this.right != null) {
sb.append(' ');
sb.append(this.right);
}
return sb.toString();
}
public String toString() {
if(this.left==null){
return this.val + this.right;
} else if (this.right==null){
return this.left + this.val;
} else if (this.left == null && this.right == null){
return "";
} else {
return this.left + " " + this.val + " " + this.right;
}
}
You assign your nodes to null to start, and your toString method assumes that they have been altered. Imagine a tree where you added 5, then 3. Then called toString on the tree. It will try to print the node, 5 is the value, left is 3, right is null. When you try to call
return this.left + " " + this.val + " " + this.right;
You are saying to print
3 5 NULL
You can initialize left and right with an empty Node object (with no val) and when you print it you will see null as the val of an empty Node:
Node(Integer val) {
this.val = val;
left = new Node(null);
right = new Node(null);
}
This only works if you make val an Integer.
There is also a bug in your code:
val = val will leave this.val untouched. You have to use this.val = val;
toString() is overridden not overwritten. It has to return a String and you can't really avoid nulls if your Node is a leaf.
What you can do is writing toString() in a way it can be meaningful to have a null as val like this:
public String toString() {
return "#{val = " + val + ", left = " + left + ", right = " + right + "}"
}
Please note that this will traverse your tree recursively so to print your tree you only have to call root.toString().
This is a popular interview question and the only article I can find on the topic is one from TopCoder. Unfortunately for me, it looks overly complicated from an interview answer's perspective.
Isn't there a simpler way of doing this other than plotting the path to both nodes and deducing the ancestor? (This is a popular answer, but there's a variation of the interview question asking for a constant space answer).
A simplistic (but much less involved version) could simply be (.NET guy here Java a bit rusty, so please excuse the syntax, but I think you won't have to adjust too much). This is what I threw together.
class Program
{
static void Main(string[] args)
{
Node node1 = new Node { Number = 1 };
Node node2 = new Node { Number = 2, Parent = node1 };
Node node3 = new Node { Number = 3, Parent = node1 };
Node node4 = new Node { Number = 4, Parent = node1 };
Node node5 = new Node { Number = 5, Parent = node3 };
Node node6 = new Node { Number = 6, Parent = node3 };
Node node7 = new Node { Number = 7, Parent = node3 };
Node node8 = new Node { Number = 8, Parent = node6 };
Node node9 = new Node { Number = 9, Parent = node6 };
Node node10 = new Node { Number = 10, Parent = node7 };
Node node11 = new Node { Number = 11, Parent = node7 };
Node node12 = new Node { Number = 12, Parent = node10 };
Node node13 = new Node { Number = 13, Parent = node10 };
Node commonAncestor = FindLowestCommonAncestor(node9, node12);
Console.WriteLine(commonAncestor.Number);
Console.ReadLine();
}
public class Node
{
public int Number { get; set; }
public Node Parent { get; set; }
public int CalculateNodeHeight()
{
return CalculateNodeHeight(this);
}
private int CalculateNodeHeight(Node node)
{
if (node.Parent == null)
{
return 1;
}
return CalculateNodeHeight(node.Parent) + 1;
}
}
public static Node FindLowestCommonAncestor(Node node1, Node node2)
{
int nodeLevel1 = node1.CalculateNodeHeight();
int nodeLevel2 = node2.CalculateNodeHeight();
while (nodeLevel1 > 0 && nodeLevel2 > 0)
{
if (nodeLevel1 > nodeLevel2)
{
node1 = node1.Parent;
nodeLevel1--;
}
else if (nodeLevel2 > nodeLevel1)
{
node2 = node2.Parent;
nodeLevel2--;
}
else
{
if (node1 == node2)
{
return node1;
}
node1 = node1.Parent;
node2 = node2.Parent;
nodeLevel1--;
nodeLevel2--;
}
}
return null;
}
}
Constant space answer: (although not necessarily efficient).
Have a function findItemInPath(int index, int searchId, Node root)
then iterate from 0 .. depth of tree, finding the 0-th item, 1-th item etc. in both search paths.
When you find i such that the function returns the same result for both, but not for i+1,
then the i-th item in the path is the lowest common ancestor.
The main reason why the article's solutions are more complicated is that it is dealing with a two-stage problem- preprocessing and then queries- while from your question it sounds like you're only doing one query so preprocessing doesn't make sense. It's also dealing with arbitrary trees rather than binary trees.
The best answer will certainly depend on details about the tree. For many kinds of trees, the time complexity is going to be O(h) where h is the tree's height. If you've got pointers to parent nodes, then the easy "constant-space" answer is, as in Mirko's solution, to find both nodes' height and compare ancestors of the same height. Note that this works for any tree with parent links, binary or no. We can improve on Mirko's solution by making the height function iterative and by separating the "get to the same depth" loops from the main loop:
int height(Node n){
int h=-1;
while(n!=null){h++;n=n.parent;}
return h;
}
Node LCA(Node n1, Node n2){
int discrepancy=height(n1)-height(n2);
while(discrepancy>0) {n1=n1.parent;discrepancy--;}
while(discrepancy<0) {n2=n2.parent;discrepancy++;}
while(n1!=n2){n1=n1.parent();n2=n2.parent();}
return n1;
}
The quotation marks around "constant-space" are because in general we need O(log(h)) space to store the heights and the difference between them (say, 3 BigIntegers). But if you're dealing with trees with heights too large to stuff in a long, you likely have other problems to worry about that are more pressing than storing a couple nodes' heights.
If you have a BST, then you can easily take a common ancestor (usu. starting with root) and check its children to see whether either of them is a common ancestor:
Node LCA(Node n1, Node n2, Node CA){
while(true){
if(n1.val<CA.val & n2.val<CA.val) CA=CA.left;
else if (n1.val>CA.val & n2.val>CA.val) CA=CA.right;
else return CA;
}
}
As Philip JF mentioned, this same idea can be used in any tree for a constant-space algorithm, but for a general tree doing it this way will be really slow since figuring out repeatedly whether CA.left or CA.right is a common ancestor will repeat a lot of work, so you'd normally prefer to use more space to save some time. The main way to make that tradeoff would be basically the algorithm you've mentioned (storing the path from root).
It matters what kind of tree you are using. You can always tell if a node is the ancestor of another node in constant space, and the top node is always a common ancestor, so getting the Lowest Common Ancestor in constant space just requires iterating your way down. On a binary search tree this is pretty easy to do fast, but it will work on any tree.
Many different trade offs are relevant for this problem, and the type of tree matters. The problem tends is much easier if you have pointers to parent nodes, and not just to children (Mirko's code uses this)
See also:
http://en.wikipedia.org/wiki/Lowest_common_ancestor
The obvious solution, that uses log(n) space, (n is the number of nodes) is the algorithm you mentioned. Here's an implementation. In the worst case it takes O(n) time (imagine that one of the node you are searching common ancestor for includes the last node).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Node
{
private static int counter = 0;
private Node left = null;
private Node right = null;
public int id = counter++;
static Node constructTreeAux(int depth)
{
if (depth == 0)
return null;
Node newNode = new Node();
newNode.left = constructTree(depth - 1);
newNode.right = constructTree(depth - 1);
return newNode;
}
public static Node constructTree(int depth)
{
if (depth == 0)
return null;
Node root = new Node();
root.left = constructTreeAux(depth - 1);
root.right = constructTreeAux(depth - 1);
return root;
}
private List<Node> findPathAux(List<Node> pathSoFar, int searchId)
{
if (this.id == searchId)
{
if (pathSoFar == null)
pathSoFar = new List<Node>();
pathSoFar.Add(this);
return pathSoFar;
}
if (left != null)
{
List<Node> result = left.findPathAux(null, searchId);
if (result != null)
{
result.Add(this);
return result;
}
}
if (right != null)
{
List<Node> result = right.findPathAux(null, searchId);
if (result != null)
{
result.Add(this);
return result;
}
}
return null;
}
public static void printPath(List<Node> path)
{
if (path == null)
{
Console.Out.WriteLine(" empty path ");
return;
}
Console.Out.Write("[");
for (int i = 0; i < path.Count; i++)
Console.Out.Write(path[i] + " ");
Console.Out.WriteLine("]");
}
public override string ToString()
{
return id.ToString();
}
/// <summary>
/// Returns null if no common ancestor, the lowest common ancestor otherwise.
/// </summary>
public Node findCommonAncestor(int id1, int id2)
{
List<Node> path1 = findPathAux(null, id1);
if (path1 == null)
return null;
path1 = path1.Reverse<Node>().ToList<Node>();
List<Node> path2 = findPathAux(null, id2);
if (path2 == null)
return null;
path2 = path2.Reverse<Node>().ToList<Node>();
Node commonAncestor = this;
int n = path1.Count < path2.Count? path1.Count : path2.Count;
printPath(path1);
printPath(path2);
for (int i = 0; i < n; i++)
{
if (path1[i].id == path2[i].id)
commonAncestor = path1[i];
else
return commonAncestor;
}
return commonAncestor;
}
private void printTreeAux(int depth)
{
for (int i = 0; i < depth; i++)
Console.Write(" ");
Console.WriteLine(id);
if (left != null)
left.printTreeAux(depth + 1);
if (right != null)
right.printTreeAux(depth + 1);
}
public void printTree()
{
printTreeAux(0);
}
public static void testAux(out Node root, out Node commonAncestor, out int id1, out int id2)
{
Random gen = new Random();
int startid = counter;
root = constructTree(5);
int endid = counter;
int offset = gen.Next(endid - startid);
id1 = startid + offset;
offset = gen.Next(endid - startid);
id2 = startid + offset;
commonAncestor = root.findCommonAncestor(id1, id2);
}
public static void test1()
{
Node root = null, commonAncestor = null;
int id1 = 0, id2 = 0;
testAux(out root, out commonAncestor, out id1, out id2);
root.printTree();
commonAncestor = root.findCommonAncestor(id1, id2);
if (commonAncestor == null)
Console.WriteLine("Couldn't find common ancestor for " + id1 + " and " + id2);
else
Console.WriteLine("Common ancestor for " + id1 + " and " + id2 + " is " + commonAncestor.id);
}
}
}
The bottom up approach described here is an O(n) time, O(1) space approach:
http://www.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
Node *LCA(Node *root, Node *p, Node *q) {
if (!root) return NULL;
if (root == p || root == q) return root;
Node *L = LCA(root->left, p, q);
Node *R = LCA(root->right, p, q);
if (L && R) return root; // if p and q are on both sides
return L ? L : R; // either one of p,q is on one side OR p,q is not in L&R subtrees
}