java linked list copy constructor - java

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.

Related

Understanding setup for doubly linked list in Java

I am working on a doubly linked list in Java. So that I can create functions, I'm first working to understand the setup.
I have this code. I have started comments with what each line does. Looking at tutorials and I want to make sure I understand this correctly. I still get a little confused on using classes.
If I create a new node by Node x = new Node(); - I am creating a new node of class Node. So that creates an instance using "static class Node {"
Each Node created contains a int item, Node next, and Node prev, that I will set in my functions. The int item I assume is the contents of the Node.
What does the line "public Node() {}" do?
public class MyDeque {
Node first = null; //instance variable, first is of type node and is set to null
Node last = null; //instance variable, last is of type node and is set to null
int N = 0; //keeping track of number of nodes
static class Node {
public Node() { }
public int item;
public Node next; //next is of type node
public Node prev; //prev is of type node
}
To understand this setup for Double-Linked-List you need to understand how a constructor works; A constructor is like a method, which is used to initialize properties of a class when the object of this class is initialized in memory for the first time.
Let's take your code for an example, I modified it in a proper way to understand why and how constructors used in Java -
public class MyDeque {
Node first;
Node last;
int N;
public MyDeque(){
this.first = null;
this.last = null;
this.N = 0;
}
static class Node {
int item;
Node next;
Node prev;
public Node() {
this.next = null;
this.prev = null;
}
public void setItem(int item) {
this.item = item;
}
public int getItem(){
return this.item;
}
// ... public getters for other items
}
As you can see two constructors public Node(){} and public MyDeque(){} are used to set values for the properties of those objects when they are initialized in memory for the first time.
Later, of course, you can set / unchange / change values of properties using the setter method or using the "." operator but remember constructor will always take place when the objects are initialized or reinitialized in memory for the first time.

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.

about linear time and constant time of queue implementation on java linked list

if I maintain a reference of the least added item but not maintain a reference of most recently added item, then I will have constant time "dequeue" and linear time "enqueue". so this is my program which implement queue in java linked list. I want to ask if this program maintains both least added item and most recently added item? so it's all constant time when I "dequeue" or "enqueue"? thank you!
add: I kinda agree with what first answer said, so I tried the debugging mode and it shows that the oldlast hasn't updated after last changed so it's still working... but from the reference theory I learned from uni, just like he said, it shouldn't work.. Anyone can tell me why it's not updated automatically?(my java version 1.8)
package tst;
public class linkedlsqueue {
private class Node {
String item;
Node next;
}
Node first, last;
public boolean isEmpty() {
return first == null;
}
public void enqueue(String item) {
Node oldlast = last;
last = new Node();
last.item = item;
if (isEmpty()) {
first = last;
}
else {
oldlast.next = last;
}
}
public String dequeue() {
String item = first.item;
first = first.next;
if (isEmpty()) {
last = null;
}
return item;
}
}
Yes, you are correct. It is constant for both cases.
It is a good idea to keep record of both first and last for linked list.
Someone call it head and tail.
If you maintain only one of last or first, you have to search another one by iterating first to last to find another one or vice versa - one by one element, which is O(n).
It is like you are in darkness.
You hand holds an end of a rope and you want to know where it will lead to.
I can't think other ways beside tracing that rope. It takes O(n) to trace.
I prefer to use array[] though.
With array, it is like you have a map, a sun, and a super portal (random access).
However, it is not in the scope of the question.
The idea is correct, but the implementation is wrong.
Look at this:
public void enqueue(String item) {
Node oldlast = last;
last = new Node();
last.item = item;
if (isEmpty()) {
first = last;
}
else {
oldlast.next = last;
}
}
when you do oldlast = last, you DON'T COPY the last, you just pass last reference to oldlast.
During the whole process, oldlast will be whatever last is. And in the meanwhile, you RESET the values of last when you do last = new Node().
if you just want to enqueue, the correct method could work like this:
public void enqueue(String item) {
Node newNode = new Node();
newNode.item = item;
if(isEmpty()){
first = newNode; last = newNode;
return;
}
this.last.next = newNode;
this.last = newNode;
}
to copy the element correctly, you should do:
Node oldlast = new Node();
oldlast.item = String(last.item);
hope that helps.

java linked list copy constructor and constructor from string

I have 2 questions about linked lists so i figured i'll post them in one question.
first i'll show my node class and the copy constructor and constructor from a string
class CharNode
{
private char letter;
private CharNode next;
public CharNode(char ch, CharNode link)
{
letter = ch;
next = link;
}
public void setCharacter(char ch)
{
letter = ch;
}
public char getCharacter()
{
return letter;
}
public void setNext(CharNode next)
{
this.next = next;
}
public CharNode getNext()
{
return next;
}
}
copy constructor
// copy constructor
public CharList(CharList l)
{
CharNode pt = head;
while(pt.getNext() != null)
{
this.setCharacter() = l.getCharacter();
this.setNext() = l.getNext();
}
}
constructor from string
// constructor from a String
public CharList(String s)
{
head = head.setCharacter(s);
}
when i try to compile i get an error for my copy constructor it says that it cant find the symbol this.setCharacter()... and the l.setCharacter()...
am i just doing it completely wrong?
and with my constructor from a string i know thats wrong. i thought about using the charAt() but how would i know when to stop the loop to do that? is that a good approach to take?
any help would be appreciated.
in your CharList constructor, this refers to the CharList class, which doesn't have a setCharacter() method (CharNode does). also, when you call a method in java, you need to pass the parameter, e.g. setFoo(newFoo), not setFoo() = newFoo
Your set character method is probably in your node, not in your list. You also need to be moving your pointer along. What I mean is, where do you ever "go to the next node"?
Your copy constructor is for the class CharList, while setCharacter is defined in CharNode.
this in the copy constructor references the current instance of the CharList object the constructor is defined on. l is also a CharList in your code rather than a CharNode which defines setCharacter.
The copy constructor should be defined in the CharNode class.
In your "copy constructor" you would need to go through the list being passed in starting with its head, and create new nodes for your new list ...
public CharList(CharList l)
{
// Whatever method your CharList provides to get the
// first node in the list goes here
CharNode pt = l.head();
// create a new head node for *this* list
CharNode newNode = new CharNode();
this.head = newNode;
// Go through old list, copy data, create new nodes
// for this list.
while(pt != null)
{
newNode.setCharacter(pt.getCharacter());
pt = pt.getNext();
if (pt != null)
{
newNode.setNext(new CharNode());
newNode = newNode.getNext();
}
}
}
As for creating a list from a String ... same concept except you iterate through the string rather than another CharList
for (int i = 0; i < myString.length(); i++)
{
...
newNode.setCharacter(myString.charAt(i));
...

Manual Linked List - Insert before method

This is part of an exercise we did in class, I just can't figure it out...
The required method is the insertBefore(object data) method wherein when a user choose this method it will prompt it to enter a data to be inserted before the reference data(input by user)
An example of how it should run:
// assuming linked list has data 1,2,3 inserted already
Choose Method:
1)Insert Before
choice: 1 // input by user
====Insert Before====
Enter Reference data: 2 // input by user
Enter Data to be inserted: 5 // input by user
supposed output: 1,5,2,3
Here's my code for this exercise: (This is inside a class called LinkList with variables
protected int end;
protected Node start;
and an inner class called Node)
private class Node
{
public char data;
public Node next;
public Node(char data)
{
this.data = data;
}
}
public void insertBef(char ref,char data)
{
Node temp = new Node(data);
Node current = start;
if(end!=0)
{
for(int i = 1; i<end; i++)
{
if(current == start)
{
Node newNode = start;
newNode.data = current.data;
newNode.next = temp;
current = current.next;
}
else if(current.data == ref)
{
Node newNode = current;
newNode.data = current.data;
newNode.next = temp;
current = current.next;
}
}
end++;
}
else
{
temp.next = start;
start = temp;
}
end++;
}
But when I run my code it ouputs 3,5, not 1,5,2,3! I can't see where I might have gone wrong...
Can someone please tell me where the mistake is, and explain how I might fix it?
I understand that to be able to insert before a reference value you should:
Make a new node for the new data
Make a temporary node for the reference value and link
Make the link of the data before the reference value point to the new node and make the link of the new node point to the temporary node
I just can't seem to figure out how to implement it in Java code...
When programming, if it seems hard, you're probably going about it the wrong way...
You only need one line of code to accomplish the task!
list.add(list.indexOf(reference), data);
Here's this line wrapped as an insertBefore method:
public static void insertBefore(List<Integer> list, int reference, int data) {
list.add(list.indexOf(reference), data);
}
Here's a test using your example:
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
insertBefore(list, 2, 5);
System.out.println(list);
}
Output:
[1, 5, 2, 3]
Note: This code will throw an exception if the reference element is not found.
I'll leave it to you to plug that hole.
First things first: for loops are generally a bad idea with linked lists. while loops are much better; you can do something like while(next != null).
Looking at your code, you seem to have a few problems.
Your for loop is overly complicated, and doesn't seem to make a lot of sense. Here's how your loop should look:
Get head node
Begin looping through the list, checking the next node's value as you go
Once you find that the next node's value is the one you're looking for, creating a new node.
Insert the new node by setting its Next value to be equal to the current node's Next value, then set the current node's next value to be the new node.
Return from the function.
Your middle bullet point is actually unnecessary, and I have no idea what you use end for. Regardless, you seem to have the basic principle down, so I won't feel like I'm spoiling you by posting code.
Now, I'm not sure what your start is. Does it hold a value, or is it a dedicated head node? I'd vote for a dedicated head node, I generally find it easier to work with because you don't need to add code for a special case where the number should come before the head. So your start node should be "empty"; the value it holds is ignored, the only thing it's used for is to keep a pointer to the first legit node in the list. If you do this, the insertBef method becomes incredibly simple. NOTE: untested code to follow.
public void insertBef(char ref, char data)
{
Node current = start;
while( current.next != null )
{
if( current.next.value == ref )
{
Node n = new Node(data);
n.next = current.next;
current.next = n;
return;
}
current = current.next;
}
}
Please don't just copy the code. If you have questions, post them and I'll do my best to answer.

Categories

Resources