i'm doing a project and its to do with binary trees and botanical keys, now what i need to do load a bot key into the programme, then work be able to work my way through it going to each node in order to determine the type of tree it is, and it will display the tree itis when i reach a leaf node. Now im having trouble with the moving through it part, i cant figure out how to get it to work, ive tried many different things including a pre oder traversal, and i was just wondering if anyone could give me a hand in getting it off the ground so to speak. the code for the part of the programme i need to edit is below, the "chooseOption" method is the method used to traverse the tree.
thanks in advance.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Stack;
/**
*
* #author Alex Drinkwater 10077473
*/
public class BotKey implements IBotKey {
private Node root;
private Node currentNode;
// This stack will come in handy when you implement the "undo" facility
private Stack<Node> choiceStack = new Stack<Node>();
#Override
public boolean isLoaded() {
return root != null;
}
#Override
public int getNbrChildren() {
if (currentNode == null) {
return 0;
} else {
return currentNode.getNbrChildren();
}
}
#Override
public String getLeadStatement(int i) {
return currentNode.getChildStatement(i);
}
#Override
public void chooseOption(int i) {
//You need to implement this method
if (root != null) {
root.getChildNode(i);
root.getChildStatement(i);
}
}
#Override
public void undoChoice() {
//You need to implement this method
}
#Override
public String getResults() {
//Dummy implementation. You need to supply a proper one
if (currentNode.isLeaf() == true) {
currentNode.getName();
}
else{
String s =currentNode + "";
if(currentNode!= null){
}
}
return "s";
}
#Override
public void loadExample1() {
Node southernLive = new Node("Southern live Oak: Quercus virginiana");
Node dwarfLive = new Node("Dwarf live oak: Quercus minima");
Node willow = new Node("Willow oak");
Node shingle = new Node("Shingle oak");
Node blackJack = new Node("Blackjack Oak");
Node northernRed = new Node("Northern red oak");
Node white = new Node("White oak Quercus alba");
Node swampChestnut = new Node("Swamp chestnut oak Quercus prinus");
Node node7 = new Node();
node7.addChild(white, "Leaves with 5-9 deep lobes");
node7.addChild(swampChestnut, "Leaves with 21-27 shallow lobes");
Node node6 = new Node();
node6.addChild(blackJack, "Leaves mostly with 3 lobes");
node6.addChild(northernRed, "Leaves mostly with 7-9 lobes");
Node node5 = new Node();
node5.addChild(node7,
"Lobes or teeth rounded or blunt-pointed, no bristles");
node5.addChild(node6, "Lobes or teeth bristle-tipped");
Node node4 = new Node();
node4.addChild(willow, "Leaf narrow, about 4-6 times as long as broad");
node4.addChild(shingle, "Leaf broad, about 2-3 times as long as broad");
Node node3 = new Node();
node3.addChild(dwarfLive, "Mature plant a small shrub");
node3.addChild(southernLive, "Mature plant a large tree");
Node node2 = new Node();
node2.addChild(node4, "Leaves not evergreen");
node2.addChild(node3, "Leaves evergreen");
Node node1 = new Node();
node1.addChild(node5, "Leaves usually with teeth or lobes");
node1.addChild(node2, "Leaves usually without teeth or lobes");
root = node1;
currentNode = root;
}
#Override
public void loadExample2() {
Node southernLive = new Node("Southern live Oak: Quercus virginiana");
Node dwarfLive = new Node("Dwarf live oak: Quercus minima");
Node willow = new Node("Willow oak");
Node shingle = new Node("Shingle oak");
Node blackJack = new Node("Blackjack Oak");
Node northernRed = new Node("Northern red oak");
Node white = new Node("White oak Quercus alba");
Node swampChestnut = new Node("Swamp chestnut oak Quercus prinus");
Node node7 = new Node();
node7.addChild(white, "Leaves with 5-9 deep lobes");
node7.addChild(swampChestnut, "Leaves with 21-27 shallow lobes");
Node node6 = new Node();
node6.addChild(blackJack, "Leaves mostly with 3 lobes");
node6.addChild(northernRed, "Leaves mostly with 7-9 lobes");
Node node5 = new Node();
node5.addChild(node7,
"Lobes or teeth rounded or blunt-pointed, no bristles");
node5.addChild(node6, "Lobes or teeth bristle-tipped");
Node node4 = new Node();
node4.addChild(willow, "Leaf narrow, about 4-6 times as long as broad");
node4.addChild(shingle, "Leaf broad, about 2-3 times as long as broad");
Node node3 = new Node();
node3.addChild(dwarfLive, "Mature plant a small shrub");
node3.addChild(southernLive, "Mature plant a large tree");
Node node2 = new Node();
node2.addChild(node4, "Leaves not evergreen");
node2.addChild(node3, "Leaves evergreen");
Node node1 = new Node();
node1.addChild(node5, "Leaves usually with teeth or lobes");
node1.addChild(node2, "Leaves usually without teeth or lobes");
root = node1;
currentNode = root;
//You need to implement this method
}
#Override
public void readFromFile(FileInputStream fs) {
//You need to implement this method
// You may find that a hashmap like this is useful
HashMap<Integer, Node> map = new HashMap<Integer, Node>();
}
#Override
public boolean canUndo() {
//Dummy implementation. You need to provide a proper one
if (choiceStack != null) {
return true;
} else {
return false;
}
}
}
You have a botanical "database" (in tree structure), that describes each plant, for example: "Willow oak"? Then you want to understand what was given for the search? For example we have a description of some plant: "Leaves with 5-9 deep lobes" and we want to get all plants that this plant could be? In that case we need to find a Node wich contains text "Leaves with 5-9 deep lobes". Let's call this node startingNode.
Then we have to move from startingNode to it's parent. Let's call startingNode's parent a parentNode. Then we have to get a parent of parentNode and so on. Repeat until you reach a node which has a name for the plant.
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 2 years ago.
The code below shows a data structure in leetcode. We can see the node1 store a list with node2 and node3, node2 will store a list with node1 and node4. In this case I think node1 and node2 will store the object of each others, which will cause an infinite recursion. How does java store the data structure like this, doesn't it cause a memory exceed?
class Node {
public int val;
public List<Node> neighbors;
public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}
public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}
public static void main(String[] args) {
Node node1 = new Node(1, new ArrayList<>());
Node node2 = new Node(2, new ArrayList<>());
Node node3 = new Node(3, new ArrayList<>());
Node node4 = new Node(4, new ArrayList<>());
node1.neighbors.add(node2);
node1.neighbors.add(node4);
node2.neighbors.add(node1);
node2.neighbors.add(node3);
node3.neighbors.add(node2);
node3.neighbors.add(node4);
node4.neighbors.add(node1);
node4.neighbors.add(node3);
Solution solution = new Solution();
solution.cloneGraph(node1);
}
You would be correct about this code causing memory to be exceeded if each node's list of neighbours contained copies of those neighbours. But that's not how Java works. Instead the list contains references to the neighbour nodes.
As an analogy, if each time you wrote down someone's address you need a complete copy of their house then you'd run out of space quickly. But you don't - you just need a reference to their house which can itself contain a reference to yours.
Note that's it's pretty easy to write code that causes a stack overflow with objects that contain references to themselves. For example, if your class had a method:
class Node {
public int sumVals() {
return val + neighbours.stream().mapToInt(Node::sumVals).sum();
}
}
calling node1.sumVals() will cause infinite recursion.
Try to create an empty link list. To creating the empty list I create a inner class Node and made it static such that main class can access it.
import java.util.LinkedList;
public class Addtwo {
static class Node {
int data;
Node next;
Node head;
Node(int d) {
data = d;
next = null;
// Constructor
}
public static void main (String args[])
{
/* Start with the empty list. */
LinkedList llist = new LinkedList();
llist.head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
llist.head.next = second;
second.next = third;
}
}
}
It cannot find the node head that I create within the inner class Node. How to solve this?
Error:
Error :(22, 22) java: cannot find symbol
symbol : variable head
location: variable llist of type java.util.LinkedList
First, if you want to use the JDK's LinkedList, you don't need to manage the nodes of the list, this work is already implemented. You only need to do this:
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(1);
llist.add(2);
llist.add(3);
And there is more functionality here.
Second, if you want to implement your own linked list (I think this is what you want), you donĀ“t need to use the JDK's LinkedList, you can start with this basic code:
public class Addtwo {
static class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
public static void main(String args[]) {
/* Start with the empty list. */
Node head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
head.next = second;
second.next = third;
Node iterator = head;
while (iterator != null) {
System.out.println(iterator.data);
iterator = iterator.next;
}
}
}
}
PS: You don't need to store a head for each node. You probably need another class LinkedListManager to implement some methods and store the head and the tail of the list.
I am still learning Java, and currently working problems from Cracking the Coding Interview, and one of the problems on Chapter-2 (LinkedList) asks to remove duplicates from an unsorted linked List. I found a bunch of answers/solution on GitHub, but I would like to create my own Node, and write my own version.
What I have implemented so far is that I created Node class and write the function/method that can remove the duplicates from unsorted LinkedList, but when I try to test it, I tried to create the LinkedList in the main function, but I still have no idea how to figure it out. Can someone please help/guide me how to create a Singly LinkedList?
Basically, I create four nodes (fourth,third,second,head), and connect them all using the Node class.
Thanks in advance,
public class Node {
int data;
Node next;
public Node(int data, Node next){
this.data = data;
this.next = next;
}
public String toString(){
return data + "";
}
}
public class problem1 {
public void Remove_duplicates(Node head){
if(head == null){
return;
}
Node current = head;
while(current != null){
Node runner = current;
while(runner.next != null){
if(runner.next.data == current.data){
runner.next = runner.next.next;
}
else {
runner = runner.next;
}
}
current = current.next;
}
}
public static void main(String[] args) {
Node fourth = new Node(5,null);
Node third = new Node(3,fourth);
Node second = new Node(4,third);
Node head = new Node(3,second);
for(Node a: head){
// ERROR: saying can only iterate over an array (or) java.lang.Iterable
System.out.println(a.toString());
a = a.next;
}
}
}
Try another kind of loop e.g. while
Node head = new Node(3, second);
Node node = head;
while (node.next != null) {
System.out.println(node.toString());
node = node.next;
}
Like it explains it does not know how to iterate over your nodes.
Another approach for using the foreach would be to create an own class which implements the interface Iterable and does contain your LinkedList logic.
For the second approach I would suggest you to read the following: How can I implement the Iterable interface?
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm getting a NullPointerException when I try to run this code. I've assigned Nodes 2,3,and 4 as children nodes to Node1. I tried to create a method that will go through all the children nodes in Node1 and return the list. I'm not sure what I'm doing wrong.
public class TestingArrays2 {
List<Node> myList1;
List<Node> myList2;
List<Node> myList3;
List<Node> myList4;
private Node Node1;
private Node Node2;
private Node Node3;
private Node Node4;
public TestingArrays2() {
myList1 = new ArrayList<Node>();
myList2 = new ArrayList<Node>();
myList3 = new ArrayList<Node>();
myList4 = new ArrayList<Node>();
myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);
Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);
List<Node> allNodesArray = nodeArray(Node1);
for (int i = 0; i < allNodesArray.size(); i++){
System.out.println(allNodesArray.get(i).label);
}
}
public static void main(String arg[]) {
TestingArrays2 testArray = new TestingArrays2();
}
public List<Node> nodeArray(Node n){
List<Node> tempList = new ArrayList<Node>();
for (int i = 0; i < n.children.size(); i++){
tempList.add(n.children.get(i));
}
return tempList;
}
}
You're not creating your Nodes. See these lines...
private Node Node1;
private Node Node2;
private Node Node3;
private Node Node4;
These just declare a variable as being able to contain an object of type Node. However, they initially start with a null value - ie they're empty.
You're then calling these lines...
myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);
Which would insert null values into your List, because you're trying to add an object that hasn't been created yet.
So, you need to change your code so that these lines...
Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);
appear before you try to myList1.add() them to the list. This will create the Node objects first, which can then be added to your List.
As #BalusC mentioned in the comments, it is failing on your for loop later in your code, because it is trying to call .label on a null object. Correcting the order as suggested above will correct this, as all the objects in your List will now be Nodes.
This:
myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);
Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);
You are trying to add the nodes to the list before they have been created.
A good answer to your question is already given.
Looking at your code I have several suggested modifications.
You are doing all the work in (the constructor of) your test class. It is nicer design to delegate this to the Node class where possible. Also try not to do 'work' in the constructor, just initialization.
Also check out the code conventions I applied like using nouns for class names and starting variable names with a lower case letter.
public class ArrayTest2 {
public static void main(String arg[]) {
Node node1 = new Node("One");
node1.add(new Node("Two"));
node1.add(new Node("Three"));
node1.add(new Node("Four"));
// this calls the toString method of node1
System.out.println(node1);
}
}
public class Node {
private final String name;
private final List<Node> children;
public Node(String name) {
this.name = name;
this.children = new ArrayList<Node>();
}
public String getName() {
return name;
}
public void add(Node children) {
children.add(child);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name);
if(children.size() > 0) {
sb.append("(");
String separator = "";
for (Node child : children){
sb.append(separator).append(String.valueOf(child));
separator = ",";
}
sb.append(")");
}
return sb.toString();
}
}
Notice that the children field is private and there is no getter for it. It is considered bad practice to offer direct access to internal data structures like 'children' so I provided an 'add' method for adding nodes. In this way the class keeps control over what happens to its data, which is an important OO design principle.
The toString method builds a string representation of a Node. It appends the Node name and then, in case there are children, appends each child node's string representation in a comma-separated list surrounded by parentheses, so this should print something like:
One(Two,Three,Four)
A more complex structure for example:
Node node1 = new Node("One");
Node node2 = new Node("Two");
Node node3 = new Node("Three");
Node node4 = new Node("Four");
Node node5 = new Node("Five");
Node node6 = new Node("Six");
node1.add(node2);
node1.add(node3);
node2.add(node4);
node4.add(node5);
node4.add(node6);
Should give:
One(Two(Four(Five,Six)),Three)
Disclaimer: my code is hand-crafted, uncompiled and untested
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.