Why is my doubly linked list removing previous links? - java

I Know this topic has been beat to death but I'm really struggling with implementing these two add methods to a linked list. addFirst and addLast both work when called by themselves but when I call addFirst("foo") and addLast("bar") the add last removes anything previously added to the list. add first is supposed to add an item to the beginning of the list, and add last is supposed to append it to the end.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Deque<Item> implements Iterable<Item> {
private int N;
private Node first;
private Node last;
//create linked list
private class Node
{
String item;
Node next;
Node previous;
}
public Deque() // construct an empty deque
{
N = 2;
first = new Node();
last = new Node();
//link together first and last node;
first.next = last;
last.previous = first;
last.item = "Last";
first.item = "First";
}
public boolean isEmpty() // is the deque empty?
{
return first == null;
}
public int size() // return the number of items on the deque
{
return N;
}
public void addFirst(Item item) // insert the item at the front
{
Node nextElement = new Node();
nextElement.item = (String)item;
nextElement.next = first.next;
nextElement.previous = first;
first.next = nextElement;
N++;
}
public void addLast(Item item) // insert the item at the end
{
Node newLast = new Node();
newLast.item = (String)item;
newLast.next = last;
newLast.previous = last.previous;
last.previous.next = newLast;
last.previous = newLast;
N++;
}
public void printList()
{
Node print = first;
for (int i = 0; i < N; i++)
{
System.out.print(print.item);
print = print.next;
}
System.out.println("");
}

Seems like you're getting yourself confused. Generally, if your doing something.next.next or similar, a warning should go off in your head. You'd also be well served to provide a constructor that could take the item instead of the addition statement in the method.
public void addLast(Item item) // insert the item at the end
{
Node newLast = new Node();
newLast.item = (String)item;
if (isEmpty()) {
first = newLast;
} else {
last.next = newLast;
newLast.previous = last;
}
last = newLast;
N++;
}
As far as addFirst is concerned, so you don't inadvertently get bad advice, it would go something like this...
public void addFirst(Item item) {
Node newFirst = new Node();
newFirst.item = (String)item;
if (isEmpty()) {
last = newFirst;
} else {
first.previous = newFirst;
}
newFirst.next = first;
first = newFirst;
N++;
}

The addfirst method is missing updating one of the pointers
public void addFirst(Item item) // insert the item at the front
{
Node nextElement = new Node();
nextElement.item = (String)item;
nextElement.next = first.next;
nextElement.previous = first;
first.next.previous = nextElement; //ADDED HERE
first.next = nextElement;
N++;
}

I think this question is answered with one simple link - you're re-inventing the wheel which is always a bad idea, no matter what educational purposes your goals serve.
Use the Deque interface.

Related

Determine the Object (book) that appears first alphabetically

I was tasked with creating my own linked list class, using a book class i made. One of the questions was to Determine the book that appears first alphabetically.
i was able to sort the Linked list alphabetically using bubble sort(i know its not efficient but im still new) here is the code.
public void alphaBubbleSort() {
int size = size();
if (size > 1) {
boolean wasChanged;
do {
Node current = head;
Node previous = null;
Node next = head.next;
wasChanged = false;
while (next != null) {
if (current.book.getName().compareToIgnoreCase(next.book.getName()) > 0) {
wasChanged = true;
if (previous != null) {
Node sig = next.next;
previous.next = next;
next.next = current;
current.next = sig;
} else {
Node temp = next.next;
head = next;
next.next = current;
current.next = temp;
}
previous = next;
next = current.next;
} else {
previous = current;
current = next;
next = next.next;
}
}
} while (wasChanged);
}
}
my problem is i only want the front node and i do not want to alter the linked list order. i tried to do this in my main.
Linky tempLinky = new Linky(); // create temp linked list
tempLinky = linky; // copy temp main linked list to temp
tempLinky.alphaBubbleSort(); // sort temp list
System.out.println(tempLinky.peek());// return object in first node
This did not seem to work. Ive tried some other code that does not work, so ive come here as a last resort.
If you need to find the first book alphabetically, there's no need to sort the entire list (and, as you commented, you don't want to alter the list's order anyway).
Instead, you could iterate over the list and keep the "first" object as you go:
public Book getFirstAlphabetically() {
Node current = head;
Book retVal = head.book;
while (current != null) {
if (current.book.getName().compareToIgnoreCase(retVal.getName()) < 0) {
retVal = current.book;
}
current = current.next;
}
return retVal;
}
Here's an example:
import java.util.Random;
class Book {
String title;
Book(String title){this.title = title;}
}
class Node {
Book b; Node next;
Node(Book b){this.b = b;}
}
public class Main {
static Book least(Node head){
if (head == null) return null;
Book least = head.b;
for(Node n=head.next; n.next!=null; n=n.next)
least = least.title.compareTo(n.b.title) > 0 ? n.b : least;
return least;
}
static void print(Node head){
for(Node n=head; n.next!=null; n=n.next)
System.out.println(n.b.title);
}
static String randString(){
Random r = new Random();
int len = r.nextInt(20)+1;
char[] chars = new char[len];
for(int i=0; i<chars.length; i++)
chars[i]= (char) (r.nextInt(26)+97);
return new String(chars);
}
public static void main(String[] args) {
Node head = new Node(new Book(randString()));
Node next = head;
for(int i = 0; i<20; i++)
next = next.next = new Node(new Book(randString()));
print(head);
System.out.println("==========");
System.out.println(least(head).title);
}
}

