Equivalent subtree - java

I have two trees. The tree Node is defined as
class Node{
String treeId;
String type; //Each node has type which has fixed value. For example, its color: RED, BLANK, GREEN
Set<Node> children;
String ref; //The ref is a string and allowed value are "0", "1",..."10". The value is null if it is not leaf.
};
For leaf, the children set is empty.
I am wondering whether there is some existing efficient work done how to identify equivalent substree for two given tree. The equivalent is defined as:
1) Both subtree leaves are setsets leaves of original tree.
2) Both subtrees leaves have same ref value.
3) for non-leaves node, the equivalent refers to both node have same type and equivalent children.
Thanks. It would be better if there is some Java library addressing this problem.
The input should are two tree roots while output is the Node that is root of equivalent subtree. An the the tree's height is 100~ and it has more than 500 nodes.
What i did now is that I added a new field for class Node.
class Cache{
Map<String, Set<String>> map = new LinkedHashMap<String, Set<Str>>();
}
The key of map is Node id while the value is a ref set this node of this nodeid can reach. The Cache initiated when Node is initialized.
During isEquivalent compare phase, check whether overlap exists between two root's ref set. Return false if none.
I think this can help reduce the number of comparison space.

I am not sure about 1) Both subtree leaves are leaves of original tree. requirement as it seems to conflict with how to identify equivalent substree for two given tree.. Otherwise following recursive method should be able to cover other two conditions. The haveSameOriginalTree(r1, r2) method may be implemented to satisfy the first condition that I couldn't understand. r1 and r2 are roots of two subtrees that need to be checked for equivalence.
bool areEquivalent(Node r1, Node r2)
{
if(r1.children == null && r2.children == null)
{
return (haveSameOriginalTree(r1, r2) && (r1.ref == r2.ref));
}
if((r1.children == null && r2.children != null) || (r1.children != null && r2.children == null))
{
return false;
}
// if here then both must be non-leaf nodes
if(r1.type != r2.type)
{
return false;
}
if(r1.children.getCount() != r2.children.getCount()) // not sure of correct syntax for Java Sets
{
return false;
}
for(int i=0; i<r1.children.getCount(); i++)
{
if(!areEquivalent(r1.children[i], r2.children[i])) // again please correct the syntax for Sets
{
return false;
}
}
return true;
}
Let me know what you think.
Update
Here is an iterative version of the above solution. It uses stack data structure which is allocated on the heap rather than pushed on function's call stack, so not hugely different from recursive but still better. Also, since we only hold references to Nodes (rather than copying the whole object), this shouldn't be that much of an additional memory overhead if we are already loading the original tree into memory.
bool areEquivalent(Node r1, Node r2)
{
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
Node n1, n2;
s1.Push(r1);
s2.Push(r2);
while(true) // Need a better check
{
if(s1.getCount() != s2.getCount())
{
return false;
}
if(s1.getCount() == 0) // if both stacks are empty then we've traversed both trees without failure.
{
return true;
}
n1 = s1.Pop();
n2 = s2.Pop();
if(!areEquivalentNodes(n1, n2))
{
return false;
}
foreach(Node child in n1.children)
{
s1.Push(child);
}
foreach(Node child in n2.children)
{
s2.Push(child);
}
}
}
// only checks the two nodes are equivalent. their childrens' equivalence will be handled by other calls to this method.
bool areEquivalentNodes(Node n1, Node n2)
{
if(n1.children.getCount() != n2.children.getCount())
{
return false;
}
if(n1.children.getCount() == 0) // if both are leaf nodes...
{
if(n1.ref != n2.ref)
{
return false;
}
}
else // both are non-leaf
{
if(n1.type != n2.type)
{
return false;
}
// the condition that children of non-leaf nodes be equivalent will be covered by subsequent calls this method...
}
return true;
}
Please note that both solutions expect children of two equivalent nodes in the same order. If children are not ordered then we will need to sort them before calling above code.
Let me know if this is better.

Related

Having Issues with my code comparing two binary trees with different structures

