Building a linked list in Java - java

This is an example from my book. As I see it, when you create a list with this class, you create two objects (first and last, which are null). I can't figure out why, when you put both first and last "Node" objects in the add method. Shouldn't it create two elements when you set both first = n and last = n. For example, if I call list.add(2), shouldn't both first and last be 2 now ?
public class List {
private Node first = null;
private Node last = null;
public List(){
first = null;
last = null;
}
private static class Node{
public int value;
public Node next;
public Node ( int value, Node next){
this.value = value;
this.next = next;
}
}
public void add (int value){
Node n = new Node (value,null);
if(first==null){
first = n;
last = n;
}else{
last.next = n;
last = n;
}
}
public int size(){
int number = 0;
Node n = first;
while(n != null){
number++;
n = n.next;
}
return number;
}
}

As i see it, when u create a list with this class, you create two objects (first and last, which are null).
That's not true. first and last are not objects, but references to objects. And in this case, they start out as null references, meaning that they don't refer to any object at all.
When you write first = n; last = n;, you set first and last to both refer to the same object — whatever object n refers to.
For example, if list.add(2), shouldn't now both first and last be 2?
Yes, they'll both refer to the same Node instance, whose value is 2.

Yes i see that first and last are needed. Probably later on first will be much more useful if you have dequeue (remove first) or a search (which i guess can be done from the end rather than at the start, same process for a simple linear search).
As for your question. Yes if you started with a blank list and said list.add(2). Both first and last will be pointing to node with value 2. This is because the first element and the last element in the list are the same, hence 1 element in the list. Its both first and last (and middle if you want to be weird).
but if you did list.add(1), list.add(2). You would get first = node.value == 1 and second = node.value == 2

Related

Constructor Node cannot be applied to given types while working with nodes

I am working on a code that puts new elements on MyStack if they are unique. I had to copy and paste the node starting code, so I'm having a bit of trouble with an issue. I keep getting two error messages, even after trying various workarounds and I'm not really understanding why. I've even tried using some helper functions I've previously made that have worked before so I'm extra confused.
The two errors I consistently get are:
-cannot infer type arguments for MyStack.Node (actual and formal arguments differ in length)
-constructor node cannot be applied to given types. Required, no arguments, found: anything,
Here's my code:
public class MyStack<Anything>
{
private Node first, last;
private class Node<Anything>
{
Anything item;
Node next;
}
public boolean contains(Anything value)
{
for (Node curr = first; curr != null; curr = curr.next)
{
if (value.equals(curr.item)) {
return true;
}
}
return false;
}
public void add(Anything value)
//method that adds a new value to the end of the list
//COMPLETE
{
Node temp = first;
while(temp.next!=null){ //finds the end
temp=temp.next;
}
temp.next=new Node(value, null); //assigns new value
}
public void enqueue(Anything info){
if (this.contains(info)==true) { //if the info is already present
System.out.println("the stack already contains this value");
return;
}
//if we actually need to add the info
if (first == null) { //if there is nothing in the stack
Node temp= first;
first = new Node<>(info,temp);
first = temp;
return;
}
if (first != null) { //if there is already stuff
Node temp = first;
while (temp.next == null)
{ Node newNode= new Node<>(info, temp);
temp.next = newNode;
}
return;
}
}
}
As #Andreas already pointed out, Node needs a constructor.
There are a few other flaws in your Code:
Use Generics
With your Code, you can only store Objects of the class Anything, what strongly limits its reusability. Use a generic instead and you can reuse this class for many more purposes.
Linked List
I suggest, you use the paradigm of a double-linked-list. That way you do not need to find the last Node to add something to the Stack. Node now has a pointer to its previous and next element.
Use the last Object
You have the object last but never use it. To find out, whether the current object is the last one you compare the value to null. This has the effect, that storing a null value will break your List. Instead compare to the Object last, this object is unique and guarantees you, that you are at the end of the list. Both first and last are Nodes that do not contain a value and are simply used to mark the start/end of your List.
Adding elements
Using the changes above, the code in the Method enqueue(T value) becomes significantly simpler: You just check whether contains(value) and decide whether you add the value to the List or not.
All these changes applied result in following code:
public class MyStack<T extends Object> {
private Node first, last;
public MyStack() {
first = new Node(null, null, null);
last = new Node(null, null, first);
first.next = last;
}
private class Node {
T item;
Node next;
Node previous;
public Node(T item, Node next, Node previous) {
this.item = item;
this.next = next;
this.previous = previous;
}
}
public boolean contains(T value) {
for (Node curr = first.next; curr != last; curr = curr.next) {
if (value.equals(curr.item)) {
return true;
}
}
return false;
}
/**
* method that adds a new value to the end of the list
*/
public void add(T value)
{
Node secondLast = last.previous;
Node added = new Node(value, last, secondLast);
secondLast.next = added;
last.previous = added;
}
/**
* only adds value if it is not already contained by the Stack
*/
public void enqueue(T value) {
if (this.contains(value) == true) { // if the info is already present
System.out.println("the stack already contains this value");
}
else {
add(value);
}
}
public static void main(String[] args) {
MyStack<String> test = new MyStack<>();
test.add("foo");
test.add("bar");
test.add("baz");
System.out.println(test.contains("bar"));
System.out.println(test.contains("new"));
test.enqueue("baz");
test.enqueue("MyStack");
}
}
Naming
As you may have noticed, in my explanation I called this class a List. This is because it fulfills more of the characteristics of a List. A Stack usually only provides the methods push to put something at the top of the Stack and pop to remove and return the topmost Object. Optionally peek can return the topmost Object, without removing it from the Stack.
Also consider renaming the method enqueue: enqueue is used in Queues (obviously) and Queues do not forbid to add two equal Objects. So the name is misleading. I would call this method something like addIfNotContaining.
In my Opinion you should name this class to be a List and add a method get(int i) to get a specific element at a position. Naturally adding some other methods like size ect. to comply with a standard List. But I assume you already had, but did not post them because they are not related to your problem.
Multithreading
This Class is far from threadsave. But I let you figure out yourself how to make it threadsave if needed.