Linked list is only displaying the head node, not sure why

I am doing a linked list project for my class at school. Essentially we are supposed to make a linked list from scratch, and have add, delete, and find commands. No matter how hard I've been trying I cannot seem to get the list to display anything other than the head node. here are my classes starting from node
public class main {
public static void main(String args[]) {
for (int i = 0; i < 3; i++) {
LinkedList list = new LinkedList();
Node focus = new Node();
String start;
start = JOptionPane.showInputDialog("Enter 'A' to add an item"
+ "\n" + "Enter 'D' to delete an item\nEnter 'F' to find an item.");
if (start.equals("a") || start.equals("A")) {
focus.data = JOptionPane.showInputDialog("enter an item to ADD");
list.Add(focus);
while (focus != null) {
focus = list.head;
focus = focus.next;
JOptionPane.showMessageDialog(null, "your list is\n" + focus.getData());
}
}
}
}
}
public class Node {
String data;
Node next;
Node prev;
public Node(String data, Node next) {
this.data = data;
this.next = next;
}
Node() {
}
public void setData(String data) {
this.data = data;
}
public String getData() {
return this.data;
}
public void setNext(Node next) {//setnext
this.next = next;
}
public Node getNext() {
return next;
}
}
public class LinkedList extends Node {
Node head;
int listcount = 0;
public LinkedList() {
this.prev = null;
this.next = null;
this.listcount = 0;
}
LinkedList(Node Set) {
}
public void Add(Node n) {
Node current = this.prev;
if (current != null) {
current = this.prev;
this.prev = new Node();
} else {
head = this.prev = new Node();
current = head;
}
listcount++;
}
}
I think my biggest problem is the "your list is" part. I can't seem to get it to display anything other than the head node. I would really appreciate the help, as this has been giving me a huge headache. :)
First of all, why does your LinkedList extends the Node class? It's a linked list not a node. There's nothing coming before and after the linked list. So the linked list has no prev and next. All the elements are added in the list and the elements are inserted after the head node. The head of the node has a prev and a next. In the Add method, if the head of the list is null (i.e, the list is empty), the new element becomes the head of the list. Otherwise, the new node is inserted after the head.
public class LinkedList {
Node head;
int listcount = 0;
public LinkedList() {
this.head = null;
this.listcount = 0;
}
public void Add(Node n) {
Node current = this.head;
if (current == null) {
head = n;
} else {
Node prev = null;
while (current != null) {
prev = current;
current = current.next;
}
prev.next = n;
}
listcount++;
}
public String toString() {
StringBuilder builder = new StringBuilder();
Node current = this.head;
while (current != null) {
builder.append(current.data).append(", ");
current = current.next;
}
return builder.toString();
}
}
I added a toString method which loops over the list and builds a string with the content from each node.
In the main method there are a few problems. The linked list is initialised only once not every time you select a choice. If you initialise the linked list every time you select something, then the linked list will always be reinitialised and the only node that will contain will be the head node after you add the new element.
public class main {
public static void main(String args[]) {
String start;
boolean finished=false;
LinkedList list = new LinkedList();
while(!finished) {
start = JOptionPane.showInputDialog("Enter 'A' to add an item"
+ "\n" + "Enter 'D' to delete an item\nEnter 'F' to find an item.");
if (start.equals("a") || start.equals("A")) {
Node focus = new Node();
focus.data = JOptionPane.showInputDialog("enter an item to ADD");
list.Add(focus);
JOptionPane.showMessageDialog(null, "your list is\n" + list.toString());
}
else {
finished = true;
}
}
}
}
Try to go over the code and understand what is happening and why. Also use pencil and paper to understand the logic.

