For Homework I was told to write the insert method(in order) of a custom linked list. I wrote the base case, but I still don't understand the recursion case. I know I just asked how to write the contain method and someone helped me out, but in that case I did not have to do any modifications to the list like on this method. Please help me understand what is causing my linked list to override and if there is an easier way to simplify my code.
Here is my code:
public class OrderedList {
private Node first;
//Constructor
public OrderedList() {
this.first = null;
}
//Return the number of items in the list
public int size() {
int counter = 0;
Node pointer = this.first;
while (pointer != null) {
counter++;
pointer = pointer.next;
}
return counter;
}
//Return an array of copies of the stored elements
public Comparable[] getStore() {
Comparable[] elements = new Comparable[size()];
Node pointer = this.first;
if (this.first == null) {
return elements;
} else {
int i = 0;
while (pointer != null) {
elements[i] = pointer.data;
pointer = pointer.next;
i++;
}
return elements;
}
}
//true iff item matches a stored element
//Recursive
public boolean contains(Comparable item) {
return containsHelper(this.first, item);
}
private boolean containsHelper(Node node, Comparable item) {
//base case
if (node == null) {
return false;
} else {
if (node.data.compareTo(item) == 0) {
return true;
}
return containsHelper(node.next, item);
}
}
//Add item preserving the order of the elements
//Recursive
public void insert(Comparable item) {
insertHelper(this.first, item);
}
public void insertHelper(Node pointer, Comparable item) {
//Base case
Node store = new Node(item);
if (pointer == null) {
store.next = this.first;
this.first = store;
return;
}
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer;
return;
}
if (pointer.data.compareTo(item) < 0 && pointer.next == null) {
store.next = pointer.next;
pointer.next = store;
return;
} else {
Node save = this.first;
this.first = this.first.next;
insertHelper(this.first, item);
if (pointer.data.compareTo(item) > 0) {
save.next = store;
this.first = save;
} else {
save.next = pointer;
this.first = save;
}
}
}
I'm only giving you part of the answer at first. Consider this a clue. Then there are more clues. See if you can figure it out before you get to the bottom where a whole answer is.
clue 1
This part of the code can't be in the recursive method because it makes reference to the head of the linked list. Your recursion is moving down the list, breaking it into the head and the rest, deciding whether to insert at the head and recursing if the insertion has to be in the rest.
if (pointer == null) {
store.next = this.first;
this.first = store;
return;
}
This should be modified a bit so it can go in the insert() method, which deals with the whole list.
Why?
Because this code deals with the whole list and asks the question, "Is this list empty?"
clue 2
Now, for this part of the code:
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer;
return;
}
Notice how it has a reference to the whole list. That's a bad thing.
Its asking the question, "Is the new item (to be inserted) supposed to go in front of the current head item?"
If the answer is yes, it needs to insert it in front of the current head, leave the current head with the current rest of the linked list attached as before and return something that lets the calling code attach a newly arranged rest of the list.
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer; // new item goes in front of this part of list
return store;
}
clue 3
Now, let's skip to this part of the code:
Node save = this.first;
this.first = this.first.next;
insertHelper(this.first, item);
if (pointer.data.compareTo(item) > 0) {
save.next = store;
this.first = save;
} else {
save.next = pointer;
this.first = save;
}
This code asks no questions. It just recurses since we know that no change is needed related to the head of the current linked list. When we recurse, we pass it the rest of the linked list and tell it to fix that up. We don't care how because we trust it to fix up the rest of the list by inserting the new item in the right place.
So here is what we do:
Node rest = insertHelper(pointer.next, item);
pointer.next = rest;
return pointer;
clue 4
This part of the code is the last part to consider:
if (pointer.data.compareTo(item) < 0 && pointer.next == null) {
store.next = pointer.next;
pointer.next = store;
return;
}
Now, think about why you are comparing it again. The previous code tested whether the item needed to go in front of the rest of the linked list. The answer was no.
That means there are only two possible situations left.
Either there is nothing left in the list ... and we have to put the new item on the end.
Or there is something in the list ... and clue 3 deals with that by recursing.
So this part gets a little simpler:
if (pointer.next == null) {
return store;
}
All we have to do is return the new node which will be the new "rest of the list", instead of there being nothing in the rest of the list.
One more note
Remember that the method signature has to change to be like this:
/**
* Insert the 'item' into the linked list beginning with the supplied node, 'pointer'
* #returns the new, modified linked list, with the new item in it.
*/
public Node insertHelper(Node pointer, Comparable item) {
The whole thing
This includes the changes to the 'insert' method:
public void insert(Comparable item) {
// if there isn't anything in the list, the new item becomes the whole list
if (first == null) {
Node store = new Node(item);
store.next = null;
this.first = store;
return;
}
// Otherwise let the helper fix up the list for us to store away
this.first = insertHelper(this.first, item);
}
public Node insertHelper(Node pointer, Comparable item) {
Node store = new Node(item);
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer; // new item goes in front of this part of list
return store;
}
if (pointer.next == null) {
return store; // new item becomes this part of the list
}
// The head of this part of the list is ok, fix the rest of the list
pointer.next = insertHelper(pointer.next, item);
return pointer;
}
Further comments
There is another way to do this where you store the first node in some other class and each Node only stores a pointer to the rest of the list (as next).
Then you have a method to insert that knows when it gets called that it can't be null because you couldn't call it if it was null.
There is no test for the first one being null inside insert because of that. But it means the caller has to do something like:
Node item = new Node(data);
if (list != null) {
list.insert(item);
} else {
list = item;
}
and the insert method looks like this:
if (this.next == null || this.data > item.data) { // pseudo code for greater than
item.next = this.next;
this.next = item;
return;
}
this.next.insert(item);
And that's it.
Related
I have written my own linked list and am reading integers from a file into the list and printing them out. However, only the head of my list is printing and nothing else. I've been staring at this code for so long I feel insane, can anyone help?
Method in a separate 'files' class that reads in a file of integers separated by whitespace. This method will take the next integer and add it to my linked list.
public void readValues() {
LinkedList list = new LinkedList();
while(scan.hasNextInt()) {
Integer someData = scan.nextInt();
list.addNode(someData);
}
list.printList();
}
This method is in my LinkedList class which takes the data sent from my readValues method in my files class.
public void addNode(Integer someData) {
myNode = new LinkedNode(someData,null);
//initialize node if this is first element
if (head == null) {
head = myNode;
size++;
}
else if (myNode.getNext() == null) {
myNode.setNext(myNode);
size ++;
}
else if (myNode.getNext() != null) {
while(myNode.getNext() != null) {
myNode = myNode.getNext();
}
myNode.setNext(myNode);
size++;
}
}
This method is also in my LinkedList class and successfully prints the head of my list which with my data is the number 40 followed by ---> and then nothing else. It should print ever other integer read in from my file.
public void printList() {
LinkedNode current = head;
if (head == null) {
System.out.print("list is empty");
return;
}
while(current != null) {
System.out.print(current.getElement());
System.out.print(" --> ");
current = current.getNext();
}
}
LinkedNode class:
public class LinkedNode {
Integer data;
LinkedNode next;
public LinkedNode(Integer someData, LinkedNode next) {
this.data = someData;
this.next = null;
}
public int getElement() {
return data;
}
public void setElement(Integer data) {
this.data = data;
}
public LinkedNode getNext() {
return next;
}
public void setNext(LinkedNode next) {
this.next = next;
}
public String toString() {
return data + "";
}
}
Your code has a small bug in the if else conditions in your addNode() method due to which your data is not getting added in the list.
Root Cause
When you add a new node to your list,
In the first iteration
The head is currently null and hence the first if conditions becomes true and your first node gets added (That's why you got the data 40).
In the Subsequent iteration(s)
your else if condition checks the myNode's next pointer which will always be null (as per the constructor) and thus it's next pointer points towards itself. The nodes created from here do not become the part of the list as the next pointer of head was never assigned to any of these and these nodes also point to themselves only.
Solution
I made a little modification in the if else conditions:
public void addNode(Integer someData) {
LinkedNode myNode = new LinkedNode(someData,null);
//initialize node if this is first element
if (head == null) {
head = myNode;
size++;
}
else if (head.getNext() == null) {
head.setNext(myNode);
size ++;
}
else if (head.getNext() != null) {
System.out.println("in second else if");
LinkedNode n = head;
while(n.getNext() != null) {
n = n.getNext();
}
n.setNext(myNode);
size++;
}
}
PS: Try debugging your code with dry run, it's a great mental exercise and helps in boosting the learning curve significantly too. All the best! :)
The problem is with your addNode() method. Inside the addNode() method you are first creating a new node named mynode. Now when the head is null it sets head to mynode, thats ok. But when the head is not null the mynode is not being added to the list. Thats why only the first element exist and other's are getting lost.
Hope this helps. Let me know if I can help with anything else. Happy coding!
I wrote A node class whose 'data' field is designed to hold any type of data and A linked list class designed to hold nodes with any type of data. I was implementing a class to delete duplicates ("deleteDuplicates") and found myself having trouble setting the tail to null ("deleting the tail") of my linked list and I feel like it's because I'm trying to set a class to null. What am I not understanding? I was hoping someone could correct my thinking. Specifically see my commented out code TODO on line 116 in the method deleteDuplicates.
import java.io.*;
// A node class whose 'data' field is designed to hold any type of data.
class node<AnyType> {
AnyType data;
node<AnyType> next;
// Constructor; sets this object's 'data' field to 'data'.
node(AnyType data) {
this.data = data;
}
}
// A linked list class designed to hold nodes with any type of data.
public class LinkedList<AnyType> {
// Notice that when you create a LinkedList object (in main(), for example),
// you tell it what kind of data it'll be holding. The LinkedList class
// needs to pass that information on to the node class, as well. That's
// what's happening here.
private node<AnyType> head, tail;
// insert at the tail of the list
void insert(AnyType data) {
// if the list is empty, set 'head' and 'tail' to the new node
if (head == null) {
head = tail = new node<AnyType>(data);
}
// otherwise, append the new node to the end of the list and move the
// tail reference forward
else {
tail.next = new node<AnyType>(data);
tail = tail.next;
}
}
// insert at the head of the list
void headInsert(AnyType data) {
// first, create the node to be inserted
node<AnyType> YouCanJustMakeANewNode = new node<AnyType>(data);
// insert it at the beginning of the list
YouCanJustMakeANewNode.next = head;
head = YouCanJustMakeANewNode;
// if the list was empty before adding this node, 'head' AND 'tail'
// need to reference this new node
if (tail == null)
tail = YouCanJustMakeANewNode;
}
// print the contents of the linked list
void printList() {
for (node<AnyType> temp = head; temp != null; temp = temp.next)
System.out.print(temp.data + " ");
System.out.println();
}
// Remove the head of the list (and return its 'data' value).
AnyType removeHead() {
// if the list is empty, signify that by returning null
if (head == null)
return null;
// Store the data from the head, then move the head reference forward.
// Java will take care of the memory management when it realizes there
// are no references to the old head anymore.
AnyType temp = head.data;
head = head.next;
// If the list is now empty (i.e., if the node we just removed was the
// only node in the list), update the tail reference, too!
if (head == null)
tail = null;
// Return the value from the old head node.
return temp;
}
node<AnyType> deleteNode(node<AnyType> data)
{
node<AnyType> helper = head;
if( helper.equals(data) )
{
return head.next;
}
while( helper.next != null )
{
if( helper.next.equals(data) )
{
helper.next = helper.next.next;
return helper;
}
helper = helper.next;
}
return helper;
}
void deleteDuplicates( LinkedList<Integer> L1 )
{
for (node<Integer> temp = L1.head; temp != null; temp = temp.next)
{
for (node<Integer> helper = temp; helper.next != null; helper = helper.next)
{
//start at helper.next so that temp doesn't delete it's self
if( temp.data == helper.next.data && helper.next.next != null )
{
helper.next = helper.next.next;
}
/* TODO: DELETE TAIL
//can't seem to figure out how to delete the tail
if( temp.data == helper.next.data && helper.next.next == null )
{
//helper.next = null;
}
*/
}
}
}
// returns true if the list is empty, false otherwise
boolean isEmpty() {
return (head == null);
}
public static void main(String [] args) {
// create a new linked list that holds integers
LinkedList<Integer> L1 = new LinkedList<Integer>();
/*
for (int i = 0; i < 10; i++)
{
// this inserts random values on the range [1, 100]
int SomeRandomJunk = (int)(Math.random() * 100) + 1;
System.out.println("Inserting " + SomeRandomJunk);
L1.insert(SomeRandomJunk);
}
*/
//8,24,15,15,9,9,25,9
L1.insert(8);
L1.insert(24);
L1.insert(15);
L1.insert(15);
L1.insert(9);
L1.insert(9);
L1.insert(25);
L1.insert(9);
//L1.insert(9);
//L1.insert(9);
// print the list to verify everything got in there correctly
System.out.println("Printing integer linked list");
L1.printList();
System.out.println("Printing DEL-repeaded LL");
L1.deleteDuplicates(L1);
L1.printList();
// create another linked list (this time, one that holds strings)
LinkedList<String> L2 = new LinkedList<String>();
L2.insert("Llamas");
L2.insert("eat");
L2.insert("very sexy");
L2.insert("critical thinking");
L2.insert("Paper clips annd now I'm ");
L2.insert("daydreaming");
// print the new list to verify everything got in there correctly
while (!L2.isEmpty())
System.out.print(L2.removeHead() + " ");
System.out.println();
// print the old list just to verify that there weren't any static
// problems that messed things up when we created L2
L1.printList();
}
}
It will work if you change to this:
for (node<Integer> helper = temp; helper != null && helper.next != null; helper = helper.next)
{
//start at helper.next so that temp doesn't delete it's self
if( temp.data == helper.next.data && helper.next.next != null )
{
helper.next = helper.next.next;
}
//can't seem to figure out how to delete the tail
if( temp.data == helper.next.data && helper.next.next == null )
{
helper.next = null;
}
}
That is, in the loop condition instead of:
helper.next != null
You need one more condition:
helper != null && helper.next != null
This is because after you set helper.next = null;,
the loop moves forward and executes helper = helper.next,
and then in the next iteration the loop condition helper.next != null
throws a NullPointerException because helper is null.
for homework I was asked to write a contain method for a custom linked list.
I know that the recursive method should have a base case and then the recursive case.However, I am having some trouble understanding how to write the recursive case of the method. So far this is what I have written, but my code is executing the base case more than once. Can you please give me some guidance?
public class OrderedList {
private Node first;
//Constructor
public OrderedList() {
this.first = null;
}
//Return the number of items in the list
public int size() {
int counter = 0;
Node pointer = this.first;
while (pointer != null) {
counter++;
pointer = pointer.next;
}
return counter;
}
//Return an array of copies of the stored elements
public Comparable[] getStore() {
Comparable[] elements = new Comparable[size()];
Node pointer = this.first;
if (this.first == null) {
return elements;
} else {
int i = 0;
while (pointer != null) {
elements[i] = pointer.data;
pointer = pointer.next;
i++;
}
return elements;
}
}
//true iff item matches a stored element
//Recursive
public boolean contains(Comparable item) {
//Base case
if (this.first == null) {
return false;
}
Node pointer = this.first;
this.first = this.first.next;
if (pointer.data.compareTo(item) == 0) {
return true;
}
//Recursive case
else {
boolean info = contains(item);
pointer.next = this.first;
this.first = pointer;
return info;
}
}
First of all I like to do something like this:
public boolean contains(Comparable item)
{
return containsHelper(this.first, Comparable item);
}
private boolean containsHelper(Node node, Comparable item)
{
//base case
if(node == null)
{
return false;
}
else
{
if(node.data.compareTo(item) == 0)
{
return true;
}
return containsHelper(node.next, item);
}
}
This hides implementation details from the user and it stops your list from getting overridden when you run that method.
To implement a recursive solution, you need an auxiliary method for contains. The auxiliary method should have an additional argument that is the Node from which to start testing. The public contains method should call the auxiliary method and pass this.first as the start node. The rest of the logic should then be pretty simple for you to figure out.
From what I am seeing, your code will return true once the else statemnet have been executed once. I think what you need to do is to set the boolean value to false everytime because recursion acts very much like a while loop and if the values are not updated, the base case would be executed over and over again.
I want to remove duplicates from sorted linked list {0 1 2 2 3 3 4 5}.
`
public Node removeDuplicates(Node header)
{
Node tempHeader = null;
if(header != null)
tempHeader = header.next;
else return header;
Node prev = header;
if((tempHeader == null)) return header ;
while(tempHeader != null)
{
if(tempHeader.data != prev.data)
{
prev.setNext(tempHeader);
}
tempHeader = tempHeader.next;
}
prev = header;
printList(prev);
return tempHeader;
}
`
prev.setNext(tempHeader) is not working correctly inside the while loop. Ideally when prev = 2 and tempHeader = 3, prev.next should be node with data = 3.
Printlist function just takes header pointer and prints the list.
Node definition is given below.
public class Node
{
int data;
Node next;
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
The loop is sorted, so you know that duplicates are going to sit next to each other. If you want to edit the list in place then, you've got to have two list pointers (which you do). The one you call tempHeader and prev, and you've got to advance them both in the the list as you go (which I don't see in the code). Otherwise, if you don't advance the prev pointer as you go, then you're always comparing the element under tempHeader to the first item in the list, which is not correct.
An easier way to do this, however, is to build a new list as you go. Simply remember the value of the last item that you appended to the list. Then if the one that you're about to insert is the same then simply don't insert it, and when you're done, just return your new list.
I can give you 2 suggestions for the above suggestion
1) Convert the linked List to Set, that will eliminate the duplicates and
Back from Set to the Linked list
Code to get this done would be
linkedList = new LinkedList<anything>(new HashSet<anything>(origList));
2) You can use LinkedHashSet, if you dont want any duplicates
In this case no return value is needed.
public void removeDuplicates(Node list) {
while (list != null) {
// Walk to next unequal node:
Node current = list.next;
while (current != null && current.data.equals(list.data)) {
current = current.next;
}
// Skip the equal nodes:
list.next = current;
// Take the next unequal node:
list = current;
}
}
public ListNode removeDuplicateElements(ListNode head) {
if (head == null || head.next == null) {
return null;
}
if (head.data.equals(head.next.data)) {
ListNode next_next = head.next.next;
head.next = null;
head.next = next_next;
removeDuplicateElements(head);
} else {
removeDuplicateElements(head.next);
}
return head;
}
By DoublyLinked List and using HashSet,
public static void deleteDups(Node n) {
HashSet<Integer> set = new HashSet<Integer>();
Node previous = null;
while (n != null) {
if (set.contains(n.data)) {
previous.next = n.next;
} else {
set.add(n.data);
previous = n;
}
n = n.next;
}
}
doublylinkedList
class Node{
public Node next;
public Node prev;
public Node last;
public int data;
public Node (int d, Node n, Node p) {
data = d;
setNext(n);
setPrevious(p);
}
public Node() { }
public void setNext(Node n) {
next = n;
if (this == last) {
last = n;
}
if (n != null && n.prev != this) {
n.setPrevious(this);
}
}
public void setPrevious(Node p) {
prev = p;
if (p != null && p.next != this) {
p.setNext(this);
}
}}
I'm trying to insert items into a custom linked list, while keeping the list in order.
My work up to now is this:
public class CustomList {
public CustomList() {
this.first = null;
}
public void insert(Comparable newThing) {
Node point = this.first;
Node follow = null;
while (point != null && point.data.compareTo(newThing) < 0) {
follow = point;
point = point.next;
}
if (point == null) {
Node newNode = new Node(newThing);
newNode.next = this.first;
this.first = newNode;
} else {
Node newNode = new Node(newThing);
newNode.next = point;
if (follow == null) {
this.first = newNode;
} else {
follow.next = newNode;
}
}
}
private Node first;
private class Node {
public Comparable data;
public Node next;
public Node(Comparable item) {
this.data = item;
this.next = null;
}
}
}
The output I get from this looks like it orders parts of the list, then starts over.
Example (I'm sorting strings):
Instead of getting something like a,b,c,...,z
I get a,b,c,...,z,a,b,c,...,z,a,b,c,...,z
So it looks like it doesn't "see" the whole list at certain points.
This is part of a HW assignment, so I'd appreciate suggestions, but let me try to figure it out myself!
What happens if you insert an element which is greater than all your existing elements?
You want to insert the element at the end, but in fact you are inserting it at start. And any later elements will then inserted before this (if they are smaller), or again at start.