Data structures class, implementing a singly linked-list with head, tail and current nodes. Having trouble with a method, could use a nudge in the right direction.
From the assignment, write the method:
add( item ) : adds the item (String) after the current node in the list and sets the current pointer to refer to the new node.
My attempt:
public void add(String item)
{
if(curr != null)
{
Node newNode = new Node(item, curr.next);
curr.next = newNode;
curr = newNode;
}
else
{
head = tail = new Node(item, null);
curr = head;
}
}
My add method only seems to work when I'm adding items to the middle of the list, not on either end. If I use it to add a few items and then print the list, only the first one I added will be on the list, while my prepend and append methods have tested just fine.
Is there any glaring issue with my code? I feel like I'm missing something obvious.
All:
public class LinkedList {
Node head = null; /* Head of the list */
Node tail = null; /* Tail of the list */
Node curr = null; /* Current node in the list */
public void prepend(String item) {
if (head == null) {
head = tail = new Node(item, null);
curr = head;
} else {
head = new Node(item, head);
curr = head;
}
}
public void append(String item) {
if (head == null) {
head = tail = new Node(item, null);
curr = tail;
} else {
tail.next = new Node(item, null);
tail = tail.next;
curr = tail;
}
}
public void add(String item) {
if (curr != null) {
Node newNode = new Node(item, curr.next);
curr.next = newNode;
curr = newNode;
} else {
head = tail = new Node(item, null);
curr = head;
}
}
public void delete() {
if (curr.next == null) {
Node temp = head;
while (temp.next != curr) {
System.out.println(temp.item);
temp = temp.next;
}
temp.next = null;
curr = head;
}
}
public void find(String item) {
Node temp = new Node(curr.item, curr.next);
if (item.equals(temp.item))
curr = temp;
else {
temp = temp.next;
while (temp.next != null && temp != curr) {
if (item.equals(temp.item))
curr = temp;
}
}
}
public String get() {
if (curr != null)
return curr.item;
else
return "";
}
public boolean next() {
if (curr != tail) {
curr = curr.next;
return true;
} else
return false;
}
public void start() {
curr = head;
}
public void end() {
curr = tail;
}
public boolean empty() {
if (head == null)
return true;
else
return false;
}
}
Node class:
class Node {
Node next;
String item;
Node(String item, Node next) {
this.next = next;
this.item = item;
}
}
There is indeed a problem in add: it doesn't update tail when nodes already exist. Consider this sequence of actions:
LinkedList list = new LinkedList();
list.add("one");
list.add("two");
list.append("three");
If you were to then print it using this:
public void print() {
Node curr = this.head;
while(curr != null) {
System.out.println(curr.item);
curr = curr.next;
}
}
Like this:
list.print();
You'd get the following output:
one
three
This happens because tail -- which append relies on -- continues to point to the first Node after the second add operation is performed.
I don't see any problems here, so I would guess the issue is elsewhere.
Okay, the only issue I see there is in delete:
public void delete()
{
Node temp = head;
while(temp != null && temp.next != curr) {
System.out.println(temp.item);
temp=temp.next;
}
if (temp != null && temp.next != null) {
temp.next = temp.next.next;
}
curr = head;
}
I think I have found your problem.
If you use append() you add it directly after the tail. But when you have added previous nodes after the tail you don't set your tail to the new node. This means that once you call append() twice you loose all the nodes that you have added after the first append().
Brief example:
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("First add");
list.append("First Append");
list.add("Second add");
list.prepend("First prepend");
list.add("Third add");
list.prepend("Second prepend");
list.add("fourth add");
list.append("Second Append");
list.add("Fifth add");
list.add("Sixth add");
list.start();
do {
System.out.println(list.get().toString());
} while (list.next());
}
Output:
Second prepend
fourth add
First prepend
Third add
First add
First Append
Second Append
Conclusion: "Second Add" is lost, as well as "Fifth add" and "Sixth add" because your next() method stops as soon as it reaches the tail. You need to always update the tail if you add a new node in the end.
Hope this helps.
Cheers, Chnoch
I think the problem is
if (curr != null) {
Node newNode = new Node(item, curr.next); //<-- here (curr.next)
//and
Node(String item, Node next) {
this.next = next; //<-- here
Try (Edited):
Node newNode = new Node(item, curr); // pass curr to the constructor of Node
curr = newNode;
Related
How can I add it and delete Node First and delete Node Last in a double-link list
Just want to add delete Node First and delete Node Last. I did not know how to add it in your programming, but I want to help it solve it
i have 3 class
class node .
class doublyLinkedListMain .
class doublyLinkedList .
I want to add special programming in class doublyLinkedList this one delete Node First and delete Node Last
class doublyLinkedList
{
Node head;
public void push(int newdata)
{
Node NewNode = new Node(newdata);
NewNode.next = head;
NewNode.prev = null;
if (head != null) head.prev = NewNode;
head = NewNode;
}
public void insertAfter(Node PrevNode, int newdata)
{
if (PrevNode == null)
{
System.out.println("The given previous node cannot be null");
return;
}
Node NewNode = new Node(newdata);
NewNode.next = PrevNode.next;
PrevNode.next = NewNode;
NewNode.prev = PrevNode;
if (NewNode.next != null)
NewNode.next.prev = NewNode;
}
public void append(int newdata)
{
Node NewNode = new Node(newdata);
Node last = head;
NewNode.next = null;
if (head == null)
{
NewNode.prev = null;
head = NewNode;
return;
}
while (last.next != null) last = last.next;
last.next = NewNode;
NewNode.prev = last;
return;
}
void insertBefore(Node NextNode, int newdata)
{
if (NextNode == null)
{
System.out.println("the given next node cannot be NULL");
return;
}
Node NewNode = new Node(newdata);
NewNode.data = newdata;
NewNode.prev = NextNode.prev;
NextNode.prev = NewNode;
NewNode.next = NextNode;
if (NewNode.prev != null)
NewNode.prev.next = NewNode;
else head = NewNode;
}
void deleteNode( Node del)
{
if (head == null || del == null) return;
if (head == del) head = head.next;
if (del.next != null) del.next.prev = del.prev;
if (del.prev != null) del.prev.next = del.next;
return;
}
void printList()
{
Node n = head;
while (n != null)
{
System.out.print(n.data+" ");
n = n.next;
}
System.out.print(" \n ") ;
}
}
sorry, but you have different mistakes in your code. Firstly, for a list you need two or three pointers as attribute in your List class (Node head /* begin */, tail /* end */, current /* yes, the current element on which you have access */ - I have learned it with a current pointer but depending on your implementation you can do it without it too). Because of that, you must change some of your code. For example, you need a hasAccess() : boolean method, if you use a current pointer, which return current != null and your methods must consider and use tail. Furthermore, you should add a method isEmpty():
public boolean isEmpty() {
return head == null;
}
This method checks if the list is empty. In the case, that the list is empty (the method returns true), you cannot do some things, but you had seen that yet. But, because of the new pointer tail, you have its much easier to delete the last Node (see below).
Please, change all your attributes to private and code a getter and a setter for each of them. For example in the class Node for the attribute next:
private Node next;
// other code...
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
I have solved the problem with "delete Node First and delete Node Last" in the following way:
public class DoublyLinkedList {
private Node head; // begin
private Node tail; // end
public void deleteFirstElement() {
if (!isEmpty()) {
head = head.getNext();
}
}
public void deleteLastElement() {
if (!isEmpty()) {
tail = tail.getPrev();
}
}
// other code
}
Of course, you have to proof your other code, if it works. I hope that I could help you.
I have the below program to reverse elements in a singly linked list. I can't get it to work. I have used simple swapping of variables technique to swap the nodes but when I print, it doesn't go beyond the first node.
public static void reverseLinkedList(Node head) {
Node current = head;
Node temp = null;
while (current != null && current.next != null) {
temp = current;
current = current.next;
current.next = temp;
}
}
public static void printData(Node head) {
Node currentNode = head;
while (true) {
System.out.println(currentNode.data);
if (currentNode.next != null) {
currentNode = currentNode.next;
} else {
break;
}
}
}
I prefer to return the head node after the function. Keeps thing simple
Node reverse(Node node)
{
Node prev = null;
Node current = node;
Node next = null;
while (current != null) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
node = prev;
return node;
}
Alternatively you can opt for the simpler recursive version
Node reverse(Node head) {
if(head == null) {
return head;
}
if(head.next == null) {
return head;
}
Node newHeadNode = reverse(head.next);
head.next.next = head;
head.next = null;
return newHeadNode;
}
You are assigning the next of the current variable to itself which is wrong. You can do like below.
public void reverseLL(Node head) {
Node currentNode = head, prevLink = null, nextNode = null;
while (currentNode != null) {
nextNode = currentNode.next;
currentNode.next = prevLink;
prevLink = currentNode;
currentNode = nextNode;
}
head = prevLink;
}
In your algorithm the first two nodes of the list creates a loop after the first iteration of the while loop.It's better to use the below algorithm.
public static void reverseLinkedList(Node head) {
Node current = head;
Node prev = head;
Node next = head.next;
while (current != null && current.next != null) {
current=next;
next=current.next;
current.next=prev;
prev=current;
}
head=current;
}
For the below code, I would like to know why the size of the linked list keeps giving me a null pointer exeption and why my pushEnd method to push a new node at the end doesnt work, it add an element after a few nodes and gets rid of rest.
class Node {
int data;
Node next;
Node(int data){
this.data = data;
}
}
public class LinkedList {
Node head;
/* Inserts a new Node at front of the list. */
public Node push(int data)
{
Node newNode = new Node(data);
newNode.next = head;
return head = newNode;
}
public Node pushEnd(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
}
newNode.next = null;
while(head != null) {
head = head.next;
head.next = newNode;
return newNode;
}
return head;
}
public int getSize() {
int size = 0;
while(this.head != null) {
size++;
head = head.next;
}
return size;
}
public void printList() {
while (this.head !=null) {
System.out.print(head.data + "-->");
head = head.next;
}
System.out.println(head);
}
}
public class Tester {
public static void main(String[] args) {
LinkedList ll = new LinkedList();
ll.push(35);
ll.push(100);
ll.push(14);
ll.push(44);
ll.push(10);
ll.push(8);
System.out.println("Created Linked list is:");
ll.printList();
System.out.println(ll.getSize());
}
}
I want to figure out the size of the linked list and be able to add nodes at the end.
Your while loops modify the head variable directly. This causes your other code to fail because now head is pointing to the last node in the list.
Create a new local variable for use in the while loops (instead of modifying head directly). That should fix it!
You are changing head reference, due to which you are getting incorrect output. You should make temp refer to head, do your operation using temp which will not affect head. It should be like below:
public class LinkedList {
Node head;
/* Inserts a new Node at front of the list. */
public void push(int data) {
Node newNode = new Node(data);
newNode.next = head;
head = newNode;
}
public void pushEnd(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
newNode.next = null;
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
public int getSize() {
int size = 0;
Node temp = head;
while (temp != null) {
size++;
temp = temp.next;
}
return size;
}
public void printList() {
Node temp = this.head;
while (temp != null) {
System.out.print(temp.data + "-->");
temp = temp.next;
}
System.out.println(temp);
}
}
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
}
}
Here is a implementation of LinkedList algorithm. Algorithm inserts node at beginner, after a given node, or at the end of list.
package LinkedList;
class LinkedList {
Node Head;
class Node {
int data;
Node Next;
public Node(int d) {
data = d;
Next = null;
}
}
public void insert(int value) {
if (Head ==null) {
Head = new Node(value);
return;
}
Node new_node = new Node(value);
new_node.Next = Head;
Head = new_node;
}
public void display() {
Node a = Head;
while (a != null) {
System.out.println("value:" + a.data);
a = a.Next;
}
}
public void insertMiddle(int valueToInsert, Node prev_node) {
if (Head == null) {
System.out.println("Cant put value after last node");
}
Node new_node = new Node(valueToInsert);
new_node.Next = prev_node.Next;
prev_node.Next = new_node;
}
public void last(int value){
Node new_node = new Node(value);
if(Head == null){
Head = new Node(value);
return;
}
new_node.Next = null;
Node last = Head;
while(last != null){
last = last.Next ;
}
last = new_node;
return;
}
}
public class LinkedList_Insertion {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList list = new LinkedList();
list.insert(8);
list.insert(20);
list.insert(0);
list.insertMiddle(999, list.Head.Next);
list.display();
System.out.println("--------------");
list.last(10000);
list.display();
}
}
In the above code, While using method insert:
public void insert(int value) {
if(Head ==null){
Head = new Node(value);
return;
}
Node new_node = new Node(value);
new_node.Next = Head;
Head = new_node;
}
why don't we use Head.next = new_node;
Similarly, for method :
public void last(int value){
Node new_node = new Node(value);
if(Head == null){
Head = new Node(value);
return;
}
new_node.Next = null;
Node last = Head;
while(last != null){
last = last.Next ;
}
last = new_node;
return;
}
why don't we use last.next = new_node;?
I often end up doing same mistake again and again. If someone can clear this concept, I will be grateful.
Looking forward to your response!
Head case:
You can have Head->node1->node2->node3->...->lastNode
If you do Head.next = newNode, then node1->node2->node3->...->lastNode will be lost.
If you had a doubly-linked list, you could do Head.prev = newNode; Head = Head.prev (prev means previous).
Last case:
This code:
public void last(int value){
Node new_node = new Node(value);
if(Head == null){
Head = new Node(value);
return;
}
new_node.Next = null;
Node last = Head;
while(last != null){
last = last.Next ;
}
last = new_node;
return;
}
looks weird, the condition should actually be while (last.next != null), but even then you are not inserting, you first get a reference to the element that is last in your list, then you make that reference point to another object, it should actually be last.next = newNode, you are right.
Implementing linked lists is a good way to understand how java references work, keep practicing and also try to implement a doubly-linked list.
Your Second Code seems to be wrong, You are right it has to be last.next = newNode
now answering your 1st question consider 3 nos in linked list 100(head),200,300.
here head node with value 100 points to next node with value 200 which must in turn point to the node with value 300. Now let us suppose you want to insert 50 before 100, so when you do
Head.next = new_node;
The node with value 100 is made to point to next node with value 50, so now we have 100,50 in the linked list with the head as 100 still which is wrong
so we do
new_node.Next = Head;
Head = new_node;
In this case linked list becomes 50,100,200,300.
Thus we do it this way.
I have to implement a singly linked list for my project and I'm having trouble getting the remove method to work. I have searched on here for answers but I can't find any that incorporate the tail reference. My project needs to have a head and tail reference in the list and needs to be updated wherever necessary. This is my class and the remove method:
public class BasicLinkedList<T> implements Iterable<T> {
public int size;
protected class Node {
protected T data;
protected Node next;
protected Node(T data) {
this.data = data;
next = null;
}
}
protected Node head;
protected Node tail;
public BasicLinkedList() {
head = tail = null;
}
public BasicLinkedList<T> addToEnd(T data) {
Node n = new Node(data);
Node curr = head;
//Check to see if the list is empty
if (head == null) {
head = n;
tail = head;
} else {
while (curr.next != null) {
curr = curr.next;
}
curr.next = n;
tail = n;
}
size++;
return this;
}
public BasicLinkedList<T> addToFront(T data) {
Node n = new Node(data);
if(head == null){
head = n;
tail = n;
}
n.next = head;
head = n;
size++;
return this;
}
public T getFirst() {
if (head == null) {
return null;
}
return head.data;
}
public T getLast() {
if(tail == null){
return null;
}
return tail.data;
}
public int getSize() {
return size;
}
public T retrieveFirstElement() {
// Check to see if the list is empty
if (head == null) {
return null;
}
Node firstElement = head;
Node curr = head.next;
head = curr;
size--;
return firstElement.data;
}
public T retrieveLastElement() {
Node curr = head;
Node prev = head;
// Check to see if the list is empty
if (head == null) {
return null;
} else {
// If there's only one element in the list
if (head.next == null) {
curr = head;
head = null;
} else {
while (curr.next != null) {
prev = curr;
curr = curr.next;
}
tail = prev;
tail.next = null;
}
}
size--;
return curr.data;
}
public void remove(T targetData, Comparator<T> comparator) {
Node prev = null, curr = head;
while (curr != null) {
if (comparator.compare(curr.data, targetData) == 0) {
//Check to see if we need to remove the very first element
if (curr == head) {
head = head.next;
curr = head;
}
//Check to see if we need to remove the last element, in which case update the tail
else if(curr == tail){
curr = null;
tail = prev;
prev.next = null;
}
//If anywhere else in the list
else {
prev.next = curr.next;
curr = curr.next;
}
size--;
} else {
prev = curr;
curr = curr.next;
}
}
}
public Iterator<T> iterator() {
return new Iterator<T>() {
Node current = head;
#Override
public boolean hasNext() {
return current != null;
}
#Override
public T next() {
if(hasNext()){
T data = current.data;
current = current.next;
return data;
}
return null;
}
#Override
public void remove(){
throw new UnsupportedOperationException("Remove not implemented.");
}
};
}
}
I have went through many iterations of this method and each time I either lose the head reference, the tail reference or I don't remove the element and I am stumped trying to figure it out. For reference here is the test I'm running on it. I don't even fail the test, it just says failure trace.
public void testRemove(){
BasicLinkedList<String> basicList = new BasicLinkedList<String>();
basicList.addToEnd("Blue");
basicList.addToEnd("Red");
basicList.addToEnd("Magenta");
//Blue -> Red -> Magenta -> null
basicList.remove("Red", String.CASE_INSENSITIVE_ORDER);
//Blue -> Magenta -> null
assertTrue(basicList.getFirst().equals("Blue"));
//getLast() returns the tail node
assertTrue(basicList.getLast().equals("Magenta"));
}
EDIT: Forgot to mention that the remove method should be removing all instances of the target data from the list.
I see only 1 bug. If your list is initially empty the following method will cause a loop where you have one node whose next refers to itself:
public BasicLinkedList<T> addToFront(T data) {
Node n = new Node(data);
// The list was empty so this if is true
if(head == null){
head = n;
tail = n;
}
n.next = head;
// now head == n and n.next == head == n so you've got a circle
head = n;
size++;
return this;
}
You can fix this like so:
public BasicLinkedList<T> addToFront(T data) {
Node n = new Node(data);
if(head == null){
tail = n;
}
n.next = head;
head = n;
size++;
return this;
}