Reputation: 25
Okay, so I am a intro programmer to java and we were assigned a project to create a functioning linked list. I am posting my DLinkedlist file to show how I created my linked list. Finally I will show the tester that is being used to make sure it is functioning properly. The exception is fine, that is what is wanted by the instructor. The problem is the "While has next" and "While has previous" outputs. Much thanks!
package project5;
import java.util.NoSuchElementException;
public class DLinkedList {
private Node first;
private Node last;
public DLinkedList() {
first = null;
last = null;
}
/**
* Adds an element to the head of the list
* @param data - the object to store at the head of the list
*/
public void addFirst(Object data){
Node newNode = new Node();
newNode.data = data; // No setter necessary
if (first != null){
newNode.next = first;
}else{
last = newNode;
}
first = newNode;
}
/**
* Gets what is stored at the beginning of the list
* @return - the data stored at the head of the list
*/
public Object getFirst(){
/*
This is the syntax for getting the "data attribute" of the object called "first"
We can do this because "data" is piublic and thus we do not need to call a getter method
*/
if (first == null){
throw new NoSuchElementException();
}
return first.data;
}
/**
* Removes the head of the list
* @return - returns data that was stored in the same node removed
*/
public Object removeFirst(){
if (first == null){
throw new NoSuchElementException();
}
Object temp = first.data;
first = first.next;
return temp;
}
/**
* Adds an element to the tail of the list
* @param data - the object to store at the tail of the list
*/
public void addLast(Object data){
Node newNode = new Node();
newNode.data = data;
if(first == null){
addFirst(data);
}else{
if (last != null){
newNode.previous = last;
last.next = newNode;
}
last = newNode;
}
}
/**
* Gets what is stored at the end of the list
* @return - the data stored at the tail of the list
*/
public Object getLast(){
/*
Ths s
*/
if (last == null){
throw new NoSuchElementException();
}
return last.data;
}
/**
* Removes the last item in the list
* @return
*/
public Object removeLast(){
if (last == null){
throw new NoSuchElementException();
}
Object temp = last.data;
last = last.previous;
return temp;
}
/**
* Checks if the Linked List contains an object
* @param other
* @return
*/
public boolean contains(Object other){
Node temp = first;
while (temp.next != null){
if(temp.data == other){
return true;
}else{
temp = temp.next;
}
}
return false;
}
/**
* Note: We return ListIterator because it is a PUBLIC interface that can be used outside fo the LinkedList class,
* whereas LinkedListIterator only exists inside LinkedList
* @return
*/
public ListIterator listIterator(){
return new LinkedListIterator();
}
class LinkedListIterator implements ListIterator{
private DLinkedList.Node position;
private DLinkedList.Node previous;
private DLinkedList.Node next;
private boolean isAfterNext;
private boolean isAfterPrevious;
public LinkedListIterator(){
position = null;
previous = null;
next = null;
isAfterNext = false;
isAfterPrevious = false;
}
@Override
public Object next() {
if (!hasNext()){
throw new NoSuchElementException();
}
// Updating previous to be at the current pos
previous = position;
// Iterator is at the beginning of the lsit
if (position == null){
position = first;
}
else{
position = position.next;
}
isAfterNext = true;
return position.data;
}
@Override
public boolean hasNext() {
if (position == null){
// Beginning of the list
return first != null;
}
else{
return position.next != null;
}
}
@Override
public void add(Object data) {
if (!isAfterNext){
throw new IllegalStateException();
}
if (position == first){
addFirst(data);
}
else{
Node newNode = new Node();
newNode.data = data;
newNode.next = position.next;
newNode.previous = position;
position.next = newNode;
position = newNode;
}
}
@Override
public Object remove() {
if (!isAfterNext){
throw new IllegalStateException();
}
Object temp;
if (position == first){
temp = removeFirst();
}
else{
temp = position.data;
previous.next = position.next;
}
position = previous;
isAfterNext = false;
return temp;
}
@Override
public Object previous() {
boolean hasBeenCalled = false;
if (!hasPrevious()){
throw new NoSuchElementException();
}
// Updating next to be at the current pos
next = position;
// Iterator is at the end of the list
if (position == null){
position = last;
}
else{
position = position.previous;
}
isAfterPrevious = true;
return position.next.data;
}
@Override
public boolean hasPrevious() {
if (position == null){
// End of the list
return first != null;
}
else{
return position.previous != null;
}
}
@Override
public void set(Object element) {
position.data = element;
}
}
/*
Node is an inner class, which means access to it is restruced to members of its outer class, i.e. LinkedList
*/
class Node{
/*
These variables don't need setters or getters because they are public, and thus can be accessed/modified by any
member of the outer class, i.e. LinkedList
*/
public Object data;
public Node next;
public Node previous;
}
}
Tester shown with expected vs actual output!
package project5;
import project5.DLinkedList;
import project5.ListIterator;
public class DLinkedListTester {
public static void main(String[] args) {
DLinkedList ages = new DLinkedList();
for(int i = 1; i <= 15; i++) {
ages.addFirst(i);
}
for(int i = 16; i <= 30; i++) {
ages.addLast(i);
}
System.out.println("Remove First Expected: 15");
System.out.println("Output: "+ages.removeFirst() + "\n");
System.out.println("Remove Last Expected: 30");
System.out.println("Output: "+ages.removeLast() + "\n");
System.out.println("Get First Expected: 14");
System.out.println("Output: "+ages.getFirst() + "\n");
System.out.println("Get Last Expected: 29");
System.out.println("Output: "+ages.getLast() + "\n");
System.out.println("Contains 10 Expected: true");
System.out.println("Output: " + ages.contains(10) + "\n");
System.out.println("Contains 100 Expected: false");
System.out.println("Output: " + ages.contains("100") + "\n");
ListIterator iter = ages.listIterator();
System.out.print("While has next Expected: 14 13 12 11 10 9 8 7 6 5 4 3 2 1 16 17 18 19 20 21 22 23 24 25 26 27 28 29 \nOutput: ");
while(iter.hasNext()) {
System.out.print(iter.next() + " ");
}
System.out.println("\n");
System.out.print("While has previous Expected: 29 28 27 26 25 24 23 22 21 20 19 18 17 16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 \nOutput: ");
while(iter.hasPrevious()) {
System.out.print(iter.previous() + " ");
}
iter = ages.listIterator();
iter.next(); //14 | 13 12 11 10 ...
iter.next(); //14 13 | 12 11 10 ...
iter.add("12.5"); //14 13 12.5 | 12 11 10 ...
iter.next(); //14 13 12.5 12 | 11 10 ...
System.out.println("\n\nRemove Expected: 12");
System.out.println("Output: " + iter.remove() + "\n");
iter.previous(); //14 13 | 12.5 11 10 ...
iter.previous(); //14 | 13 12.5 11 10 ...
iter.remove(); //14 | 12.5 11 10 ...
while(iter.hasNext()) {
iter.next();
}
iter.previous();
iter.set("100");
System.out.print("\nWhile has next Expected: 14 12.5 11 10 9 8 7 6 5 4 3 2 1 16 17 18 19 20 21 22 23 24 25 26 27 28 100 \nOutput: ");
iter = ages.listIterator();
while(iter.hasNext()) {
System.out.print(iter.next() + " ");
}
}
}
Console Output!
Remove First Expected: 15
Output: 15
Remove Last Expected: 30
Output: 30
Get First Expected: 14
Output: 14
Get Last Expected: 29
Output: 29
Contains 10 Expected: true
Output: true
Contains 100 Expected: false
Output: false
While has next Expected: 14 13 12 11 10 9 8 7 6 5 4 3 2 1 16 17 18 19 20 21
22 23 24 25 26 27 28 29
Output: 14 13 12 11 10 9 8 7 6 5 4 3 2 1 16 17 18 19 20 21 22 23 24 25 26 27
28 29 30
While has previous Expected: 29 28 27 26 25 24 23 22 21 20 19 18 17 16 1 2 3
4 5 6 7 8 9 10 11 12 13 14
Output: 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Remove Expected: 12
Output: 12
Exception in thread "main" java.util.NoSuchElementException
at project5.DLinkedList$LinkedListIterator.previous(DLinkedList.java:224)
at project5.DLinkedListTester.main(DLinkedListTester.java:59)
Upvotes: 0
Views: 293
Reputation: 3544
If you carefully look at your code and the way your linked list is populated, you would notice that (right after the population) the elements from 15
(first element) up to 1
are singly-linked while next elements from 16
up to 30
are doubly-linked (there's a double-link between 1
and 16
as well).
Regarding "while has next":
Whenever you remove the last element, you simply update last
pointer to the previous element, but the last element still remains in the linked list, hence you get 30
at the end of value list. iterator's loop stops at values prev=29
and position=30
Regarding "while has previous":
Because the previous pointers are all null
starting from element 1
and all way up to the first
, you update position
by position = position.previous;
so it starts pointing at 29
, then you output position.next
which is 30
, then traverse up one by one and naturally stop at position=1
then you output position.next
which is 16
and stop, because the previous pointer of 1
does not point at 2
So,
1.You have to modify addFirst()
in such a way that the previous
pointer of a first node would point to the new one:
public void addFirst(Object data){
Node newNode = new Node();
newNode.data = data; // No setter necessary
if (first != null){
newNode.next = first;
first.previous = newNode; //<---added
}else{
last = newNode;
}
first = newNode;
}
2.You have to modify removeLast()
in such a way that the removed element no longer stays in the list:
public Object removeLast(){
if (last == null){
throw new NoSuchElementException();
}
Node temp = last;
last = last.previous;
last.next = null;
temp.previous = null;
return temp.data;
}
Upvotes: 1