I'm working with double-ended queues for an assignment, and we're running into an issue where the object reference is disappearing from a node after being passed through an extremely simple method.
Some important definitions:
class Node {
String s;
Node prev;
Node next;
...
}
class Sentinel extends Node {
Node prev;
Node next;
//Constructor uses that of Node
}
class Deque {
Sentinel start;
...
}
One method we are writing removes a Node from a deque, based on the given string.
In deque:
public void removeSorted(String toRemove) {
// System.out.println(this.start);
// System.out.println(this.start.next);
this.start.next.removeSorted(toRemove);
}
The commented out println's show the correct Sentinel and Node.
Then, in Node:
public void removeSorted(String toRemove) {
if (this.s.equals(toRemove)) {
// System.out.println(this.prev);
// System.out.println(this.prev.next);
this.prev.next = this.next;
this.next.prev = this.prev;
} else if (this.s.compareTo(toRemove) > 0) {
throw new RuntimeException("String does not exist in these nodes!");
} else {
this.next.removeSorted(toRemove);
}
}
The println for this.prev outputs the Sentinel on the first recursion, as expected. However, this.prev.next outputs null instead of the Node.
This function only fails when trying to remove the first Node, directly after the Sentinel. If you try to remove any other Node, it works correctly, and trying to call this.prev.next results in a non-null answer.
Why does the reference disappear when passing to the function (immediately after), since we've shown that the reference is there directly before calling the function?
Either your question code is wrong, or you have same fields in both Node and in Sentinel. This means, that these two are different:
start.next is next field of Sentinel class, which hides field with same name from Node class.
start.next.prev.next is also a field of start, but now it is the field of Node class, because you access it through Node reference.
Remove prev and next from Sentinel. Actually remove the whole Sentinel, it looks like you use to to "remove" the String s, which is impossible, you can't "remove" super class fields. Or if you need/want sentinel, see below for alternative design.
Also, this demonstrates why you should use getters and setters instead of accessing fields directly... Your IDE probably has nice refactoring tool to add getters etc (right click on field, see "Refactor" submenu), use it! And if your IDE does not have that, switch to one which does (I prefer NetBeans, but Eclipse and IntelliJ are worthy too), writing Java without such an IDE is an exercise in masochism...
Also, in Java avoid that kind of inheritance. You should probably have this kind of overall design:
interface NodeInterface {...}
public class Node implements NodeInterface {...}
public class Sentinel implements NodeInterface {...}
Then in the NodeInterface, define getters and setters, which should take as parameters as well as return NodeInterface type. Sentinel class would not support all interface methods of course, so those methods can either return null;/do nothing, or throw new IllegalStateException("Sentinel does not support Xxxx."); depending on method and if calling that method for sentinel is bug in calling code or not (better start with throwing exception).
If this is school work and you have not gone over interfaces yet, then replace interface NodeInterface with class NodeBase (preferably abstract), but in "real world" this would be bad code, because Java does not support multiple inheritance.
Related
I am currently working on an assignment for class where I am tasked with creating an empty List that has a Comparator as an argument then creating an add method for that sortedDoublyLinkedList where I am passed an argument and I have to iterate through the list to find where the new node fits. I'm not very familiar with Comparator so I'm a bit clueless as to how to add elements to my DoublyLinkedList because I cannot access the Comparator the way I though I was supposed to. Here is what I have now. Here is what I currently have.
public class SortedDoubleLinkedList<T> extends BasicDoubleLinkedList<T> {
Node<T> head=null;
Node<T> tail=null;
SortedDoubleLinkedList<T> sDLL;
public SortedDoubleLinkedList(Comparator<T> comparator2){
sDLL=new SortedDoubleLinkedList<T>(comparator2);
}
public SortedDoubleLinkedList<T> add(T data){
Node<T> newNode=new Node<T>(data);
//I have to iterate through the list and find where the new element data fits
if(head!=null&&tail!=null) {
Node<T> cursor=head;
while(cursor!=null) {
//the following code doesn't work
if(sDLL.comparator2.compare(data, cursor.getData())==0) {
}
}
}
else {
head=newNode;
tail=newNode;
}
return this; //return the SortedDoubleLinkedList<T>
}
Comparator is an interface. You need to implement a class that will provide that interface.
class Whatever implements Comparator<TYPE> {
int compare(TYPE a, TYPE b) {
... code to decide whether a is less than,
equal to, or greater than b ...
}
}
Where I wrote TYPE, you need an actual type. Just supplying the type variable T is not going to get you to runnable code, which I assume is your goal. Ultimately you've got to say what type will go in your list. So I'd be expecting something like (in your code above)
public class SortedDoubleLinkedList extends BasicDoubleLinkedList<String> {
where you're storing Strings in your list. And then TYPE in my code is also String.
ALTERNATIVELY
You can leave your SortedDoubleLinkedList generic (in terms of T) but ultimately you want to get concrete about it, maybe
SortedDoubleLinkedList<String> = new SortedDoubleLinkedList(new Whatever());
but the Comparator is still going to need to be a Comparator<String> (or whatever type you choose).
I recently was in a interview and was asked to code a in order traversal for a BST using the java member function prototype below.
public void inOrderPrint()
I was confused by the fact that it did not take in any parameters. I am used to the node to be passed in. It is very easy to traverse the tree with the node passed in... I am just a little confused how one would go about it without the initial reference?
The given signature makes sense if inOrderPrint() is defined in the Node class of the BST, then it's implied that the tree to traverse is the one rooted in the current node. Alternatively, it could be that the tree is an attribute in the current class. Assuming that the method is in the node class, it'd be something like this - and do notice how the recursion gets called:
public class Node {
private Node left;
private Node right;
private Object value;
public void inOrderPrint() {
if (left != null)
left.inOrderPrint();
System.out.println(value);
if (right != null)
right.inOrderPrint();
}
}
Given that it's a member function,one can assume that you have access to the root (e.g. this.root). You could just overload this method with a method where you pass in a node. You would then call the overloaded method inside the given one with the root.
EDIT:
I thought the method was defined in the tree, not in the Node class. You could do it like this: (make sure to check for null!)
public void inOrderPrint(){
//traverse down the left tree
this.left.inOrderPrint();
System.out.println(this);
//traverse down the right tree
this.right.inOrderPrint();
}
Well I have a fairly simple question I just can't seem to find my way around...
For a class, I have to implement an interface for a binary tree that has a method like:
public List<Node<E>> listAll();
we are required to have a class called MyNode.java, which is what I use to make my tree with. So to list all children I thought I would do this:
public List<Node<E>> listAll(){
List<Node<E>> childList = new ArrayList<>();
MyNode<E> thisNode = this.l;
while(thisNode!= null){
childList.add(thisNode);
thisNode = thisNode.l;
}
return childList;
}
and to do something like set a child
public void setChild(Node<E> child){
E elem = child.getElement();
MyNode<E> newNode = new MyNode(elem);
this.l = newNode;
}
So my question is: am I going about this correctly? If I try to create a Node, I can't because my nodes are called MyNodes but when I try to create a list of MyNodes and return them it gives me an error because I am not following the interface.. When I try to make the method accept MyNode instead of Node it says I am not following the interface. A little more clarification below..
I currently am using the implements declaration to implement the Node.java interface.. When I am writing the method that is specified by my interface as:
public void setChild(Node<E> child);
then I am currently fleshing out the method like so:
public void setChild(Node<E> child) {
E elem = child.getElement();
MyNode<E> newNode = new MyNode<E>(elem);
MyNode<E> transNode = this.l;
if(transNode!=null){
while(transNode.r!=null){
transNode = transNode.r;
}
transNode = newNode;
}
else transNode = newNode;
}
you can see how I am getting the element from input child and creating a new MyNode out of it to put as the new child instead of just injecting Node into my tree.. Is this wrong? I can't seem to get another way to work...
Interfaces are good for making code generic. If you wanted to have multiple implementations of a Node class that each would have the same methods then making an interface would be a good idea.
Alternatively, if you want to enforce an API for someone else to use, and interface is the right way to do that. You can make methods that accept any object that implements that interface.
If you're just creating one Node class for a simple binary tree implementation it might not make sense. Your binary tree might want to implement a Collection interface to make it available as a generic structure.
If you want to contractualize yourself to an API before beginning, an interface could further be a good way to do that.
In general you don't want to create an interface unless you want an abstraction where you actually will write different implementations of that abstraction. In your case, class Node<T> will suffice for your needs.
It is generally considered good form to use an interface for the API.
Briefly, doing so:
allowing the caller to provide whatever implementation they like
makes testing easier, especially when using mocks
chisels the least amount of the API in stone
See Liskov substitution principle
I have this node class, I was wondering how does the program recognize that the Node next is actually the next node? and why would I want to assign it to null please? Detailed explanation would be greatly appreciated.
package LinearNode;
import dataobjects.*;
public class Node
{
public Node next;
public AnyClass obj;
public Node(AnyClass newObj)
{
next = null;
obj = newObj;
}
public void show()
{
System.out.println(obj.getData());
}
public void editNode()
{
obj.editData();
}
public Node getNext()
{
return next;
}
}
A Node is typically used in a linked list, and the node with a null next node is the last one of the list (since it doesn't have any next node).
The next node of a node will be the one you initialize, by doing
someNode.next = someOtherNode;
Note that fields should be private by default, and should almost never be public. Use methods to modify the state of objects.
It's the responsibility of the programmer to properly assemble and use the data structures he chooses. The next node points to a reference of what is assumed to be the 'next' node in the linked list, but Java can't tell you if you've linked them correctly or not. null is often used to represent the end of the list (as opposed to say a circular linked list, in which case head and tail pointers may be used instead of null). Documentation on the linked list data structure can be found on Wikipedia and also here, though the examples are written in C.
I have to create an array of linked lists for a class in order to store a graph (adjacency list). We have to use Java. I can create the array and instantiate each linked list, but when I go to add the first elements to each one, every linked list gets changed, not just the one at the index of the array.
Node [] adjList;
for(i=0;i<adjList.length;i++)
adjList[i] = new Node(0,0,null);
this instantiates each new linked list [Node is my own class, with constructor Node(int head, int data, Node next) and extends LinkedList]
then i go to add the first values to each node:
for(i=0;i<adjList.length;i++)
adjList[i].setHead(i+1); // numbers 1 to end are the graph vertices
or
for(i=0;i<adjList.length;i++)
adjList[i].add(new Node(i+1,0,null);
I use print statements to debug the code
at the end of these loop I print off each Linked List, but for each one, the values come out to be the final one
ie. if adjList.length = 2, it would print out
[3,0,null] // adjList[0]
[3,0,null] // adjList[1]
[3,0,null] // adjList[2]
edit: here is the Node class
import java.util.LinkedList;
public class Node extends LinkedList{
private static int head;
private static int data;
private static Node next;
public Node(int h,int d,Node n) {
head = h;
data = d;
next = n;
}
public int getHead(){ // getNext() and getData() are the same
return head;
}
public void setHead(int h){ // setNext() and setData() are basically the same
head = h;
}
}
You have probably declared something within Node as static, so every instance ends up with the same shared value, rather than having its own value. However, this is just a guess - please post the code of Node so we can see what the problem really is...
when I go to add the first elements to each one, every linked list gets changed, not just the one at the index of the array
Although your code snippet doesn't show it, almost definitely you have an aliasing problem. The aliasing problem, which tends to bite beginners in almost all object-oriented languages, is the problem of referring to the same object with two different names i.e. two different variables pointing at the same object.
Now you may be wondering: what about array indices? The problem is with changing a variable at one array index and getting a change across all array indices, not a bunch of named variables. But, as Eric Lippert explains (for C#, which is quite similar to Java), an array really is a bunch of variables that you can refer to with an indexer expression rather than having to define a bunch of individual names. In a sense, int[] foo = new int[3] is like declaring foo0, foo1, and foo2, and indexing into foo just tells the compiler to pick the appropriate variable out of foo0, foo1, and foo2.
You may also be wondering how data could be shared between multiple Node instances, if your array indeed has multiple nodes in it. There are a few ways, and knowing which is pretty much impossible without the code for the Node class. As #DNA points out, there could be static data in the Node class, which is automatically shared across all instances. A Node object may also have a reference to underlying data. If you pass the same reference into all the Node constructors, they are all aliasing the same object in this way as well.