Java Using Nodes with LinkedList

I've been working through some standard coding interview questions from a book I recently bought, and I came across the following question and answer:
Implement an algorithm to find the nth to last element in a linked list.
Here's the provided answer:
public static LinkedListNode findNtoLast(LinkedListNode head, int n) { //changing LinkedListNode to ListNode<String>
if(head == null || n < 1) {
return null;
}
LinkedListNode p1 = head;
LinkedListNode p2 = head;
for(int j = 0; j < n-1; ++j) {
if(p2 == null) {
return null;
}
p2 = p2.next;
}
if(p2 == null) {
return null;
}
while(p2.next != null) {
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
I understand the algorithm, how it works, and why the book lists this as its answer, but I'm confused about how to access the LinkedListNodes to send as an argument to the method. I know that I'd have to create a LinkedListNode class (since Java doesn't already have one), but I can't seem to figure out how to do that. It's frustrating because I feel like I should know how to do this. Here's something that I've been working on. I'd greatly appreciate any clarification. You can expand/comment on my code or offer your own alternatives. Thanks.
class ListNode<E> {
ListNode<E> next;
E data;
public ListNode(E value) {
data = value;
next = null;
}
public ListNode(E value, ListNode<E> n) {
data = value;
next = n;
}
public void setNext(ListNode<E> n) {
next = n;
}
}
public class MyLinkedList<E> extends LinkedList {
LinkedList<ListNode<E>> list;
ListNode<E> head;
ListNode<E> tail;
ListNode<E> current;
ListNode<E> prev;
public MyLinkedList() {
list = null;
head = null;
tail = null;
current = null;
prev = null;
}
public MyLinkedList(LinkedList<E> paramList) {
list = (LinkedList<ListNode<E>>) paramList; //or maybe create a loop assigning each ListNode a value and next ptr
head = list.getFirst();
tail = list.getLast(); //will need to update tail every time add new node
current = null;
prev = null;
}
public void addNode(E value) {
super.add(value);
//ListNode<E> temp = tail;
current = new ListNode<E>(value);
tail.setNext(current);
tail = current;
}
public LinkedList<ListNode<E>> getList() {
return list;
}
public ListNode<E> getHead() {
return head;
}
public ListNode<E> getTail() {
return tail;
}
public ListNode<E> getCurrent() {
return current;
}
public ListNode<E> getPrev() {
return prev;
}
}
How can the LinkedListNode head from a LinkedList?
Update: I think part of my confusion comes from what to put in the main method. Do I need to create a LinkedList of ListNode? If I do that, how would I connect the ListNodes to each other? How would I connect them without using a LinkedList collection object? If someone could show me how they would code the main method, I think that would put things into enough perspective for me to solve my issues. Here's my latest attempt at the main method:
public static void main(String args[]) {
LinkedList<ListNode<String>> list = new LinkedList<ListNode<String>>();
//MyLinkedList<ListNode<String>> list = new MyLinkedList(linkedList);
list.add(new ListNode<String>("Jeff"));
list.add(new ListNode<String>("Brian"));
list.add(new ListNode<String>("Negin"));
list.add(new ListNode<String>("Alex"));
list.add(new ListNode<String>("Alaina"));
int n = 3;
//ListIterator<String> itr1 = list.listIterator();
//ListIterator<String> itr2 = list.listIterator();
LinkedListNode<String> head = new LinkedListNode(list.getFirst(), null);
//String result = findNtoLast(itr1, itr2, n);
//System.out.println("The " + n + "th to the last value: " + result);
//LinkedListNode<String> nth = findNtoLast(list.getFirst(), n);
ListNode<String> nth = findNtoLast(list.getFirst(), n);
System.out.println("The " + n + "th to the last value: " + nth);
}
In an attempt to connect the nodes without using a custom linked list class, I have edited my ListNode class to the following:
class ListNode<E> {
ListNode<E> next;
ListNode<E> prev; //only used for linking nodes in singly linked list
ListNode<E> current; //also only used for linking nodes in singly linked list
E data;
private static int size = 0;
public ListNode() {
data = null;
next = null;
current = null;
if(size > 0) { //changed from prev != null because no code to make prev not null
prev.setNext(this);
}
size++;
}
public ListNode(E value) {
data = value;
next = null;
current = this;
System.out.println("current is " + current);
if(size > 0) {
prev.setNext(current);//this line causing npe
}
else
{
prev = current;
System.out.println("prev now set to " + prev);
}
size++;
System.out.println("after constructor, size is " + size);
}
public ListNode(E value, ListNode<E> n) {
data = value;
next = n;
current = this;
if(size > 0) {
prev.setNext(this);
}
size++;
}
public void setNext(ListNode<E> n) {
next = n;
}
}
As is right now, the program will run until it reaches prev.setNext(current); in the single argument constructor for ListNode. Neither current nor prev are null at the time this line is reached. Any advice would be greatly appreciated. Thanks.
You don't actually need a separate LinkedList class; the ListNode class is a linked list. Or, to state it differently, a reference to the head of the list is a reference to the list.
The use of head, tail, current, prev in the sample code you posted has come from a double-linked list which is a data type that has links in both directions. This is more efficient for certain types of applications (such as finding the nth last item).
So I would recommend renaming your ListNode class to LinkedList and renaming next to tail.
To add a new item to the list you need a method that creates a new list with the new item at it's head. Here is an example:
class LinkedList<E> {
...
private LinkedList(E value, LinkedList<E> tail) {
this.data = value;
this.tail = tail;
}
public LinkedList<E> prependItem(E item) {
return new LinkedList(item, this);
}
}
Then to add a new item i to list you use list = list.prependItem(i);
If for some reason you need to always add the items to the end, then:
private LinkedList(E value) {
this.data = value;
this.tail = null;
}
public void appendItem(E item) {
LinkedList<E> list = this;
while (list.tail != null)
list = list.tail;
list.tail = new LinkedList<>(item);
}
However this is obviously pretty inefficient for long lists. If you need to do this then either use a different data structure or just reverse the list when you have finished adding to it.
Incidentally, an interesting side effect of this is that a reference to any item in the list is a reference to a linked list. This makes recursion very easy. For example, here's a recursive solution for finding the length of a list:
public int getLength(LinkedList list) {
if (list == null) {
return 0;
} else {
return 1 + getLength(list.getTail());
}
}
And using this a simple (but very inefficient!) solution to the problem you provided - I've renamed the method to make its function more obvious:
public LinkedList getTailOfListOfLengthN(LinkedList list, int n) {
int length = getLength(list);
if (length < n) {
return null;
} else if (length == n) {
return list;
} else {
return getTailOfLengthN(list.getTail(), n);
}
}
And to reverse the list:
public LinkedList<E> reverse() {
if (tail == null) {
return this;
} else {
LinkedList<E> list = reverse(tail);
tail.tail = this;
tail = null;
return list;
}
}
As I hope you can see this makes the methods a lot more elegant than separating the node list classes.
Actually you have created a linked list with you class ListNode.
A linked list is made of a node and a reference to another linked list (see the recursion?).

NullPointerException while implementing Queue using Linked List

I am following Coursera Algorithm 1 course, and right now implementing Queues using linked list, but getting a NullPointerException. Please help me out.
package algo_packages;
public class QueueLinkedList {
private Node first, last;
public class Node{
String item;
Node next;
}
public QueueLinkedList(){
first = null;
last = null;
}
public boolean isEmpty(){
return first == last;
}
public void enqueue(String item){
Node oldLast = last;
last = new Node();
last.item = item;
last.next = null;
if(isEmpty()){
first = last;
}
else {
oldLast.next = last;
}
}
public String dequeue(){
String item = first.item;
first = first.next;
if (isEmpty()) last = null;
return item;
}
}
I am getting the exception at:
oldLast.next = last;
oldLast.next caused the NullPointerException when I tried to debug the program.
The first time you enqueue an item isEmpty() returns false, since it checks if first==last, but first is still null and last is no longer null (since you already assigned the new Node to it). This brings you to access oldLast.next when oldLast is null, hence the NullPointerException.
A possible fix :
public void enqueue(String item)
{
Node oldLast = last;
Node newNode = new Node();
newNode.item = item;
newNode.next = null;
if(isEmpty()) { // last is not assigned yet, so isEmpty returns correct result
last = newNode;
first = last;
} else {
last = newNode;
oldLast.next = last;
}
}
When you check isEmpty() it always returns false for enqueue because you are setting last to a new Node() which will never equal first. You don't need to check if list isEmpty() because if list is empty then first == last so you don't need to assign first = last because they are already equal. Try this:
public void enqueue(String item){
Node oldLast = last;
last = new Node();
last.item = item;
last.next = null;
if(oldLast != null)
{
oldLast.next = last;
}
else
{
first = last;
}
}

exception with java data structure

I am writing a generic data structure that can add and delete from the first or last nodes
I tested my code however I got exceptions in some certain way of input.
now if I addlast then addfirst then removelast i got exception
and when I addfirst many time without adding last then try to remove them by removelast() function i got exception
but when I addlast many time without adding first then remove them by removefirst() it works
I am trying to avoid while loops here is the code
import java.util.Iterator;
public class Deque <Item> implements Iterable <Item> {
private Node first,last;
private class Node
{
Item item;
Node next;
Node prev;
}
public Deque()
{
first = null;
last = null;
}
public boolean IsEmpty()
{
return first == null;
}
public void addFirst(Item item)
{
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
first.prev = null;
if (last == null)
{
last = first;
}
}
public void addlast(Item item)
{
Node oldlast = last;
last = new Node();
last.item = item;
last.next = null;
if (first == null)
{
first = last;
}
else
{
last.prev = oldlast;
oldlast.next = last;
}
}
public Item removeFirst()
{
Item x = first.item;
first = first.next;
if (IsEmpty())
last = null;
return x;
}
public Item removeLast()
{
if (first == last)
return removeFirst();
Item x = last.item;
last = last.prev;
last.next = null;
if (IsEmpty())
first = null;
return x;
}
public Iterator<Item> iterator ()
{
return new ListIterator();
}
private class ListIterator implements Iterator<Item>
{
private Node current = first;
public boolean hasNext ()
{
return current != null;
}
public void remove()
{
//NOt Supported
}
public Item next()
{
Item x = current.item;
current = current.next;
return x;
}
}
}
I believe I have something wrong with last.prev in removelast() since it is already null and then referred last = last.perv in remove()
but i couldnt think of a way to link last to last node of first
can anyone help me with this
here is the main if you want to try...
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Deque<Integer> o = new Deque<Integer>();
int num = 0;
while (true)
{
StdOut.println("enter 1 to addfirst, 2 addlast, 3 removefirst, 4 removelast, " +
"5 to exit");
num = StdIn.readInt();
if (num == 5)
break;
switch (num)
{
case 1:
StdOut.println("enter number to add first");
int x = StdIn.readInt();
o.addFirst(x);
break;
case 2:
StdOut.println("enter number to add last");
int y = StdIn.readInt();
o.addlast(y);
break;
case 3:
int w=o.removeFirst();
StdOut.print("the deleted number is: ");
StdOut.print(w);
StdOut.println();
break;
case 4:
int z=o.removeLast();
StdOut.print("the deleted number is: ");
StdOut.print(z);
StdOut.println();
break;
default:
StdOut.println("Stick with the range!");
break;
}
for (Iterator<Integer> i=o.iterator(); i.hasNext();)
{
StdOut.print(i.next());
StdOut.print(" ");
}
StdOut.println();
}
}
}
You have missed a couple of operations. In addFirst you don't set oldFirst.prev = first;, so if you add nodes with it, you won't have any prev references defined. That is why removeLast fails. It attempts to clean traverse to last.prev, but since everything was added with addFirst, last.prev is null.
Also, in removeFirst, you have a similar issue, that you don't remove the link to the former prev node, such as first.prev = null; Without doing that, if you were traversing using prev references, you would be able to move beyond the first node, after having called removeFirst.
addLast and addFirst should do, in essence, exactly the same things, just at different ends of the list. addFirst looks simpler, in your implementation, which means either you missed something in addFirst, or addLast is overly complex. In this case, you missed something in addFirst. Same with the remove methods.

Categories

Resources