explain Linked List data structure in Java

Iknow java is passed by value. For linked list data structure, what is the difference between method size() and size1()? I think there are the same becasue the head and next reference point to the same thing in size1(). but the result is difference
public class IntList {
int item;
IntList next;
public IntList(int item, IntList next){
this.item = item;
this.next = next;
}
public int size(){
int size = 1;
while (next !=null){
size++;
next = next.next;
}
return size;
}
public int size1(){
int size = 1;
IntList head = next;
while (head != null){
size++;
head = head.next;
}
return size;
}
public static void main(String[] args) {
IntList L = new IntList(1,null);
L = new IntList(2,L);
L = new IntList(3,L);
L = new IntList(10,L);
L = new IntList(20,L);
System.out.println(L.size());
}
}
I am confused about the reference means in java.
This is a matter of issue with scope. In size1(), you are creating a local variable named head. When you call size1() it creates a reference variable that will be destroyed at the end of the call. This means that no matter how many times you call size1(), it will always give you the proper size.
However, when you use the field "next" in size(), it iterates through each variable until the end. However, once it gets there, it is notdestroyed because its scope is the object. This means the next time you call size(), and all subsequent calls (given no changes), it will always return 1.
They're logically the same, but size() is actually pointing next to the final node, so the next size check will return 1. size1() uses a local variable to traverse the list, so the object state isn't affected.

Not clear why "start" is assigned/gives reference at line 1

This is a issue of single linked list implementation.
Say, A class Node is defined.
Now, for operations another class LinkedList is defined. We are going to add element at start position.
class LinkedList {
protected Node start;
protected Node end;
public int size;
public LinkedList() {
start = null;
end = null;
size = 0;
}
//method for insert at start
public void insertAtStart(int value) {
Node nptr = new Node (value, null);
size++;
if (start == null) {
start = nptr;
end = start; //Line 1
}
}
// others method(omitted here)
}
I was thinking, what would happen if we assign nptr itself to end in Line 1? I am not getting clear in that issue.
After this line:
start = nptr;
the variable start holds the reference to the same object as nptr, i.e. the object created during:
Node nptr = new Node (value, null);
So it doesn't matter if you call end = start or end = nptr as end will contain the same reference afterwards; nptr, end and start will all point to the same object.
In this case the end reference variable should be updated only for first call of insertAtStart(int val) to maintain the reference to the end node.
if you assign nptr itself to end in Line 1, the end reference variable will have the reference to newly added node (Which is the first node of the list).