I'm trying to compare series of two binary trees and seeing if they have the same elements in them but the trees can have different structures all recursively.
Here is my current code, the "Find" function is a search the tree function:
private static boolean problem1Recursive(Node t1, Node t2)
{
if(t1 == null || t2 == null)
{
return false;
}
else if(find(t2, t1.key))
{
return true;
}
return (problem1Recursive(t1.left, t2) && problem1Recursive(t1.right, t2));
}
I'm just at a loss on where to go from here
The code you provided seems to be checking if all elements in the first tree exist in the second tree, rather than checking if the two trees have the same elements. But, in your problem statement you have stated that the trees can have different structures and you want to compare if they have the same elements.
Here is one possible solution to your problem:
private static boolean problem1Recursive(Node t1, Node t2) {
if (t1 == null && t2 == null) {
return true;
}
if (t1 == null || t2 == null) {
return false;
}
if (t1.key != t2.key) {
return false;
}
return problem1Recursive(t1.left, t2) || problem1Recursive(t1.right, t2);
}
This function first check if both nodes are null, if they are it returns true. If one of the nodes is null it returns false, indicating that the trees have different elements. If the key of the nodes is different it also returns false. It then recursively checks the left and right subtrees of the first tree against the entire second tree. If at least one of the subtrees contains all the elements of the second tree, the function will return true.
It's important to note that this solution considers that there aren't repeating values on the tree and the values are comparable.

recursive ordered node coloring

I want to color all nodes of a given graph according to a given node ordering: the order is set through the Iterator<Node> nodeIterator parameter which contains all the nodes to process in the right order.
A node is colored if its neighbor is not and if a certain condition between the two considered nodes is met. A node is colored if it is an element of the parameter vector. A node is colored with its pre-defined color.
here's my code:
#Recursive method colorNodes
colorNodes(Graph graph,Iterator<Node> nodeIterator, Vector vector)
if (vector.size() == graph.size())
return true;
node = nodeIterator.next();
nodeNeighbors = node.getNeighbors();
while(nodeNeighbors.hasnext()) {
neighbor = nodeNeighbors.next();
if (!nodeIsColored(vector, neighbor)) {
if(conditionBetweenNodeAndNeighbor is true) {
vector.add(node) #color current node
colorNodes(graph, nodeIterator,vector)#call recursively the method
}
}
else if (!nodeNeighbors.hasNext()) {
#potential last node or isolated node (having one neighbor only)
if(conditionBetweenNodeAndNeighbor is true) {
vector.add(node) #color last node anyway
colorNodes(graph, nodeIterator,vector)#call recursively the method
}
}
else {
continue;
}
return false;
}
Could anyone clarify how to approach this problem and if my approach is correct (especially the cases differentiation)?
I merely give an answer as the recursion is a bit awkward. I would expect the following - not regarding the logic.
// Recursive method colorNodes
void colorNodes(Graph graph, Iterator<Node> nodeIterator, List<Node> vector)
//if (vector.size() == graph.size())
// return true;
if (!nodeIterator.hasNext()) {
return;
}
Node node = nodeIterator.next();
if (nodeIsColored(vector, node)) {
return;
}
// Here the node is processed before the children, to stop recursion.
​vector.add(node);
for (Node neighbor: node.getNeighbors()) {
//if (!nodeIsColored(vector, neighbor)) {
colorNodes(graph, nodeIterator,vector);
//}
}
// Here the node could be processed after the children.
}
Vector<> is the old class, and still lives under that name in for instance C++.
I am not sure I fully understood the requirement. Please check this pseudo code:
//Recursive method colorNodes
colorNodes(Graph graph,Iterator<Node> nodeIterator, Vector vector){
if (vector.size() == graph.size()) return true;
node = nodeIterator.next();
neighbors = node.getNeighbors()
//check if leaf or isolted or all neigbors colored
if( (! nodeIterator.hasNext()) or (neighbor.length == 0) or (allNodesAreColored(neighbors)) ) {
//color leaf
if(conditionBetweenNodeAndNeighbor is true) {
vector.add(node)
node.setColor(color)
// no need for recursive call for a leaf
}
return;
}
for(neighbor : neighbors ){
if ((!nodeIsColored(vector, neighbor) and
(conditionBetweenNodeAndNeighbor is true) ){
vector.add(node)
node.setColor(color)
colorNodes(graph, nodeIterator,vector)
//break if you don't want to check rest of the neighbors
}
}
}

Java Circular Linked List,Remove Node not working properly

Ok so i need to deleted items from a circular list,as part of a bigger program that isnt working, and i cant seem to delete the last node passed in to the delete method, if the index passed in is 1 it will delete the 1st node in list and replace it, but when there is only one node left it has nothing to reference off, been at this hours. i will leave my delete method here
public void delete(int index)
{
if(Node.numOfUsers == 1)
{
first=null;
return;
}
//make curr the same as first node
int i = 1;
curr=first;
//if index passed in is 1, make temporary node same as one after first node
// if(size<1)
// {
// System.out.println("ok so this is where we are at");
// }
if(index==1)
{
temp=first.nextNode;
while(temp.nextNode!=first)
{
temp=temp.nextNode;
}
temp.nextNode=temp.nextNode.nextNode;
first=curr.nextNode;
}
else
{
//as long as i is not equal to node index-1 move current on 1 and increment i by 1
while(i != index-1)
{
curr=curr.nextNode;
i++;
}
//curr.nextNode is pointing to the node index we want and making it equal to one index above it
curr.nextNode=curr.nextNode.nextNode;
}
Node.numOfUsers--;
int size=size();
}
}
Looks like you're keeping track globally of a number of users. If this behaves the way I think it would, you could just have a small check at the beginning of this method so that if it is zero, you don't follow through with any of the logic following it.
if(Node.numOfUsers == 0) return;
This will make it so you don't bother executing any of the other logic.
A slightly better methodology to this problem might be to use the Node you want to delete as a parameter, rather than its index. This way you can avoid having to keep track of indices inside your data structure.
e.g.
public void delete(Node n) {
if(Node.numOfUsers == 0 || n == null) return; // 0 nodes or null parameter.
Node temp = first;
if(temp.next == null) { //only one node
temp = null; //simply delete it
} else {
while(temp.next != n) {
temp = temp.next;
if(temp == first) { //if we circle the entire list and don't find n, it doesn't exist.
return;
}
}
temp.next = n.next; // perform the switch, deleting n
}
}
EDIT: The above code follows the assumption that you'll have references to the node you want to delete. If this is not the case, using indices is just as good. You may also consider comparing values, however this would require you to assume that you have unique values in your nodes (and I don't know what you're restrictions are).
The logic for comparing values would be identical to the above, however instead of comparing if(temp == n) for example, you would compare if(temp.data.equals(n.data)). The use of the .equals() method is specifically for the String type, but you could modify it to work with whatever data type you are expecting, or better yet write a custom .equals method that allows the use of Generics for your abstract data type.

