Parse Nodes in a Java Tree Structure in Vector of Strings - java

I have a data structure that looks like this
private String name;
private ArrayList<Node> children;
private String parent="";
public Node(String name) {
setName(name);
children = new ArrayList<Node>();
}
Elsewhere in my program, I have a Node called "root" that contains an entire tree data structure.
Conceptually it looks like this
root
/ \
/ \
node1 node2
/ \
/ \
node2 node3
/
/
node3
As you can see nodes can have the same name. That's intended. I want to create a string for each node that contains its own name, plus it's lineage and store them in a Vector.
so node 3 on the left hand side would be "root|node1|node2|node3" the node3 on the rhs would be "root|node2|node3" node1 would be "root|node1"etc.
I have a way to iterate through the node structure to print each node, but I'm finding it difficult to set every parent, as in, I can't figure out a way to do it. Any help would be fantastic as everything I've tried so far has failed. One important note is that the tree may not necessarily be a Binary tree, I'm just using it for an example.
Here's the code I use for printing every node of the tree. Hopefully it will be easy to tweak.
public void print() {
LinkedList<Node> open = new LinkedList<Node>();
LinkedList<Node> closed = new LinkedList<Node>();
open.add(this);
while(!open.isEmpty()) {
Node currentNode = open.removeFirst();
System.out.println(currentNode.getName());
ArrayList<Node> children = currentNode.getChildren();
closed.add(currentNode);
for(int i = 0; i < children.size(); i++) {
Node current = children.get(i);
open.addLast(current);
}
}
}
Thanks guys.

