I have the following code (apologies it's a little long), which works:
public class Node {
public String name;
public List<Node> children = new ArrayList<>();
}
private Node root = new Node();
public static void main(String[] args)
{
TestCreateHierarchy obj = new TestCreateHierarchy();
obj.run();
}
public void run()
{
List<List<String>> objects = new ArrayList<>();
String[] str = {"Person","Manager","Hourly","New"};
objects.add(Arrays.asList(str)) ;
String[] str2 = {"Person","Manager","Salary","Hello"};
objects.add(Arrays.asList(str2)) ;
String[] str3 = {"Person","Manager","Salary", "New"};
objects.add(Arrays.asList(str3)) ;
// String[] str4 = {"Person","Manager","Salary", "New", "John"};
// objects.add(Arrays.asList(str4)) ;
root.name = "ROOT";
for (List<String> seq : objects) {
LOG.debug("------------- NEW SEQUENCE -----------");
LOG.debug(seq);
LOG.debug("--------------------------------------");
insert(seq);
// break;
}
LOG.debug(root.children.size() + " <-- should be 1 ");
}
public Node createNode(List<String> seq, Integer start)
{
if (start >= seq.size())
return null;
Node node = new Node();
node.name = seq.get(start);
node.children.add(createNode(seq, start+1));
return node;
}
public void insert(List<String> seq) {
List<Node> children = root.children;
// Where should we start to build the tree (how
// deep into the sequence?)
int start = 0 ;
// Find the right place to add
for (int i=0; i<seq.size(); i++) {
boolean foundMatchingNode = false;
// if (children.size() == 0)
// continue;
if (children.size() > 0) {
for (Node node : children) {
LOG.debug("HERE --> " + node.name);
if (node.name.equals(seq.get(i))) {
children = node.children;
foundMatchingNode = true;
break;
}
}
}
if (!foundMatchingNode) {
children.add(createNode(seq,i));
break;
}
}
}
My issue is that when I uncomment the str4 part, I get a NullPointerException referring to the insert method, specifically to the for (Node node : children) part.
What do I need to change so that this code works with different hierarchy depths?
The problem is in this function:
public Node createNode(List<String> seq, Integer start)
{
if (start >= seq.size())
return null;
Node node = new Node();
node.name = seq.get(start);
node.children.add(createNode(seq, start+1));
return node;
}
You are adding a child to each newly created node recursively and for the last function call where this condition (start >= seq.size()) satisfies you create a null child.
So, after the insertion of str1, your tree looks like this:
ROOT->Person->Manager->Hourly->New->NULL. Now when you try to enter the str4 your logic for checking matching node name code comes into play. The loop runs fine for entries: Person, Manager, Hourly, New until it runs for the node which is NULL. In the inner for loop for (Node node : children) you have this debugger log: LOG.debug("HERE --> " + node.name);. It is at this point you're getting NullPointerException since your node is null.
Your createNode method is creating adding a null child to the leaf. The NullPointerException occurs because the Node itself is null when you get to the bottom of the tree.
If this is not enough of a hint, please ask for more.
Related
Given two binary trees with head reference as T and S having at most N nodes. The task is to check if S is present as subtree in T.
A subtree of a tree T1 is a tree T2 consisting of a node in T1 and all of its descendants in T1.
Why my approach is fail?
my algo is :-
Find inorder and preorder traversals of T, store them in two lists.
Find inorder and preorder traversals of S, store them in two lists.
If inorder and preorder lists of T occurs in inorder and preorder lists of S then return true else false.
import java.util.LinkedList;
import java.util.Queue;
import java.io.*;
import java.util.*;
class Node{
int data;
Node left;
Node right;
Node(int data){
this.data = data;
left=null;
right=null;
}
}
class GfG {
static Node buildTree(String str){
if(str.length()==0 || str.charAt(0)=='N'){
return null;
}
String ip[] = str.split(" ");
// Create the root of the tree
Node root = new Node(Integer.parseInt(ip[0]));
// Push the root to the queue
Queue<Node> queue = new LinkedList<>();
queue.add(root);
// Starting from the second element
int i = 1;
while(queue.size()>0 && i < ip.length) {
// Get and remove the front of the queue
Node currNode = queue.peek();
queue.remove();
// Get the current node's value from the string
String currVal = ip[i];
// If the left child is not null
if(!currVal.equals("N")) {
// Create the left child for the current node
currNode.left = new Node(Integer.parseInt(currVal));
// Push it to the queue
queue.add(currNode.left);
}
// For the right child
i++;
if(i >= ip.length)
break;
currVal = ip[i];
// If the right child is not null
if(!currVal.equals("N")) {
// Create the right child for the current node
currNode.right = new Node(Integer.parseInt(currVal));
// Push it to the queue
queue.add(currNode.right);
}
i++;
}
return root;
}
static void printInorder(Node root){
if(root == null)
return;
printInorder(root.left);
System.out.print(root.data+" ");
printInorder(root.right);
}
public static void main (String[] args) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
int t=Integer.parseInt(br.readLine());
while(t-- > 0){
String tt= br.readLine();
Node rootT = buildTree(tt);
String s= br.readLine();
Node rootS = buildTree(s);
// printInorder(root);
Solution tr=new Solution();
boolean st=tr.isSubtree(rootT, rootS);
if(st==true){
System.out.println("1");
}else{
System.out.println("0");
}
}
}
}// } Driver Code Ends
class Solution {
// algo implementation is started from here.
public static void preorder(Node root , ArrayList<Integer>al )
{
if(root!=null)
{
al.add(root.data);
preorder(root.left, al);
preorder(root.right, al);
}
}
public static void inorder(Node root, ArrayList<Integer>al)
{
if(root!=null)
{
inorder(root.left, al);
al.add(root.data);
inorder(root.right, al);
}
}
public static boolean isSubtree(Node t, Node s)
{
ArrayList<Integer> alt1 = new ArrayList<>();
ArrayList<Integer>alt2 = new ArrayList<>();
ArrayList<Integer> als1 = new ArrayList<>();
ArrayList<Integer>als2 = new ArrayList<>();
preorder(t,alt1);
inorder(t,alt2);
preorder(s,als1);
inorder(s,als2);
if(alt1.containsAll(als1) && alt2.contains(als2))
return true;
return false;
}
}
~~~
you approch is right, you are checking is arraylist of S has all the values present in array list of T
just change this part
als1.containsAll(alt1) && als2.contains(alt2) to if(alt1.containsAll(als1) && alt2.contains(als2)) return true;
Write the method removeFirst, member of class LinkedList, that removes the first occurrence of every element that appears more than once in the list. Do not use any auxiliary data structures and do not call any methods. The method signature is public void removeFirst().
Example 4.1. If the list contains: B => A => A => R => C => A => C => R, then
after calling removeFirst, its content becomes B => A => A => C => R.
I solved it as a member of class Arraylist and I used auxiliary data structures.
public void removeFirst() {
Node<T> traverse = head;
int[] array = new int[10];
int[] repeat = new int[10];
int count=0;
int rcount=0;
boolean isAlready = false;
while (traverse!=null)
{
for (int i=0; i<count; i++)
{
if (array[i]==traverse.value)
{
isAlready=true;
break;
}
}
if(!isAlready)
array[count++] = traverse.value;
else
repeat[rcount++] = traverse.value;
traverse = traverse.next;
}
traverse= head;
while (traverse!=null)
{
for (int i=0; i<rcount; i++)
traverse=traverse.next;
}
}//
any idea how this can be solved as member of likedlist class without using any auxiliary data structure and all you can use is the
public class Node<T> {
public T data;
public Node<T> next;
public Node () {
data = null;
next = null;
}
public Node (T val) {
data = val;
next = null;
}
// Setters/Getters...
}//End of class Node
public class LinkedList<T> { //LinkedList class
private Node<T> head;
private Node<T> current;
public LinkedList () {
head = current = null;
}
I come across this problem while I was studying for Data Structure Course it's kinda hard but here is what I did.
public void removeFirst() {
int counter = 0 ;
Node<T> tmp = null ;
Node<T> comp = head ;
current = head ;
Node<T> secHead = null ;
Node<T> secCurr = null ;
boolean check = false ;
boolean control = true ;
while(current.next != null || current == null) {
counter = 0 ;
comp = head ;
while(comp.next != null) { // we iterate using node through original list to check for occurences
if(comp.data == current.data) {
counter++;
}
comp = comp.next ;
}
if(comp.data == current.data) {
counter++;
}
tmp = current ;
if(counter >= 2) {
check = false ;
secCurr = secHead ;
while(secCurr != null) { // check for deleting to avoid multiple deletes
if(tmp.data.equals(secCurr.data)) {
check = true ;
break ;
}
secCurr = secCurr.next ;
}
secCurr = secHead ;
if(!check) { // deleting and adding to our secondary linkedlist to check it later :)
remove();
control = false ;
Node<T> tmp2;
if (secHead == null) {
secHead = new Node<T> (tmp.data);
secCurr = secHead ;
}
else {
tmp2 = secCurr.next;
secCurr.next = new Node<T> (tmp.data);
secCurr = secCurr.next;
secCurr.next = tmp2;
}
}
}
if(control) { // remove() increment the current this is for checking
current = current.next ;
}
control = true ;
}
}
by using the properties of class node you can make secondary LinkedList but not using the class itself hence we never used auxiliary data structure. you need to know how the internal methods work specifically. read the code carefully : )
I started by taking the elements in reverse order and saw if there were repeated elements on the right side and then checked from the left side.
The only case you need to delete is when the repeated elements are on the right side only.
At the end of the code, I made one case to check the head element.
public void removeFirst() {
Node<T> c=head;
Node<T> b;
Node<T> q;
int size=0;
while(c!=null) { //Counting the size of the list
size++;
c=c.next;
}
for(int i=0;i<size;i++) {//Going through the list
c=head;
for(int j=0;j<size-i-1;j++) //Getting the elements in reverse order
c=c.next;
if(c.next!=null) {
b=c.next;
while(b!=null) {
if(c.getData().equals(b.getData())){ //Check repeated elements on the right side
q=head;
while(q.next!=c) {
if(q.getData().equals(c.getData()))//Check repeated elements on the left side
break;
q=q.next;
}
if(!q.getData().equals(c.getData())) {//Deletion occurs when there are elements on the right side only.
q.next=c.next;
break;}
}
b=b.next;
}
}
}
q=head;//We only needed to check the head once, so I separated the check from the loop.
b=head.next;
while(b!=null) {
if(q.getData().equals(b.getData())&&size!=0) {
head=head.next;
break;}
else
b=b.next; }
}
List<String> list = new LinkedList<String>();
Set<String> set = new LinkedHashSet<String>();
list.add("B"); list.add("A"); list.add("A"); list.add("R");
list.add("C");list.add("A");list.add("C");list.add("R");
for (String string : list) {
if (Collections.frequency(list, string) > 1) {
set.add(string);
}
}
for (String string : set) {
list.remove(string);
}
System.out.println(list);
public class node {
int data ;
node next = null ;
//constructor
public node(int newdata){
data = newdata ;
next = null ;
}
//-----------------------------TROUBLE FUNCTION----------------
public void attach(int newdata){
node list = this ;
if(list.next == null)System.out.println("alas only 1 element given! last element so far " + list.data) ;
while(list.next != null){
System.out.println("---------------------------------------") ;
list = list.next ;
}
list.next = new node(newdata) ;
}
}
I m writing another function split() that splits the list into 2 lists:
bigger_than int x and less_than x.
But initially these 2 lists are empty(bigger_than & less_than)
I m trying to attach to these 2 empty lists - this is the bug I can't resolve
public static void divide_list_around_x(int x, node list){
node less_than = null ;
node bigger_than = null ;
node current = list ;
while(current != null){
if( current.data < x){
//less_than is null here
less_than.attach(current.data);
}
else{
//bigger list is null
bigger_than.attach(current.data) ;
}
current = current.next ;
}
}
public static void main(String[] args) {
//creating list, attach 1 by 1
node first = new node( 4) ;
first.attach( 78) ;
first.attach( 5) ;
first.attach( 51) ;
first.attach( 157) ;
first.attach( 3) ;
divide_list_around_x(78,first) ;
}
You need to initialize the :
node less_than = new node(0) ;
node bigger_than = new node(0) ;
and then attach elements based on your condition x.
You could keep a len variable in your class Node:
public class Node {
int len = 0;
Add a constructor:
public Node() {
}
Modify the attach function:
public void attach(int newdata){
if (len == 0) {
data = newdata;
next = null;
len++;
return;
}
Node list = this ;
if(list.next == null)System.out.println("alas only 1 element given! last element so far " + list.data) ;
while(list.next != null){
System.out.println("---------------------------------------") ;
list = list.next ;
}
list.next = new Node(newdata) ;
len++;
}
Also instantiate less_than and bigger_than in function divide_list_around:
Node less_than = new Node();
Node bigger_than = new Node();
TD;LR - The code was checking that current != null and then tried accessing current.data when data was null - so the result was NPE. There were a few other problems which we'll see as we go.
There are a few problems, most of them are "looking ahead" at a node with null data, and incorrect null checks. I took the liberty to change attach() (which had another NPE issue when trying to print list.data) to be more concise.
Further, a toString() method was added in order to provide clearer visibility for the whole process (see "output" section in the bottom):
public class Node {
Integer data;
Node next = null;
public Node() {
}
public Node(Integer data, Node next) {
this.data = data;
this.next = next;
}
public void attach(int newData) {
if (data == null) {
data = newData;
next = new Node();
}
else {
next.attach(newData);
}
}
public static void divideListAroundX(int x, Node next, Node lessThan, Node biggerThan) {
Node current = next;
while (current.data != null) {
if (current.data < x) {
//less_than is null here
lessThan.attach(current.data);
} else {
//bigger next is null
biggerThan.attach(current.data);
}
current = current.next;
}
}
#Override
public String toString() {
return "[data: " + data + ", next:" + next + "]";
}
public static void main(String[] args) {
//creating next, attach 1 by 1
Node first = new Node(4, new Node());
first.attach(78);
first.attach(5);
first.attach(51);
first.attach(157);
first.attach(3);
Node lessThan = new Node(); // these parameters should be initialized
Node biggerThan = new Node(); // these parameters should be initialized
divideListAroundX(78, first, lessThan, biggerThan);
System.out.println("Less than:");
System.out.println(lessThan);
System.out.println("------------------------\n");
System.out.println("Bigger than:");
System.out.println(biggerThan);
}
}
OUTPUT
Less than:
[data: 4, next:[data: 5, next:[data: 51, next:[data: 3, next:[data: null, next:null]]]]]
------------------------
Bigger than:
[data: 78, next:[data: 157, next:[data: null, next:null]]]
Comment
A few names were changed according to Java naming convention to camelCase (from sanek_case)
Having a bit of trouble adding a node to the end of my linked list. It only seems to display the very last one I added before I call my addFirst method. To me it looks like on the addLast method I'm trying to first create the node to assign it 5, then for the following numbers use a while loop to assign them to the last node on the linked list. Little stuck on why I can't get my output to display 5 and 6.
class LinkedList
{
private class Node
{
private Node link;
private int x;
}
//----------------------------------
private Node first = null;
//----------------------------------
public void addFirst(int d)
{
Node newNode = new Node();
newNode.x = d;
newNode.link = first;
first = newNode;
}
//----------------------------------
public void addLast(int d)
{
first = new Node();
if (first == null)
{
first = first.link;
}
Node newLast = new Node();
while (first.link != null)
{
first = first.link;
}
newLast.x = d;
first.link = newLast;
first = newLast;
}
//----------------------------------
public void traverse()
{
Node p = first;
while (p != null)
{
System.out.println(p.x);
p = p.link;
}
}
}
//==============================================
class test123
{
public static void main(String[] args)
{
LinkedList list = new LinkedList();
list.addLast(5);
list.addLast(6);
list.addLast(7);
list.addFirst(1);
list.addFirst(2);
list.addFirst(3);
System.out.println("Numbers on list");
list.traverse();
}
}
I've also tried creating a last Node and in the traverse method using a separate loop to traverse the last node. I end up with the same output!
public void addLast(int d)
{
Node newLast = new Node();
while (last.link != null)
{
last = newLast.link;
}
newLast.x = d;
newLast.link = last;
last = newLast;
}
The logic of your addLast method was wrong. Your method was reassigning first with every call the logic falls apart from that point forward. This method will create the Node for last and if the list is empty simply assign first to the new node last. If first is not null it will traverse the list until it finds a Node with a null link and make the assignment for that Nodes link.
public void addLast(int d) {
Node last = new Node();
last.x = d;
Node node = first;
if (first == null) {
first = last;
} else {
while (node.link != null) {
node = node.link;
}
node.link = last;
}
}
Your addLast() method displays the value of the last node because every time you append a node to the end of your list, you are overwriting the reference to "first". You are also doing this when you assign a new reference to first in the following line:
first = new Node();
Try the following:
public void addLast(int d)
{
Node newLast = new Node();
if (first == null)
{
newLast.x = d;
first = newLast;
return;
}
Node curr = first;
while (curr.link != null)
{
curr = curr.link;
}
newLast.x = d;
curr.link = newLast;
}
The method creates a new node and it is added to the end of the list after checking two conditions:
1.) If first is null: in this case the list is empty and the first node should be
initialized to the new node you are creating, then it will return (or you could do
an if-else).
2.) If first is not null: If the list is not empty you'll loop through your list until you
end up with a reference to the last node, after which you will set its next node to the
one you just created.
If you wanted to keep track of the tail of your list called "last", like you mentioned above, then add:
last = newLast
at the end of your method. Hope this helps!
I am trying to build a tree and I would like to link parent nodes to children based on a filepath like structure such as the one below, where The World is the root:
The World
The World/Asia
The World/Asia/Afghanistan
The World/Asia/Iran
The World/Asia/China";
I want to turn it into this:
The approach I am taking is as follows. I am wondering if someone could give me a hand in pointing me in the right direction. I am not sure if my logic is correct?
public void linkNodeToParent(String path, Node n)
{
String[] pathNodes = path.split("/");
Node parent = root;
for(int i = 0; i < pathNodes.length; ++i)
{
for(int j = 0; j < parent.getChildren().size(); ++j)
{
if(parent.getChildren().get(j).getNodeName().equals(pathNodes[i]))
parent = parent.getChildren().get(j);
}
}
}
Hope the below code helps you in creating your folder structure using Tree
import java.util.*;
class Tree
{
class Node
{
String data;
ArrayList<Node> children;
public Node(String data)
{
this.data = data;
children = new ArrayList<Node>();
}
public Node getChild(String data)
{
for(Node n : children)
if(n.data.equals(data))
return n;
return null;
}
}
private Node root;
public Tree()
{
root = new Node("");
}
public boolean isEmpty()
{
return root==null;
}
public void add(String str)
{
Node current = root;
StringTokenizer s = new StringTokenizer(str, "/");
while(s.hasMoreElements())
{
str = (String)s.nextElement();
Node child = current.getChild(str);
if(child==null)
{
current.children.add(new Node(str));
child = current.getChild(str);
}
current = child;
}
}
public void print()
{
print(this.root);
}
private void print(Node n)
{
if(n==null)
return;
for(Node c : n.children)
{
System.out.print(c.data + " ");
print(c);
}
}
public static void main(String[] args)
{
Tree t = new Tree();
t.add("The World");
t.add("The World/Asia");
t.add("The World/Asia/Afghanistan");
t.add("The World/Asia/Iran");
t.add("The World/Asia/China"); // Even if you insert only this statement.
// You get the desired output,
// As any string not found is inserted
t.print();
}
}
The "add" method takes folder or the entire path as input and it stores it in the tree as you required. It takes the first string and checks if it's already present in the tree other wise it adds it and proceed to the next string (folder in your terms).
The print method help you verify the storage of the data in tree.
Consider to use the new NIO.2 API.
Every Node could hold a Path object.
http://docs.oracle.com/javase/7/docs/api/java/nio/file/Paths.html
If you add one backlash "/" at every end ,as we talked in chat, then this program will work
void split()
{
String path=
"The World/"+
"The World/Asia/"+
"The World/Asia/Afghanistan/"+
"The World/Asia/Iran/"+
"The World/Asia/China/";
String[] pathNodes = path.split("/");
// for(String s:pathNodes)
// {
// System.out.println(s);
// }
String root="The World";
String continent="Asia";
List<String> ls=new ArrayList<String>();
for(int i=0;i<pathNodes.length;i++)
{
if(pathNodes[i].equals(root))
{
if(pathNodes[i+1].equals(continent))
{
ls.add(pathNodes[i+2]);
}
}
}
for(String s:ls)
{
System.out.println(s);
}
}