Identify loop or recursion in the list

I want to identify the loop or recursion in the list for the below structure of the node. How can I identify the same?
public class EntityNode {
private EntityNode nextNode; // Points to the next node
}
Example,
Node1 -> Node2 -> Node3 -> Node4 -> Node5 -> Node6 -> Node4
Here, you can see that Node6 is pointing to Node4, and here there comes the looping or recursion and my code will go into infinite. So what if I want to find out this type of scenario with the optimum performance level?
This is actually an interview question I have heard a few times. While I have never tried to implement any sort of loop detection, the answer that most of the interviewers seemed to like is iterating through the list and storing the visited nodes in a hashtable. If you get a collision while storing into the table, then you have a loop in your list.
Edit: In an attempt to offer some code for the example, here is what I would probably try to do (assuming you have some sort of LinkedList<EntityNode> object). I updated this to use a HashSet instead of a HashMap so it was more straightforward (as pointed out by PM 77-1).
public bool detectLoop(LinkedList<EntityNode> list)
{
Set<EntityNode> nodeSet = new HashSet<EntityNode>();
EntityNode curNode = list.getHead();
boolean loopDetected = false;
if(curNode != null)
{
while(curNode.getNextNode() != null && !loopDetected)
{
cureNode = curNode.getNextNode();
loopDetected = !nodeSet.add(curNode);
}
}
return loopDetected;
}
I haven't had the opportunity to test this, but this should work. The reason being that the add() method for a HashSet returns true if this set did not already contain the specified element. So if there is a EntityNode already exists in the set, it will return false, meaning that there was a loop detected.
Since my answer has sort of taken off, I want to say that there are other solutions to this as well. The other one that has been pointed out in this thread is the tortoise and the hare algorithm. You can find more information on that in this thread or at this wiki page.
You should have two EntityNode objects. Both start at Node1. Have the first object move two nodes down, and the second only move one node down. Repeat this until you either reach the end (there was no cycle) or the two objects meet at the same node (there is a cycle).
For your example:
n1: Node1, n2: Node1
n1: Node3, n2: Node2
n1: Node5, n2: Node3
n1: Node4, n2: Node4 -> cycle!!
For pseudocode:
while (n1.nextNode isn't null):
n1 = n1.nextNode.nextNode
n2 = n2.nextnode
if (n1 equals n2): return 'there is a loop!'
I searched on the net and found that this type of problem is called the tortoise and hare algorithm. The Wikipedia page is also here for the same.
As codaddict states in their answer here:
The idea is to have two references to the list and move them at
different speeds. Move one forward by 1 node and the other by 2 nodes.
If the linked list has a loop they will definitely meet.
Else either of the two references(or their next) will become null.
Java code implementing the algorithm:
boolean hasLoop(EntityNode first) {
if (first == null) // list does not exist..so no loop either.
return false;
EntityNode slow, fast; // create two references.
slow = fast = first; // make both refer to the start of the list.
while (true) {
slow = slow.nextNode; // 1 hop.
if (fast.nextNode != null)
fast = fast.nextNode; // 2 hops.
else
return false; // next node null => no loop.
if (slow == null || fast == null) // if either hits null..no loop.
return false;
if (slow == fast) // if the two ever meet...we must have a loop.
return true;
}
}
I think you can make a "visited" flag. Or you can use unintersecting sets, which helps to identify loops in O(N *log N).
P.S. I must admit that this method is more appropriate if you need to build a graph without cycles.
I like Bhavik's answer if you are constrained by memory limits. It doesn't create any possibly large objects to determine the answer.
If there is a loop then the single step and double step methods of walking through the EntityNodes will have to intersect.
Here is sample code to test with -
public class EntityNode {
private EntityNode nextNode = null; // Points to the next node
public static void main(String[] args) {
final EntityNode head = new EntityNode();
// Create small sample (test with even and odd number)
EntityNode tail = head;
for (int i = 0; i < 6; i++) {
EntityNode newNode = new EntityNode();
tail.nextNode = newNode;
tail = newNode;
}
// Add "loop" node
tail.nextNode = head;
System.out.println(detectLoop(head));
}
// Return true if a loop is found
private static boolean detectLoop(EntityNode head) {
boolean loopDetected = false;
if (head != null) {
EntityNode singleStep = head;
EntityNode doubleStep = head;
// If either EntityNode is null and end has been found
while ((singleStep.nextNode != null)
&& (doubleStep.nextNode != null)) {
singleStep = singleStep.nextNode;
// Assert doubleStepper.nextNode != null
doubleStep = doubleStep.nextNode.nextNode;
// If there is a "Collision" then there is a loop
loopDetected = (doubleStep == singleStep);
if (loopDetected) {
break;
}
}
}
return loopDetected;
}
Just traverse the list while keeping every visited node in a hash set. If the node you are adding is ever already present in the set, you have a cycle.
A.-Keep count of the amount of added nodes. Then start a loop through them, while counting the loops. If loopsAmount>nodesAmount, you have recursion.
B.-Keep track of the visited nodes. If a node is visited twice, you have recursion.
C.-Index the nodes while creating them. If node.nextNode.Index-1 != node.Index, you have recursion.

Using recursively returned reference to node in tree does not allow changes to the node itself

My data structures class is working with trees. We are implementing a 3-ary tree, containing 2 values with a reference to a left, middle, and right node (left subtree is less than value 1, middle subtree is between value 1 and value 2, right subtree is greater than value 2). An interface has been provided for the Tree class, and the find, insert, and delete methods must be recursive. The client code which this will be tested against uses the insert method repeatedly to create the tree, and the root starts off as null.
I'm trying to insert values into the tree recursively by finding the parent node in a separate private method, then changing the returned node as appropriate. The problem currently is that the method returns the initial node, which is the root, and correctly creates a new node with the value because the root is null. However, the root remains null.
I'm pretty certain this is due to the way that references and values work in Java (similar to C# as described in this article by Jon Skeet); given the constraints, how should I change this to allow insertions into the tree? Below is the current insert method in the tree class, along with the similar private method.
public void insert(AnyType newData)
{
// If insert node is null, make a new node with newData as first key
TernaryNode<AnyType> insert_node = findNode(newData, root);
if (insert_node == null)
{
insert_node = new TernaryNode<AnyType>(newData);
}
else
{
// Get the key that is equal if the insert node is not null
if (insert_node.getKey1() == null)
{
insert_node.setKey1(newData);
}
else
{
insert_node.setKey2(newData);
}
}// end else
}// end insert
private TernaryNode<AnyType> findNode(AnyType item, TernaryNode<AnyType> node)
{
TernaryNode<AnyType> current_node = node;
if (current_node != null)
{
if (current_node.getKey1() != item &&
current_node.getKey2() != item)
{
// Comparator checks left
if (compare.compare(current_node.getKey1(), item) <= -1)
{
return findNode(item, current_node.left);
} // Comparator checks right
else if (compare.compare(current_node.getKey2(), item) >= 1)
{
return findNode(item, current_node.right);
}// Comparator checks middle
else
{
return findNode(item, current_node.middle);
}
}// end while
}// end if
// Return current node even if it is null
return current_node;
}// end findNode
Unless you're assigning something to the root member, it will never acquire a value. You probably need some sort of outer container for your tree, similarly to how an XML document (which is also a tree) has an outer Document object which is distinct from the actual document root node.
TernaryNode<AnyType> insert_node = findNode(newData, root);
if (insert_node == null)
{
insert_node = new TernaryNode<AnyType>(newData);
root = insert_node;
}

Categories

Resources