I'm assuming that you already have these nodes created and they were created with children but without the parent? Seems like there are a few options:
When creating the children, set the parent (I would think you don't really have control over this because you are asking this question) so...
Instead of a Vector maybe use some type of Map where you can set the key as the lineage. Then when you iterate over the nodes do some string tweaking to remove the current node's name and you are left with the parent lineage.
Related to #2, don't use a Map (and keep the Vector) and still do the string manipulation but you would then have to iterate every node in the Vector to look for the parent by its lineage.
Hope this helps and hopefully I assumed correctly
-Dave

it seems that it would be easier to add the parent as you are building the tree but if you have the tree built and want to add a parent to each node you can use recursion.
I'd try something like
addParent(root, "");
public void addParent(Node node, String parent) {
node.setParent(parent);
// if this node has children iterate through them
// and call addParent with current node name.
for(Node childNode : node.getChildren()) {
addParent(childNode, node.getName());
}
}
NOTE: I was not able to test this code before posting.

Related

How to merge Trees together where the root of one tree equals the root of a other tree?

I am currently trying to implement a tree(not binary, order doesn't matter , not-directed) data structure.
I want to merge Trees together when one Tree's root is the same as a children node of a other Tree.
Than the children of first tree should become children of the second tree children which is the same as the root of the first tree.
The trees to be merged could be deeper.
For example(The numbers are the identifier/Names of the vertices):
I implemented the TreeNode.java like this:
public class TreeNode {
private TreeNode parent;
private List<TreeNode> children;
private IP vertexName;
private int height;
//This creates the root vertex, of the Tree.
public TreeNode(IP vertexName) {
this.vertexName = vertexName;
this.parent = null;
this.height = 0;
this.children = new ArrayList<>();
}
//This is for creating other members of a tree besides the root, the children vertices.
public TreeNode(TreeNode parentTreeNode, IP vertexName) {
this.children = new ArrayList<>();
this.parent = parentTreeNode;
this.height = (parentTreeNode.getHeight() + 1);
this.vertexName = vertexName;
parentTreeNode.children.add(this);
}
public void addChildren(List<IP> verteciesIPs) throws NotATreeException {
areValidChildren(verteciesIPs);
for (IP ip:verteciesIPs) {
TreeNode treeNode = new TreeNode(ip);
treeNode.setParent(this);
treeNode.setHeight(this.getHeight() + 1);
this.children.add(treeNode);
}
}
public void addChild(TreeNode treeNodeChildren) {
treeNodeChildren.setParent(this);
treeNodeChildren.setHeight(this.getHeight() + 1);
this.children.add(treeNodeChildren);
}
public void areValidChildren(final List<IP> verteciesIPs) throws NotATreeException {
if (hasDuplicateChildren(verteciesIPs)) {
throw new NotATreeException("Duplicate entries");
}
I then have a list of trees List<TreeNode> treeTopology I want to merge together.
But I am not quite sure how to do that since I not only need to check if the children node are the same as the root node of a given Tree.
But also the children childrens and so on.
I hope somebody can help me with that.
I didn't post the whole code for simplification sake.
I tried iterating over the List<TreeNode> treeTopology with two for-loops and another for-loop for the children. But that approach doesn't seem to work very well. Because I can only compare the children and would need one more for loop for every children's children.
You could probably implement a function to just check if the tree contains() a given number, then you could just call that function every time you want to add a new value. if tree contains() number continue else add number as child of the node to add to. You could try looking into DFS or BFS, since your tree resembles a graph more than an actual tree.

Doing a DFS on a neo4j graph

I have a database with the following structure.
The property node is of the type
create (A:Property {value:"abc"})
How to do a dfs so that it will be able to print all the values in the graph.In the order A->B->E->F->C->G->H->D->I->J
The relationship r is in the downward direction(single direction) with no properties.I have tried this link but looks complex to me.
Is there an easier way to do a simple dfc on an already existing Neo4j database
The link you linked to is very verbose to cover all the different things you can do with Neo4j's powerful Traversal API.
I think all you have to do is this:
TraversalDescription traversalDescription = graphDb.traversalDescription()
.depthFirst()
.relationships(YourRelationShipTypeR, Direction.OUTGOING);
Node a = ... // however you find your node A
try(ResourceIterator<Node> nodes =traversalDescription.traverse(a)
.nodes()
.iterator()){
while(nodes.hasNext()){
Node n = nodes.next();
//or whatever property name you use to get your names for nodes
System.out.print(n.getProperty("id") + "->");
}
}
Should print A->B->E->F->C->G->H->D->I->J->
You can make the print statement smarter by not appending the arrow at the last node but I'll leave that up to you
EDIT
After trying the code myself I got a depth first search but the iterator order was out of order. It seemed it arbitrarily picked which child node to walk first. So I got output like A->D->J->I->C->H->G->B->F->E->.
So you have to sort the returned Paths of the TraversalDescription which has a sort(Comparator<Path> ) method.
To match the traversal you want, I sorted the paths by the node property that gives the node its name, which I called "id". Here's my updated traversal code:
TraversalDescription traversalDescription = graphDb.traversalDescription()
.depthFirst()
.sort(new PathComparatorByName())
.relationships(YourRelationShipTypeR, Direction.OUTGOING);
Where PathComparatorByName is a comparator I wrote that sorts Paths based on the nodes traversed in the path lexigraphically sorted by name:
private class PathComparatorByName implements Comparator<Path>{
#Override
public int compare(Path o1, Path o2) {
Iterator<Node> iter1 = o1.nodes().iterator();
Iterator<Node> iter2 = o2.nodes().iterator();
while(iter1.hasNext()){
if(!iter2.hasNext()){
//return shorter path?
return 1;
}
Node n1 = iter1.next();
Node n2 = iter2.next();
int nodeCmp = compareByNodeName(n1, n2);
if(nodeCmp !=0){
return nodeCmp;
}
}
if(iter2.hasNext()){
//return shorter path?
return -1;
}
return 0;
}
private int compareByNodeName(Node node1, Node node2) {
String name1 = (String)node1.getProperty("id");
String name2 = (String)node2.getProperty("id");
return name1.compareTo(name2);
}
}
Rerunning it now with the comparator will output:
A->B->E->F->C->G->H->D->I->J->

Basic java: getting a list of attached nodes

so I have a list of basic nodes, for example nodes A B C.
each component can see what it is attached to for example:
a->b
b->c
c->a
I want a way that I can get a list of all the nodes in the graph. However, I'm running into trouble as my current system can't detect if it has already reached a point. EG in the above example it will go a->b->c->a->b etc. How can I detect this or how can I solve this problem.
My current "solution" getList() in the Node class:
ArrayList<Node> tempList = new ArrayList<Node>();
tempList.add(this);
for(int i = 0 ; i < nodesAttachedTo.size();i++){
tempList.addAll(nodesAttachedTo.get(i).getList());
}
return tempList;
You can use a HashSet. It will not allow one element to be added twice.
Here's an example code that first creates the graph similar to your example, then starts at some point in the graph and goes through it.
import java.util.HashSet;
public class Node
{
private HashSet<Node> nextNodes = new HashSet<Node>();
public Node()
{
}
public void addNextNode(Node node)
{
nextNodes.add(node);
}
public static void main(String[] args)
{
// this builds the graph of connected nodes
Node a = new Node();
Node b = new Node();
Node c = new Node();
a.addNextNode(b);
b.addNextNode(c);
c.addNextNode(a);
//this is the set that will lsit all nodes:
HashSet<Node> allNodes = new HashSet<Node>();
// this goes through the graph
a.listAllNodes(allNodes);
System.out.println(allNodes);
}
private void listAllNodes (HashSet<Node> listOfNodes)
{
// try to put all next nodes of the node into the list:
for(Node n : nextNodes)
{
if (listOfNodes.add(n)) // the set returns true if it did in fact add it.
n.listAllNodes(listOfNodes); // recursion
}
}
}
This goes from one node to all the nodes this node knows. (say that really fast three times)
Until it hits a dead end (= a node it already visited)
I chose to use a HashSet in the Node itself to store all the nodes it knows.
This could also be an ArrayList or whatever. But as I don't think there should be a connection twice, a HashSet seems to be a good choice in this situation, too.
I'm not familiar with your notation, but you could use two pointers to solve your issue. Start with two pointers that point to the same node. Increment one pointer until it returns to the start. Some pseudocode is below.
ArrayList<Node> tempList = new ArrayList<Node>();
Node head = nodesAttachedTo.get(0); //get the head of the list
tempList.add(head);
Node runner = head;
runner = runner.next;
while (!runner.equals(head)) {
tempList.add(runner);
runner = runner.next;
}
A hashmap is probably the way to go here. It allows constant time access (some overhead required, but I'm assuming you want a solution that scales well) to any element in the map.
HashMap<String, String> specificSolution = new HashMap<String, String>();
specificSolution.put("a", "b");
specificSolution.put("b", "c");
specificSolution.put("c", "a");
// To get all nodes in the graph
Set<String> nodes = specificSolution.keySet();
I implemented with String here because you don't provide a definition for the Node Class in your question, but it can be easily swapped out.
There are many different ways to represent a graph and each has their own limitations/advantages. Maybe another might be more appropriate but we would need more information about the problem.

I need to delete a node in a linked list, how do I find the node that comes BEFORE it so I can rearrange the list?

It's for a school assignment. I have to use a search method that returns the node that I search for or the one right before it if it doesn't exist. Obviously if I want to delete a node it'll return that one node and I won't be able to find the one that comes before it. Here's the code for the search method:
private myNode search(myEntry searchEntry)
{
myNode ref = first;
myNode pre = null;
while(ref != null)
{
if(searchEntry.compareTo(ref.data) < 0)
break;
pre = ref;
ref = ref.link;
}
return pre;
}
first is the first node, ref is the pointer, pre is the node preceding the pointer.
Maybe I'll use a doubly-linked list if it doesn't require me to rewrite things too much but if there's a simple way to find the predecessor of the node I'm trying to delete using this search method then I'd like to know. I'm not supposed to be using doubly-linked lists at all.
You can't do that with your search method. You have to implement a distinct search method that return the predecessor of the node and then delete it.
If you need to delete ref, than you return pre. To delete ref, you can write something like
pre = list.search(entry); //find the prescending node
ref = pre.link; //get the node you want to delete
pre.link = ref.link; //reassign link
ref.delete(); //delete node

Shortest path (fewest nodes) for unweighted graph

I'm trying build a method which returns the shortest path from one node to another in an unweighted graph. I considered the use of Dijkstra's but this seems a bit overkill since I only want one pair. Instead I have implemented a breadth-first search, but the trouble is that my returning list contains some of the nodes that I don't want - how can I modify my code to achieve my goal?
public List<Node> getDirections(Node start, Node finish){
List<Node> directions = new LinkedList<Node>();
Queue<Node> q = new LinkedList<Node>();
Node current = start;
q.add(current);
while(!q.isEmpty()){
current = q.remove();
directions.add(current);
if (current.equals(finish)){
break;
}else{
for(Node node : current.getOutNodes()){
if(!q.contains(node)){
q.add(node);
}
}
}
}
if (!current.equals(finish)){
System.out.println("can't reach destination");
}
return directions;
}
Actually your code will not finish in cyclic graphs, consider graph 1 -> 2 -> 1. You must have some array where you can flag which node's you've visited already. And also for each node you can save previous nodes, from which you came. So here is correct code:
private Map<Node, Boolean>> vis = new HashMap<Node, Boolean>();
private Map<Node, Node> prev = new HashMap<Node, Node>();
public List getDirections(Node start, Node finish){
List directions = new LinkedList();
Queue q = new LinkedList();
Node current = start;
q.add(current);
vis.put(current, true);
while(!q.isEmpty()){
current = q.remove();
if (current.equals(finish)){
break;
}else{
for(Node node : current.getOutNodes()){
if(!vis.contains(node)){
q.add(node);
vis.put(node, true);
prev.put(node, current);
}
}
}
}
if (!current.equals(finish)){
System.out.println("can't reach destination");
}
for(Node node = finish; node != null; node = prev.get(node)) {
directions.add(node);
}
directions.reverse();
return directions;
}
Thank you Giolekva!
I rewrote it, refactoring some:
The collection of visited nodes doesn't have to be a map.
For path reconstruction, the next node could be looked up, instead of the previous node, eliminating the need for reversing the directions.
public List<Node> getDirections(Node sourceNode, Node destinationNode) {
//Initialization.
Map<Node, Node> nextNodeMap = new HashMap<Node, Node>();
Node currentNode = sourceNode;
//Queue
Queue<Node> queue = new LinkedList<Node>();
queue.add(currentNode);
/*
* The set of visited nodes doesn't have to be a Map, and, since order
* is not important, an ordered collection is not needed. HashSet is
* fast for add and lookup, if configured properly.
*/
Set<Node> visitedNodes = new HashSet<Node>();
visitedNodes.add(currentNode);
//Search.
while (!queue.isEmpty()) {
currentNode = queue.remove();
if (currentNode.equals(destinationNode)) {
break;
} else {
for (Node nextNode : getChildNodes(currentNode)) {
if (!visitedNodes.contains(nextNode)) {
queue.add(nextNode);
visitedNodes.add(nextNode);
//Look up of next node instead of previous.
nextNodeMap.put(currentNode, nextNode);
}
}
}
}
//If all nodes are explored and the destination node hasn't been found.
if (!currentNode.equals(destinationNode)) {
throw new RuntimeException("No feasible path.");
}
//Reconstruct path. No need to reverse.
List<Node> directions = new LinkedList<Node>();
for (Node node = sourceNode; node != null; node = nextNodeMap.get(node)) {
directions.add(node);
}
return directions;
}
You must include the parent node to each node when you put them on your queue. Then you can just recursively read the path from that list.
Say you want to find the shortest path from A to D in this Graph:
/B------C------D
/ |
A /
\ /
\E---------
Each time you enqueue a node, keep track of the way you got here.
So in step 1 B(A) E(A) is put on the queue. In step two B gets dequeued and C(B) is put on the queue etc. Its then easy to find your way back again, by just recursing "backwards".
Best way is probably to make an array as long as there are nodes and keep the links there, (which is whats usually done in ie. Dijkstra's).
Every time through your loop, you call
directions.Add(current);
Instead, you should move that to a place where you really know you want that entry.
It is really no simpler to get the answer for just one pair than for all the pairs. The usual way to calculate a shortest path is to start like you do, but make a note whenever you encounter a new node and record the previous node on the path. Then, when you reach the target node, you can follow the backlinks to the source and get the path. So, remove the directions.add(current) from the loop, and add code something like the following
Map<Node,Node> backlinks = new HashMap<Node,Node>();
in the beginning and then in the loop
if (!backlinks.containsKey(node)) {
backlinks.add(node, current);
q.add(node);
}
and then in the end, just construct the directions list in backwards using the backlinks map.

Categories