Creating a linked list of notes from a Phrase (Jmusic)

I have this constructor that takes in a phrase of jmusic notes, and I'm trying to set each individual note to an individual node in a linked list of SoloNodes which hold one individual note only. most of the methods in that constructor I've written myself but they're pretty self explanatory. What exactly must I do to make this generate a linked list?
public Solo(Phrase myPhrase)
{
int length=myPhrase.length();
head=new SoloNode();
SoloNode next=new SoloNode();
for(int i=1; i<=length;i++)
{
head.setNote(myPhrase.getNote(i));
next=head.copyNode();
head.setNext(next);
head=next;
i++;
}
}
I guess that's the code you are looking for:
private SoloNode head;
public Solo(Phrase myPhrase)
{
int length = myPhrase.length();
SoloNode node = new SoloNode();
head = node;
for (int i = 0; i < length; i++) {
node.setNote(myPhrase.getNote(i));
if (i + 1 < length) {
node.setNext(new SoloNode());
node = node.getNext();
}
}
}
I assumed you are using a class SoloNode which looks like this.
I assumed too that myPhrase.getNote(i) starts with index 0 (not 1) because that is the common way how it works in Java.
After you run this code the SoloNodes are filled with data from myPhrase and linked from one to next. With getNext() you can navigate from current to next. Only for last SoloNode it will return null.

java linked list copy constructor

Im having trouble with a constructor for a linked list. it takes a string and is supposed to create a node for every character.
i get a nullpointerexception everytime i try to print out the list. Does that mean that not even the first node is being created?
below is my node class and the list constructor.
class CharNode {
private char letter;
private CharNode next;
public CharNode(char ch, CharNode link)
{
ch = letter;
link = next;
}
public void setCharacter(char ch)
{
ch = letter;
}
public char getCharacter()
{
return letter;
}
public void setNext(CharNode next)
{
this.next = next;
}
public CharNode getNext()
{
return next;
}
}
and this is my constructor
// constructor from a String
public CharList(String s) {
CharNode newNode = head;
for(int i = 0; i <s.length(); i++)
{
newNode = new CharNode(s.charAt(i), null);
newNode.setNext(newNode);
}
}
am i constructing it correctly?
First of all, your attributions are switched around!
ch = letter;
link = next;
should be
letter = ch;
next = link;
Same thing in your setter.
When you have a method in Java of the form:
public void setSomething(String argument){
this.classMember = argument;
}
Is usually what you want. You must assign your argument to your class member, not the other way around.
Also, when you're invoking your constructor, you have:
newNode = new CharNode(s.charAt(i), null);
newNode.setNext(newNode);
This make it so that your "link" is always pointing to itself! Think about what you need to do to make the previous Node point to the node you've just created (perhaps save it somehow?)!
Was I clear enough? Let me know if I can explain further.
As pcalcao said, = assigns the value on the right to the variable on the left. You'll need to change ch = letter; to letter = ch; and link = next; to next = link;
Now, the line CharNode newNode = head; doesn't mean anything unless you've specified what head is prior to the code you've given, but it doesn't look like it. Remember that when creating a linked list, you don't start with anything, so even "special" nodes like head must be created (instantiated, if you prefer). The idea is to create the first node (the head), and then assign head to that first node. For every node after the first one, this step isn't required, as you simply are adding to the end of the list.
Finally, during construction, you'll need a reference to both a new node (like you have now), and the previous node, in order to do proper appending. Your code now is simply setting the next node in the list to the current node, which means that once you create a new newNode, you will lose the reference to the previous newNode.
A good way to approach linked lists when one is first getting started is to draw out what you want to do step by step, then try and translate that into code. Hopefully this is helpful.

Categories

Resources