I'm currently trying to create a DoublyLinked list that uses tail recursion.
I have my addItem fully working. My InsertItem successfully inserts and item at the specified index. However it removes whatever item was there and doesn't move all the data along. My code also crashes when trying to add at index 1. I have commented out the code I attempted to get this working.
Here is my Node class:
public class DLLNode
{
private DLLNode previous;
public DLLNode next;
private String value;
public DLLNode(String value)
{
this.value = value;
this.previous = previous;
this.next = next;
}
public DLLNode(String value, DLLNode next, DLLNode previous)
{
this.value = value;
this.next = next;
this.previous = previous;
}
public String GetDataItem()
{
return value;
}
public void setDataItem()
{
this.value = value;
}
public DLLNode GetPreviousNode()
{
return previous;
}
public void setPrevious(DLLNode previous)
{
this.previous = previous;
}
public DLLNode GetNextNode()
{
return next;
}
public void setNextNode(DLLNode next)
{
this.next = next;
}
public void addItem(String value) {
if(this.next == null) {
DLLNode newNode = new DLLNode(value);
this.next = newNode;
} else {
this.next.addItem(value);
}
}
public void InsertItemHelper(String value, int indexToInsert, int current, DLLNode currNode)
{
/*if (indexToInsert == 1)
{
DLLNode newNode = new DLLNode(value);
currNode.setNextNode(newNode);
}*/
if (current == indexToInsert-2)
{
DLLNode newNode = new DLLNode(value);
currNode.setNextNode(currNode.GetNextNode().GetNextNode());
newNode.setNextNode(currNode.GetNextNode());
currNode.setNextNode(newNode);
newNode.setPrevious(currNode);
}
else
{
InsertItemHelper(value, indexToInsert, current+1, currNode.GetNextNode());
}
}
public void DeleteItemHelper(int indexToDelete, int current, DLLNode currNode)
{
if (current == indexToDelete-2)
{
currNode.setNextNode(currNode.GetNextNode().GetNextNode());
}
else
{
DeleteItemHelper(indexToDelete, current+1, currNode.GetNextNode());
}
}
}
And here is my DoublyLinkedList class. Any help and tips much appreciated.
public class DoublyLinkedList
{
private int noOfItems;
private DLLNode head;
private DLLNode tail;
// Default constructor
public DoublyLinkedList()
{
head = null;
tail = null;
this.noOfItems = 0;
}
public int GetNoOfItems()
{
return noOfItems;
}
/* Returns the String value held at index (base zero) or null if the index
* is out of bounds */
public String GetItemByIndex(int index)
{
return null;
}
public DLLNode GetNodeByIndex(int index)
{
return null;
}
public void AddItem(String value)
{
if (head == null)
{
DLLNode newNode = new DLLNode(value);
head = newNode;
noOfItems++;
}
else
{
head.addItem(value);
noOfItems++;
}
}
public void InsertItem(int index, String value)
{
if (index > noOfItems)
{
AddItem(value);
}
else {
head.InsertItemHelper(value, index, 0, head);
noOfItems++;
}
}
public void DeleteItem(int index)
{
if (index ==0)
{
System.out.println("Out of Bounds");
}
if (index > noOfItems)
{
System.out.println("Out of Bounds");
}
if (head == null)
{
System.out.println("No Item to remove");
}
else if (index == 1)
{
head = head.GetNextNode();
noOfItems--;
}
else
{
head.DeleteItemHelper(index, 0, head);
noOfItems--;
}
}
public int getNoOfItems()
{
return this.noOfItems;
}
public boolean isEmpty()
{
return (head == null);
}
}
Think about what's going on here:
currNode.setNextNode(currNode.GetNextNode().GetNextNode());
newNode.setNextNode(currNode.GetNextNode());
currNode.setNextNode(newNode);
newNode.setPrevious(currNode);
Analysis of your snippet
let A:= currnode; B:=currnode.getNextNode(); C:=currnode.getNextNode();
So we have something like A -> B -> C
currNode.setNextNode(currNode.GetNextNode().GetNextNode());
A ->C
newNode.setNextNode(currNode.GetNextNode());
newNode -> C
currNode.setNextNode(newNode);
A -> newNode -> C
newNode.setPrevious(currNode);
set backlink from newNode to A
What you probably want to do
newNode.setNextNode(currNode.getNextNode());
newNode -> B
now we can change the link from currNode to the newNode
currNode.setNextNode(newNode);
A -> newNode
So now you should have something like A -> newNode -> B. No need to ever touch C.
So now you can fix the backlinks and you're done.
currNode.getNextNode().setPrevious(newNode);
set backlink from B to newNode
newNode.setPrevious(currNode);
set backlink from newNode to currNode
p.s.: I didn't test this. I didn't look into the if-conditions themselves, I didn't think about your indexToInsert ==1-case, etc.. still I hope to have given you an idea where the mistake is coming from and pointed you in the right direction...
p.p.s.: It is considered good practice to stick to the standard java naming conventions - method-names should start with lowercase letters.
Related
I'm making the implementation of the Linked-List data structure and I'm looking foward to implement a remove method of all the occurrences of an element using recursion, here's a piece of my code:
public class MyLinkedList<T> {
private Node<T> head;
private Node<T> last;
private int length;
public void remove(T elem) {
if (!(this.isContained(elem)) || this.isEmpty())
return;
else {
if (head.value.equals(elem)) {
head = head.next;
length--;
remove(elem);
} else {
// This is a constructor which requieres a head and last, and a length
new MyLinkedList<>(head.next, last, length-1).remove(elem);
}
}
}
}
I do understand the problem, I'm working with copies of a list not with the original, so, how could I merge or make this sub to the original list?
If I had to do it with recursion, I think it would look something like this:
public void remove(T elem)
{
removeHelper(null, this.head, elem);
}
private void removeHelper(Node<T> prev, Node<T> head, T elem)
{
if (head != null) {
if (head.value.equals(elem)) {
if (head == this.head) {
this.head = head.next;
} else {
prev.next = head.next;
}
if (this.last == head) {
this.last = prev;
}
--this.length;
} else {
prev = head;
}
removeHelper(prev, head.next, elem);
}
}
For the record, if I didn't have to use recursion, I'd do it linearly like this:
private void remove(T elem)
{
Node<T> prev = null;
Node<T> curr = this.head;
while (curr != null) {
if (curr.value.equals(elem)) {
if (this.last == curr) {
this.last = prev;
}
if (prev == null) {
this.head = curr.next;
} else {
prev.next = curr.next;
}
--this.length;
} else {
prev = curr;
}
curr = curr.next;
}
}
I would suggest doing this in a separate static function instead of doing it in the actual node class since you are recursing through the entire linked list.
public void removeAllOccurences(Node<T> head, Node<T> prev, T elem) {
if (head == null) {
return;
}
if (head.value.equals(elem)) {
Node<T> temp = head.next;
if (prev != null) {
prev.next = temp;
}
head.next = null; // The GC will do the rest.
removeAllOccurences(temp, prev, elem);
} else {
removeAllOccurences(head.next, head, elem);
}
}
I am learning java and i am still a beginner.i have written this code to implement a circular linked list and it keeps printing the numbers when i try to print the list. it looks like some kind of an infinite loop maybe. I even tried to use a debug but it didn't do much for me. I would very much appreciate it if you could review the code and see why this is happening. here is the code below. I would be also for giving me feedback on the code :)
this is the class for the circular linked list
public class CircularLinkedList<E> implements API<E> {
private Node<E> head;
private int size = 0;
public void placeAtBeginning(E element) {
Node<E> newNode = new Node<E>(element);
if(head == null) {
head = newNode;
head.setNext(head);
}else {
Node<E> temp = head;
head = newNode;
newNode.setNext(temp);
}
size++;
}
public void placeAtEnd(E element) {
Node<E> newNode = new Node<E>(element);
if (head == null) {
head = newNode;
}else {
Node<E> temp = head;
while (temp.getNext() != head) {
temp = temp.getNext();
}
temp.setNext(newNode);
}
newNode.setNext(head);
size++;
}
public void deleteFromBeginning() {
Node<E> temp = head;
while (temp.getNext() != head) {
temp = temp.getNext();
}
temp.setNext(head.getNext());
head = head.getNext();
size --;
}
public void deleteFromEnd() {
Node<E> temp = head;
while(temp.getNext().getNext() != head) {
temp = temp.getNext();
}
temp.setNext(head);
size--;
}
public void print() {
Node<E> temp = head;
while(temp.getNext()!= head) {
System.out.print(temp.getValue() + " , ");
temp = temp.getNext();
}
System.out.print(temp.getValue());
}
}
this is the class for my node
public class Node<T> {
private Node<T> next;
private T item;
public Node(T item) {
this.item = item;
}
public void setNext(Node<T> next) {
this.next = next;
}
public Node<T> getNext() {
return this.next;
}
public T getValue() {
return this.item;
}
}
this is my main where i tried to test it using int.
public class Main {
public static void main(String [] args) {
API <Integer> list = new CircularLinkedList<Integer>();
int a = 10;
int b = 3;
int c = 15;
int d = 8;
int f = 9;
list.placeAtBeginning(a);
list.placeAtEnd(b);
list.print();
System.out.println();
list.placeAtBeginning(c);
list.placeAtBeginning(d);
list.print();
}
}
this is my API which I used
public interface API <E> {
public void placeAtBeginning(E element);
public void placeAtEnd(E element);
public void deleteFromBeginning();
public void deleteFromEnd();
public void print();
}
Your method placeAtBeginning() doesn't insert the new element in the circular list but simply lets the next of the new element refer to the original circular list.
Try this:
public void placeAtBeginning(E element)
{
Node<E> newNode = new Node<E>(element);
if(head == null)
{
head = newNode;
head.setNext(head);
}
else
{
Node<E> last = head;
while (last.getNext() != head)
last = last.getNext();
newNode.setNext(head);
head = newNode;
last.setNext(head);
}
size++;
}
I didn't check the other methods. They might contain a similar error.
I am currently working on creating a DoublyLinkedList which uses tail recursion.
I have managed to get all my methods fully working except my insert item.
It works for inserting at any Index other than 0. I have tried to write an if statement which deals with this and my code still runs however although it increments the noOfItems. It never adds the item to my list.
Could the issue be with my toString? Or am I missing something in my if case?
This is my DLLNode class:
public class DLLNode
{
private DLLNode previous;
public DLLNode next;
private String value;
public DLLNode(String value)
{
this.value = value;
this.previous = previous;
this.next = next;
}
public DLLNode(String value, DLLNode next, DLLNode previous)
{
this.value = value;
this.next = next;
this.previous = previous;
}
public String GetDataItem()
{
return value;
}
public void setDataItem()
{
this.value = value;
}
public DLLNode GetPreviousNode()
{
return previous;
}
public void setPrevious(DLLNode previous)
{
this.previous = previous;
}
public DLLNode GetNextNode()
{
return next;
}
public void setNextNode(DLLNode next)
{
this.next = next;
}
public void addItem(String value) {
if(this.next == null) {
DLLNode newNode = new DLLNode(value);
this.next = newNode;
} else {
this.next.addItem(value);
}
}
public void InsertItemHelper(String value, int indexToInsert, int current, DLLNode currNode)
{
if (indexToInsert == 0)
{
DLLNode newNode = new DLLNode(value);
currNode.GetNextNode().setPrevious(newNode);
}
else if (current == indexToInsert-1)
{
DLLNode newNode = new DLLNode(value);
newNode.setNextNode(currNode.GetNextNode());
currNode.setNextNode(newNode);
currNode.GetNextNode().setPrevious(newNode);
newNode.setPrevious(currNode);
}
else
{
InsertItemHelper(value, indexToInsert, current+1, currNode.GetNextNode());
}
}
public void DeleteItemHelper(int indexToDelete, int current, DLLNode currNode)
{
if (current == indexToDelete-1)
{
currNode.setNextNode(currNode.GetNextNode().GetNextNode());
}
else
{
DeleteItemHelper(indexToDelete, current+1, currNode.GetNextNode());
}
}
}
And this is my DoublyLinkedList class:
public class DoublyLinkedList
{
private int noOfItems;
private DLLNode head;
private DLLNode tail;
// Default constructor
public DoublyLinkedList()
{
head = null;
tail = null;
this.noOfItems = 0;
}
public int GetNoOfItems()
{
return noOfItems;
}
public String GetItemByIndex(int index)
{
int count = 0;
while (count < index)
{
head = head.GetNextNode();
count++;
}
return head.GetDataItem();
}
public DLLNode GetNodeByIndex(int index)
{
int count = 0;
while (count < index)
{
head = head.GetNextNode();
count++;
}
return head;
}
public void AddItem(String value)
{
if (head == null)
{
DLLNode newNode = new DLLNode(value);
head = newNode;
noOfItems++;
}
else
{
head.addItem(value);
noOfItems++;
}
}
public void InsertItem(int index, String value)
{
if (index > noOfItems)
{
AddItem(value);
}
else {
head.InsertItemHelper(value, index, 0, head);
noOfItems++;
}
}
public void DeleteItem(int index)
{
if (index ==0)
{
System.out.println("Out of Bounds");
}
if (index > noOfItems)
{
System.out.println("Out of Bounds");
}
if (head == null)
{
System.out.println("No Item to remove");
}
else if (index == 1)
{
head = head.GetNextNode();
noOfItems--;
}
else
{
head.DeleteItemHelper(index, 0, head);
noOfItems--;
}
}
public int getNoOfItems()
{
return this.noOfItems;
}
public boolean isEmpty()
{
return (head == null);
}
public String toString()
{
DLLNode currentNode = head;
StringBuilder sb = new StringBuilder();
while (currentNode != null) {
sb.append(currentNode.GetDataItem());
if (currentNode.GetNextNode() != null)
{
sb.append(",");
}
currentNode = currentNode.GetNextNode();
}
return sb.toString();
}
}
I have added the following code into my insert item:
if (index ==0)
{
DLLNode newNode = new DLLNode(value);
head.setNextNode(head);
// newNode.next= head.GetNextNode();
head = newNode;
noOfItems++;
}
If I include the commented out line I get an error to do with string builder.
With the line commented out it adds in the linked list at position 0, but doesn't add any of the rest. It does however increment noOfItems correctly.
The following error is what appears:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415)
at java.lang.StringBuilder.append(StringBuilder.java:132)
at ads2.DoublyLinkedList.toString(DoublyLinkedList.java:155)
at java.lang.String.valueOf(String.java:2847)
at java.lang.StringBuilder.append(StringBuilder.java:128)
at ads2.Main.printList(Main.java:62)
at ads2.Main.main(Main.java:38)
Java Result: 1
BUILD SUCCESSFUL (total time: 1 second)
If you need any more details on the error please let me know.
You need to update the head when adding at position 0
Because you don't update the head, the old head is still linked in the list object, and it's next() returns what should be in the new list object index 1, so you end up with the same list
You could confirm this by confirming
list.getNodeByIndex(0) != list.getNodeByIndex(1).previousNode();
I'm trying to delete odd values in a linked list. My function is called removeOdds. What am I messing up? I am calling cur.next within that if statement. Shouldn't that do the trick?
Here is my code:
public class SLinkedList {
public void editAtIndex(int index, int newElement) {
if (index < 0 || index >= size) {
return;
} else {
Node cur = head;
while (index > 0) {
cur = cur.next;
index--;
}
cur.setElement(newElement);
}
}
public static void main(String[] args) {
Node test = new Node(5);
test.setElement(5);
SLinkedList myList = new SLinkedList();
//System.out.println(myList.contains(5));
myList.addFirst(5);
myList.addFirst(7);
myList.addFirst(9);
myList.addLast(27);
myList.addLast(3);
myList.addLast(453);
myList.addLast(32);
myList.addLast(83);
myList.addLast(43);
myList.addLast(10);
myList.removeOdds();
myList.printList();
//myList.printList();
}
private Node head, tail, nextNode;
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
private int size;
public SLinkedList() {
}
public int size() {
int value = 0;
Node temp = head;
while (temp != null) {
temp = temp.next;
value++;
}
return value;
}
public void addFirst(int element) {
head = new Node(element, head);
size++;
if (size == 1) {
tail = head;
}
}
public void addLast(int element) {
Node last = new Node(element);
if (size == 0) {
head = last;
tail = last;
} else {
tail.setNext(last);
tail = last;
}
size++;
}
public void removeFirst() {
if (size == 0) {
return;
}
head = head.getNext();
size--;
if (size == 0) {
tail = null;
}
}
public void removeLast() {
if (size <= 1) {
head = null;
tail = null;
size = 0;
} else {
Node cur = head;
while (cur.next != tail) {
cur = cur.next;
}
tail = cur;
size--;
tail.next = null;
}
}
public void removeOdds() {
if (size <= 1) {
return;
} else {
Node cur = head;
while (cur.next != tail) {
cur = cur.next;
if (cur.getElement() % 2 != 0) {
size--;
cur = cur.next;
}
}
}
}
public boolean contains(int key) {
Node cur = head;
while (cur != null && cur.getElement() != key) {
cur = cur.next;
}
if (cur == null) {
return false;
}
return true;
}
public int indexOf(int key) {
Node cur = head;
int index = 0;
while (cur != null) {
if (cur.getElement() == key) {
return index;
}
cur = cur.next;
index++;
}
return -1;
}
public void printList() {
System.out.println("A list of size " + size);
Node temp = head;
while (temp != null) {
System.out.print(temp.getElement() + " ");
temp = temp.next;
}
System.out.println();
}
public Node getHead() {
return head;
}
public void setHead(Node head) {
this.head = head;
}
public Node getTail() {
return tail;
}
public void setTail(Node tail) {
this.tail = tail;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
private static class Node {
private int element;
private Node next;
public Node(int element) {
this.element = element;
}
public Node(int element, Node next) {
this.element = element;
this.next = next;
}
public Node() {
element = 0;
}
public int getElement() {
return element;
}
public void setElement(int element) {
this.element = element;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}
cur = cur.next; simply replaces the cur variable with the next node. That doesn't mean the earlier variable is deleted. The reference is still held.
You need to hold a reference to the node before the node you wish to delete.
public void removeOdds() {
if (size <= 1) {
return;
} else {
Node cur = head;
Node previous = cur;
while (cur.next != tail) {
cur = cur.next;
if (cur.getElement() % 2 != 0) {
size--;
previous.next = cur.next;
} else {
previous = previous.next;
}
}
}
}
This will ensure the nodes get deleted. I haven't checked the complete code, but it looks like right now you're not handling the head & tail nodes. They'll be skipped. You might want to handle those nodes too in the method.
I want to write implementation of Deque
I have written code below but unfortunately I have a problem with it
when I use addFirst and addLast or even removeFirst every thing is ok
but when I use removelast the programs throws NullPointerException
I dont know what is the problem exactly so I got really confused
Can Anyone plaese Help me??
Thanks in advance for your attention
Node Class::
public class Node<E>{
E element;
Node<E> prev , next;
public Node(E element, Node<E> prev, Node<E> next) {
this.element = element;
this.prev = prev;
this.next = next;
}
public Node() {
this(null, null, null);
}
public void setNext(Node next)
{
this.next = next;
}
public void setPrev(Node prev)
{
this.prev = prev;
}
public Node getNext()
{
return next;
}
public Node getPrev()
{
return prev;
}
}
here is Deque Interface::
public interface DQ<E> {
public int size();
public boolean isEmpty();
public E getFirst();
public E getLast();
public void addFirst (E element);
public void addLast (E element);
public E removeFirst();
public E removeLast();
}
and finally here is MyDQ Class which implements DQ class::
public class MyDQ<E> implements DQ<E>{
Node<E> head , tail;
int size = 0;
#Override
public int size() {
return size;
}
#Override
public boolean isEmpty() {
return size == 0;
}
#Override
public E getFirst() {
if(head == null)
return null;
return head.element;
}
#Override
public E getLast() {
if(head == null)
return null;
return tail.element;
}
#Override
public void addFirst(E element) {
Node<E> n = new Node<>(element, null, null);
if(head == null)
head = tail = n;
else
{
head.setPrev(n);
n.setNext(head);
head = n;
}
size++;
}
#Override
public void addLast(E element) {
Node<E> n = new Node<>(element, null, null);
if(head == null)
head = tail = n;
else
{
tail.setNext(n);
n.setPrev(head);
tail = n;
}
size++;
}
#Override
public E removeFirst() {
if(head == null)
return null;
Node<E> n = head;
head = head.getNext();
head.setPrev(null);
n.setNext(null);
size --;
return n.element;
}
#Override
public E removeLast() {
if(head == null)
return null;
Node<E> n = tail;
tail = tail.getPrev();
tail.setNext(null);
n.setPrev(null);
size --;
return n.element;
}
}
I created a simple Person object to use:
public class Person {
String name;
Integer age;
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
}
I tested this using the following unit test:
#Test
public void testOneElementDeque() {
MyDQ<Person> deq = new MyDQ<>();
Person p1 = new Person("John", 12);
Person p2 = new Person("Eric", 45);
deq.addLast(p1);
assertEquals(p1, deq.getLast());
assertEquals(p1, deq.getFirst());
deq.removeLast();
}
This throws a null pointer at this line(line 78):
tail.setNext(null);
By this point in the call tail has been set to null by this line:
tail = tail.getPrev();
To correct this I rewrote the implementaion to null check tail at this point:
public E removeLast() {
if(tail == null)
return null;
Node<E> n = tail;
tail = tail.getPrev();
if(tail != null)
tail.setNext(null);
n.setPrev(null);
size --;
return n.element;
}