I'm having trouble with a homework assignment, moving through a doubly linked list using an iterator. The following is the method that seems to be the problem, but it seems logically correct to me. I have a runner file that I'm using to pass a list, the runner file prints out both forwards and backwards to see if my links are working correctly. If I add a item using the add(T element) method it works fine both forwards and backwards. However, if I add an item using the add(T element, int index) method the list will output correctly forwards but on the backwards iterator the newly added item isn't in the output.
which leaves me to suspect current.getNextNode().setPriorNode(newNode); is the problem but it seems like it would be correct to me, or am I wrong?
Thanks you!
UPDATE: I edited the code with the fix for incase anyone else has the same problem in the future.
public void add(T element) {
Node<T> node = new Node(element);
if (itsFirstNode == null) {
itsFirstNode = node;
itsLastNode = node;
}
else {
itsLastNode.setNextNode(node);
node.setPriorNode(itsLastNode);
itsLastNode = node;
}
size++;
} // end of add() method
public void add(T element, int index) {
int counter = 0;
Node<T> newNode = new Node(element);
Node<T> current = itsFirstNode;
while (current.getNextNode() != null ) {
if (counter == index - 1 )
break;
current = current.getNextNode();
counter++;
}
newNode.setNextNode(current.getNextNode());
current.getNextNode().setPriorNode(newNode);
newNode.setPriorNode(current);
current.setNextNode(newNode);
size++;
} // end of Overloaded add() method
newNode.setNextNode(current.getNextNode());
current.setNextNode(newNode);
newNode has next one set correctly, current has next one as newNode
newNode.setPriorNode(current);
newNode has prior set correctly
current.getNextNode().setPriorNode(newNode);
current.getNextNode() is newNode, so you set newNode as the prior of newNode. It should work if you move this line two lines earlier
instead of
current.getNextNode().setPriorNode(newNode);
try
newNode.getNextNode().setPriorNode(newNode);
You can use following code in last 5 line
newNode.setNextNode(current.getNextNode());
current.getNextNode().setPriorNode(newNode);
current.setNextNode(newNode);
newNode.setPriorNode(current);
size++;
Related
I am having a lot of difficulty figuring out the add method of a linked list. My assignment says to:
Implement this method, public void add(E item), inside MoveToFront
class. The method behaves like this: when the input does not exist in
the linked list, add it at the front; otherwise remove the existing
one from the list and reinsert it to the front.
What I have done so far is create a contains and delete method that will search for the existing item in the list and then delete it. Then it will add the item to the front of the list.
public int getLength() {
Node<E> curNode = first;
int count = 0;
while (curNode != null) {
curNode = curNode.next;
count++;
}
return count;
}
public boolean Contains(E item) {
if (first == null) {
return false;
}
Node<E> currentNode = first;
while (currentNode.next != null) {
containCount++;
if (currentNode.item.equals(item)) {
return true;
}
currentNode = currentNode.next;
}
return false;
}
public E Delete(int kth) {
if (kth <= getLength()) {
Node<E> currentNode = first;
for (int i = 1; i < kth; i++) {
currentNode = currentNode.next;
}
currentNode.next = currentNode.next.next;
return currentNode.item;
} else {
return null;
}
}
public void add(E item) {
if (!Contains(item)) {
Node<E> myNode = new Node<E>(item, null);
first = myNode;
} else {
Delete(containCount);
Node<E> myNode = new Node<E>(item, null);
first = myNode;
}
}
I think you aren't properly linking the nodes. Before you set the node you're inserting as the first node, set the node's next to the old first, like this:
myNode.next = first;
first = myNode;
A couple of things:
Instead of going through the list twice to first check if it contains the item, then to find and delete it, you can rewrite delete() to just go through the list and delete if a matching item is found. You can then call this method at the beginning of your add() method.
You should keep track of the size of the list with a simple instance variable that is updated whenever an item is added or removed, and then just let getLength() return this. Going through the whole list each time is way too expensive.
First of all I see a getLength() method in your code. It is a linked list, if you are trying to get the length of it for this problem then you didn't get the data structure.
Now if we get to implementation I see from the requirement you have to add new element to the front one way or another. This is how I will do that-
Create a node and link its next to the first element of current list. This will be add method.you can do this method in the end too, it will not make much difference.
Then start searching for element in the list and if you find a match delete it. Make sure you don't match with the element you just added int the front.
I'm preparing for interviews and wrote up this simple function for recursively reversing a singly linked list. The first node is a sentinel node, head. The following code works fine for: list.reverse(list.head.next), but I can't seem to get it to work if I just pass it head.
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
reverse(current.next).next = current;
current.next = null;
return current;
}
I assume it doesn't work when I pass it head instead of head.next because I say current.next = null, but even if I check if current == head or if current.data == null and only use current.next = null when those aren't true, it still doesn't work. I'm sure there's a really simple fix, but I'm just not seeing it right now.
The above if passed head returns an empty list, and if the suggested changes are made, simply doesn't finish running, but I don't get any sort of error.
(EDITED)
I kind of get your problem now:
Simply speaking, the sentinel head acts simply as a pointer to the first node, instead of being part of the linked list. Therefore it will not be involved in the reverse process, and need to handle separately.
which means, the original list looks like:
HEAD -> a -> b -> c -> null
after reverse, it should look like
HEAD -> c -> b -> a -> null
In brief, it should look like (assume your code already works when passing in head.next)
public Node<T> reverse(Node<T> current)
{
if (current == head) {
return reverse(current.next);
}
// rest of your original code.
}
Just a further suggestion:
Your reverse() method, as an public instance method of your list class, shouldn't accept the current node, as it is conceptually meaningless for caller.
I believe you should make this method protected, which means something like:
public void reverse() {
this.head = reverseInternal(head);
}
private Node<T> reverseInternal(Node<T> node) {
// your original reverse logic
}
With such encapsulation, you don't even need to struggle before how to make your reverse works when you pass in the sentinel head: you can simply call reverseInternal(head.next) in your public reverse() method.
First: if it returns an empty list it doesn't "work".
There is no need for head to be an empty node. You should normally just keep the first node (in your case list.head.next) as your list.head. head should be a reference to where the list starts, not a separate node.
The reason your code empties the list when you pass it list.head is it sets list.head.next to null. This is because you assume the node you pass to the list is a regular one, while your head node is special.
Here's a solution for your assumptions (I'll assume someone insisted on this bizarre detached head thing. Just don't do it if you're designing the list yourself. Please...)
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
Node<T> temp = current.next;
current.next = null;
head.next = temp;
reverse(temp).next = current;
return current;
}
Explanation: This still sets the last node's next to null, but it pushes the list's head one spot down as it runs through the list, eventually pointing it to the last (now first) member.
This reeks of homework.
But still.
In general:
f(Node<T> current, ...) {
f(current.next, ...);
}
For a list a > b > c > d > e sitting in the midle at d, one
probably has built c > b > a already, so guess what is needed as additional parameter to f?
Good luck.
After comments:
public Node<T> reverse(Node<T> current)
{
return reverseRec(current, null);
}
/**
* #param current to-do (sub-)list.
* #param resultDone done reversed list sofar.
* #return reversed result.
*/
public Node<T> reverseRecursively(Node<T> current, Node<T> resultDone)
{
if (current == null) {
return resultDone;
}
Node<T> next = current.next;
current.next = resultDone;
return reverseRecursively(next, current);
}
I am trying to make an add method for a linked list, but for some reason (that is not obvious to me, in fact I came here to get help finding the error) it goes into an infinite loop every time.
EDIT: I found the error, and I will keep my original code with a comment with the corrected code
public void insert(String majorName)
{
MajorNode newNode = new MajorNode(majorName, 1);
boolean inList = false;
MajorNode current = first;
if(isEmpty())
{
first = newNode;
// inList = true;
}
else
{
while(current.next != null)
{
if(current.majorName.equalsIgnoreCase(majorName))
{
current.frequency++;
inList = true;
break;
}
else
{
current = current.next;
}
}
}
if(!inList)
{
newNode.next = first;
first = newNode;
}
}
Here is my node class if it is needed:
public class MajorNode
{
public String majorName;
public int frequency;
public MajorNode next;
public MajorNode(String majorName, int frequency)
{
this.majorName = majorName;
this.frequency = frequency;
}
public String toString()
{
return majorName + " " + frequency;
}
}
On the first call to insert(), one assumes isEmpty() returns true and consequently first is set to the newNode before newNode's next field is set to the previous (null) value of first. Thus, when the list is non-empty, the loop iterates indefinitely on the last element in the list whose next field points to itself.
Out of curiosity, why are you trying to implement your own linked list functionality rather than build upon available packages (such as java.util.LinkedList<E>)?
When you create the first node you do this:
if(!inList)
{
newNode.next = first;
first = newNode;
}
This points the first nodes next at itself... hence a loop
You should be leaving the newNode.next as null for the first node, so that when you insert the second item, you reach the end of the chain..
You will have an wrong frequency if you add a node which is similar to the last node of your List. Consider this situation (adding 2 similar nodes in the empty list)
You will add a node1 in a blank list. So first & current will point to node1. (but node1.next will be null)
If you add the same node (or a node with a same majorName), you will reach to while loop (because List is not empty now). And also, you will not enter into a while loop as well. (as your current.next is still null)
and you will end up with two noes with same majorName in your list.
I would suggest to use
while(current != null)
instead of
while(current.next != null)
This is for homework but please know that I have looked online for help (such as http://www.sethi.org/classes/class_stuff/cis435/others/notes-java/data/collections/lists/simple-linked-list.html) and my textbook but I am still having some issues.
Any help would be appreciated...
Right now I'm trying to just insert values in but nothing is working. Whether it's the first item, whether it's being added as the last one, or somewhere in between.
Node header = null; // First element of list.
Node back = null; // Last element of list.
public void insert(int i, double value){ //insert value before i-th element
Node e = new Node();
e.num = value;
Node curr = header;
for(int x=0;x<i;x++) {
if (i == 1) { //we want to insert as first thing
if (size == 0) { //its the FIRST time we add something
header.next = e;
e.next = back;
break;
} else if (size == 1){
e.next = header.next; //i.e. the second thing in the list
header.next = e;
break;
} else {
e.next = header.next.next; //i.e. the second thing in the list
header.next = e;
break;
}
}
else if (x == (i-1)) {
e.next = curr.next;
curr.next = e;
break;
}
curr = curr.next;
}
size = size+1;
}
Not really sure why it isn't working.
Thanks!
For some reason, people who are still learning to program make things far more complicated then they need to be. I did it when I was learning java, I still do it when I am just getting into a new language, and students that I have marked find new and amazing ways to do it. You have more going on in your insert then there needs to be, for example, a method that inserts a value at a specific index should not check if it's the first item to be inserted (not saying it shouldn't check bounds). Here is the pseudo code of what I would do.
insert(index, value)
if index>size
throw null pointer
traverse to index -1 //lets call this nodeI
create newnode and set value
set newnode.next to nodeI.next
set nodeI.next to newnode
increase size.
Couple of handy hints for you, you should have a function to get an element from the link list, something that returns a node? public node elementAt(int index) for example? use that to traverse the linked list. If you want to append to the Linked list, try this
append(value)
insert(size-1,value)
and if you want to insert at the beginning? same idea
insert(value)
insert(0,value)
In the line e.next = header.next.next what would happen if header.next points to a 'null'? Is it possible to get there?
What are the corner cases you have to deal with and have you taken them all into account?
Can you start with the simplest case first, adding either an element to the front or an element to the back? Then use those functions to implement the insert?
A few suggestions:
implement java.util.List
Think about generics
Read this.
Start with "insert at the end" before you think about "insert at i".
I have tried a simple program, which will be useful for you guys, I am also learning Java, please bear with me for any mistakes, but this program works fine.
I am posting a very simple singly linked list program in Java, which I tried out today.
I hope it will help all.
LinkList.java
class LinkList
{
public static void main(String args[])
{
Node node = new Node(1);
node.addAtLast(2);
node.addAtLast(3);
node.addAtLast(4);
node.addAtLast(5);
node.printList();
}
}
Node.java
class Node
{
private int data;
private Node link;
public Node(int mydata)
{
data = mydata;
link = null;
}
public void printList()
{
System.out.print("|"+data+"|"+"->");
if(link != null)
{
//recursive call
link.printList();
}
else
{
//marking end of list as NULL
System.out.print("|NULL|");
}
}
public void addAtLast(int mydata)
{
if(link == null)
{
link = new Node(mydata);
}
else
{
link.addAtLast(mydata);
}
}
}
OUTPUT :
The below is our output
|1|->|2|->|3|->|4|->|5|->|NULL|
What is a doubly linked list's remove method?
The same algorithm that Bill the Lizard said, but in a graphical way :-)
(source: jaffasoft.co.uk)
The general algorithm is as follows:
Find the node to remove.
node.previous.next = node.next
node.next.previous = node.previous
node.previous = null
node.next = null
Dispose of node if you're in a non-GC environment
You have to check the previous and next nodes for null to see if you're removing the head or the tail, but those are the easy cases.
public void remove ()
{
if (getPreviousNode () != null)
getPreviousNode ().setNextNode (getNextNode ());
if (getNextNode () != null)
getNextNode ().setPreviousNode (getPreviousNode ());
}
Doubly Linked List Implementation Remove Methods (from my second programming assignment):
public void remove(int index) {
if(index<0 || index>size())
throw new IndexOutOfBoundsException("Index out of bounds. Can't remove a node. No node exists at the specified index");
if(size()==0) {
throw new NullPointerException("Empty list");
}
if(!isEmpty()) {
Node current;
//starting next one to our head
current = head.next;
for(int i=0;i<index;i++) {
current = current.next;
}
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
}
}
public boolean remove(T o) {
Node current = head;
for(int i=0;i<size();i++) {
current=current.next;
if(current.data.equals(o)) {
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
return true;
}
}
return false;
}
Are you asking for the name of a method in the api? That answer would simply be remove, assuming you are asking about java.util.LinkedList which is in fact a double linked list.
...or are you asking about what the name of the algorithm to remove an element from that type of data structure is called? Well.. the answer for that would also be to remove an element. Now for the actual algorithm to do it... it's really just a matter of changing the next pointer in the previous node and the last pointer in the next node. However, if you are using your data structure from multiple threads, you will need to either synchronize the remove method, or do the removal steps in an order that will make sense for your usage pattern for the data structure.
What about the current pointer pointer? You have to move crnt to the next node.
http://pastebin.ca/1249635