While I am studying Liang's book I am stuck at a point and I don't understand what is going on. The cause of error is the constructor of MyArrayList class. The author warns us about not calling super(object), but they didn't explain the reason. Now when I try and run the code the author is right - when we call super(object) I get an error. What is the cause of this error?
MyArrayList.java
public class MyArrayList<E> extends MyAbstractList<E> {
public static final int INITIAL_CAPACITY = 16;
private E[] data = (E[])new Object[INITIAL_CAPACITY];
/** Create a default list */
public MyArrayList() {
}
/** Create a list from an array of objects */
public MyArrayList(E[] objects) {
/*for (int i = 0; i < objects.length; i++)
add(objects[i]); // Warning: don't use super(objects)! */
super(objects); //!!! AUTHOR WARNS US ABOUT NOT INVOKING THIS LINE !!!
}
/** Add a new element at the specified index in this list */
public void add(int index, E e) {
ensureCapacity();
// Move the elements to the right after the specified index
for (int i = size - 1; i >= index; i--)
data[i + 1] = data[i];
// Insert new element to data[index]
data[index] = e;
// Increase size by 1
size++;
}
/** Create a new larger array, double the current size */
private void ensureCapacity() {
if (size >= data.length) {
E[] newData = (E[])(new Object[size * 2 + 1]);
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
}
/** Clear the list */
public void clear() {
data = (E[])new Object[INITIAL_CAPACITY];
size = 0;
}
/** Return true if this list contains the element */
public boolean contains(E e) {
for (int i = 0; i < size; i++)
if (e.equals(data[i])) return true;
return false;
}
/** Return the element from this list at the specified index */
public E get(int index) {
return data[index];
}
/** Return the index of the first matching element in this list.
* Return -1 if no match. */
public int indexOf(E e) {
for (int i = 0; i < size; i++)
if (e.equals(data[i])) return i;
return -1;
}
/** Return the index of the last matching element in this list
* Return -1 if no match. */
public int lastIndexOf(E e) {
for (int i = size - 1; i >= 0; i--)
if (e.equals(data[i])) return i;
return -1;
}
/** Remove the element at the specified position in this list
* Shift any subsequent elements to the left.
* Return the element that was removed from the list. */
public E remove(int index) {
E e = data[index];
// Shift data to the left
for (int j = index; j < size - 1; j++)
data[j] = data[j + 1];
data[size - 1] = null; // This element is now null
// Decrement size
size--;
return e;
}
/** Replace the element at the specified position in this list
* with the specified element. */
public E set(int index, E e) {
E old = data[index];
data[index] = e;
return old;
}
/** Override toString() to return elements in the list */
public String toString() {
StringBuilder result = new StringBuilder("[");
for (int i = 0; i < size; i++) {
result.append(data[i]);
if (i < size - 1) result.append(", ");
}
return result.toString() + "]";
}
/** Trims the capacity to current size */
public void trimToSize() {
if (size != data.length) { // If size == capacity, no need to trim
E[] newData = (E[])(new Object[size]);
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
}
}
MyList.java
public interface MyList<E> {
/** Add a new element at the end of this list */
public void add(E e);
/** Add a new element at the specified index in this list */
public void add(int index, E e);
/** Clear the list */
public void clear();
/** Return true if this list contains the element */
public boolean contains(E e);
/** Return the element from this list at the specified index */
public E get(int index);
/** Return the index of the first matching element in this list.
* Return -1 if no match. */
public int indexOf(E e);
/** Return true if this list contains no elements */
public boolean isEmpty();
/** Return the index of the last matching element in this list
* Return -1 if no match. */
public int lastIndexOf(E e);
/** Remove the first occurrence of the element o from this list.
* Shift any subsequent elements to the left.
* Return true if the element is removed. */
public boolean remove(E e);
/** Remove the element at the specified position in this list
* Shift any subsequent elements to the left.
* Return the element that was removed from the list. */
public E remove(int index);
/** Replace the element at the specified position in this list
* with the specified element and returns the new set. */
public Object set(int index, E e);
/** Return the number of elements in this list */
public int size();
}
MyAbstractList.java
public abstract class MyAbstractList<E> implements MyList<E> {
protected int size = 0; // The size of the list
/** Create a default list */
protected MyAbstractList() {
}
/** Create a list from an array of objects */
protected MyAbstractList(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
/** Add a new element at the end of this list */
public void add(E e) {
add(size, e);
}
/** Return true if this list contains no elements */
public boolean isEmpty() {
return size == 0;
}
/** Return the number of elements in this list */
public int size() {
return size;
}
/** Remove the first occurrence of the element o from this list.
* Shift any subsequent elements to the left.
* Return true if the element is removed. */
public boolean remove(E e) {
if (indexOf(e) >= 0) {
remove(indexOf(e));
return true;
}
else
return false;
}
}
TestMyArrayList.java
public class TestMyArrayList {
public static void main(String[] args)
{
String[] str = {"manisa","turkey","germany"};
MyList<String> list = new MyArrayList<String>(str);
list.add("America");
list.add(0,"Canada");
list.add(1,"England");
System.out.println(list);
}
}
Here is the error code :
Exception in thread "main" java.lang.NullPointerException
at MyArrayList.ensureCapacity(MyArrayList.java:36)
at MyArrayList.add(MyArrayList.java:21)
at MyAbstractList.add(MyAbstractList.java:16)
at MyAbstractList.<init>(MyAbstractList.java:11)
at MyArrayList.<init>(MyArrayList.java:16)
at TestMyArrayList.main(TestMyArrayList.java:8)
Lets simplify your code to the bare essentials:
public abstract class MyAbstractList<E> {
protected int size = 0; // The size of the list
protected MyAbstractList() {}
protected MyAbstractList(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
public class MyArrayList<E> extends MyAbstractList<E> {
public static final int INITIAL_CAPACITY = 16;
private E[] data = (E[])new Object[INITIAL_CAPACITY];
public MyArrayList(E[] objects) {
super(objects); // this call to super() executes before data is initialized
}
}
public static void main(String[] args) {
String[] str = {"manisa","turkey","germany"};
MyList<String> list = new MyArrayList<String>(str);
}
The important thing to understand is that the parent class' constructor is called before the child class is even initialized (which is why super() always has to be the first call in a constructor), meaning when MyAbstractList's constructor is running, data is still null.
Replacing the super() call with its contents means the for loop is executed while MyArrayList is initializing, after data has been properly set.
In essence, the problem is that MyAbstractList provides a constructor that calls methods that will be overridden by a child class, which is a serious anti-pattern. MyAbstractList should not provide an add-all style constructor.
For more, see Effective Java Item 17, which notes:
Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.
The problem here is that the constructor in MyAbstractList is calling add before data has been initialized.
The data field is declared and initialized in the MyArrayList class. But the initialization doesn't occur until after the superclass initialization has finished, and the add calls are made during the superclass initialization ... when data is still null.
The general problem here is that it is dangerous for a constructor to call a method that could be overridden by a subclass. The override method is liable to be called before the subclass initialization has occurred.
In this case, add(E) could be overridden. Worse still, add(E) calls add(E, int) which definitely is overridden, because it is abstract in the superclass.
Related
I am trying to implement the set method where you pass in the position in a linked list that you want and the value and the set function adds that value into the position specified in the linked list. I have implemented the set function but for some reason The last element disappears in my implementation. I would greatly appreciate any help. Thanks in advance. I would appreciate any expert eyes that will see what I am missing.
/**
* A basic singly linked list implementation.
*/
public class SinglyLinkedList<E> implements Cloneable, Iterable<E>, List<E> {
//---------------- nested Node class ----------------
/**
* Node of a singly linked list, which stores a reference to its
* element and to the subsequent node in the list (or null if this
* is the last node).
*/
private static class Node<E> {
E value;
Node<E> next;
public Node(E e)
{
value = e;
next = null;
}
}
//----------- end of nested Node class -----------
// instance variables of the SinglyLinkedList
private Node<E> head = null; // head node of the list (or null if empty)
private int size = 0; // number of nodes in the list
public SinglyLinkedList() {
} // constructs an initially empty list
// access methods
/**
* Returns the number of elements in the linked list.
*
* #return number of elements in the linked list
*/
public int size() {
return size;
}
/**
* Adds an element to the end of the list.
*
* #param e the new element to add
*/
public void addLast(E e) {
// TODO
}
/**
* Tests whether the linked list is empty.
*
* #return true if the linked list is empty, false otherwise
*/
public boolean isEmpty() {
return size == 0;
}
#Override
public E get(int i) throws IndexOutOfBoundsException {
Node<E> a = head;
if(i<=this.size()) {
int count = 0;
while(count < i) {
count ++;
a = a.next;
}
return a.value;
}
return null;
}
#Override
public E set(int i, E e) throws IndexOutOfBoundsException {
Node<E> current = head;
Node<E> setNode = new Node<E>(e);
if(i==0) {
this.addFirst(e);
}
else if(i==this.size){
this.addLast(e);
}
else {
for(int j=0; current != null && j < (i-1);j++) {
current = current.next;
}
Node<E> temp = current.next;
current.next = setNode;
setNode.next = temp;
}
return setNode.value;
}
// update methods
/**
* Adds an element to the front of the list.
*
* #param e the new element to add
*/
public void addFirst(E e) {
Node<E> first = new Node<>(e);
first.next = this.head;
this.head = first;
this.size++;
}
#SuppressWarnings({"unchecked"})
public boolean equals(Object o) {
// TODO
return false; // if we reach this, everything matched successfully
}
#SuppressWarnings({"unchecked"})
public SinglyLinkedList<E> clone() throws CloneNotSupportedException {
// TODO
return null;
}
/**
* Produces a string representation of the contents of the list.
* This exists for debugging purposes only.
* #return
*/
public String toString() {
for(int i=0;i<this.size();i++) {
System.out.println(this.get(i));
}
return "end of Linked List";
}
public static void main(String[] args) {
SinglyLinkedList <Integer> ll =new SinglyLinkedList <Integer>();
ll.addFirst(5);
ll.addFirst(4);
ll.addFirst(3);
ll.addFirst(2);
ll.set(1,0);
System.out.println(ll);
}
}
Assumptions
addLast method is missing in the code
The error could be there too
Known cause
This code is not incrementing the size inside the set method's for loop.The size is incremented in addLast(possibly) and addFirst and not incremented in other case (final else part)
It is not clear what is planned to do with set method. The way it is implemented now, it behaves more like insert, meaning that it will add new node, bit it does not increase the total count of elements (size).
It the set method is changing the value of the node, which name indicates, then this part is wrong:
else {
for(int j=0; current != null && j < (i-1);j++) {
current = current.next;
}
Node<E> temp = current.next;
current.next = setNode;
setNode.next = temp;
}
It should replace the value instead of adding the new one:
else {
for(int j=0; current != null && j < (i-1);j++) {
current = current.next;
}
current.value=e
}
Also, it looks like the index i is 1-based, while everything else is 0 based. I didn't check the code above, but the concept should be like shown.
I have an exercise, where I have to implement a priority queue, using a min-heap.
However I cannot use the PriorityClass library, I have to implement it, by myself.
I've managed to do it by far, but, my professor, told me that my insert methods is wrong. He told me, to create an Element class, which contains 2 attributes of type T.These two attributes are (T element and T priority). How can I edit my insert method?
package priorityQueue;
import java.util.ArrayList;
import java.util.Comparator;
import priorityQueueInterfaces.PriorityQueue;
public class BinaryHeap<T> implements PriorityQueue<T>
{
private int currentSize = 0;
private static final int DEFAULT_CAPACITY = 20;
private ArrayList<T> array = null;
private Comparator <? super T> comparator = null;
/**
* Constructor of binary-heap
*/
public BinaryHeap(Comparator <? super T> comparator)
{
currentSize = 0;
array = new ArrayList<>(DEFAULT_CAPACITY + 1);
this.comparator = comparator;
}
/**
* Construct the binary heap from an arrayList
*/
public BinaryHeap(ArrayList<T> array, Comparator <? super T> comparator)
{
this.currentSize = array.size();
this.array = new ArrayList<>(array.size() + 1);
this.comparator = comparator;
for(int i = 0; i < array.size(); i++)
this.array.set(i + 1, array.get(i));
}
/**
* Method which builds the min heap with the minHeapify method
* #throws PriorityQueueException
*/
public void buildMinHeap(ArrayList<T> array, int heapSize) throws PriorityQueueException
{
for(int i = this.currentSize / 2; i > 0;i--)
minHeapify(this.array,i,this.currentSize);
}
/**
* Method which builds the max heap with the maxHeapify method
* #throws PriorityQueueException
*/
public void buildMaxHeap() throws PriorityQueueException
{
for(int i = this.currentSize/2; i > 0; i--)
maxHeapify(this.array,i,this.currentSize);
}
public void buildMaxHeap(ArrayList<T> array, int heapSize)throws PriorityQueueException
{
if(this.array == null)
throw new NullPointerException("ArrayList is null");
if(this.array.size() <= 0 || heapSize <= 0 )
throw new IllegalArgumentException("Illegal Parameters: either the arraylist or the heap size are not valid");
if(heapSize > this.array.size())
heapSize = this.array.size();
for(int i = heapSize/2; i > 0; i--)
maxHeapify(this.array,i,heapSize);
}
/**
* Insert into the priority queue.
* Duplicates are allowed.
* #param element is the item to insert.
*/
public void insert(T element) throws PriorityQueueException
{
if(element == null)
throw new IllegalArgumentException("Element to be inserted, cannot be null!");
if(this.size() + 1 == this.array.size())
extendArray();
this.currentSize = this.size() + 1;
if(this.isEmpty())
this.array.add(0,element);
else
{
this.array.add(element);
int index = this.size() - 1;//indice index = all'elemento appena aggiunto
while( index > 1 && this.comparator.compare(this.array.get(index/2), this.array.get(index)) < 0)
{
swapElements(index, index/2);
index = index / 2;
}
}
}
/**
* #param firstIndex of the element that has to be swapped
* #param secondIndex of the element that has to be swapped
* #throws PriorityQueueException
*/
private void swapElements(int firstIndex,int secondIndex)throws PriorityQueueException
{
T temp = this.array.get(firstIndex);
this.array.set(firstIndex, this.array.get(secondIndex));
this.array.set(secondIndex,temp);
}
}
THAT'S MY ELEMENT CLASS Which I have to use for adding an element with min-priority
package priorityQueue;
public class Element<T>
{
private T element;
private T priority;
public Element(T element,T priority)
{
this.element = element;
this.priority = priority;
}
public void setElement(T element)
{
this.element = element;
}
public void setPriority(T priority)
{
this.priority = priority;
}
public T getElement()
{
return this.element;
}
public T getPriority()
{
return this.priority;
}
}
My method of insert works just fine, but i have to insert also the priority contained in the class element. How to do it?
I'm sorry if this is a very long code, but the only problem is the remove() method in the LinkedList Class, and I've been struggling on this code for hours and couldn't seem to find a solution. Whenever I input ADD 456 for the main method, instead of printing
0+6+5+4
RESULT 15
I keep on getting
0+6+6+4
RESULT 16
That means either the remove() or insert() method went wrong, but when I checked the input of the insert() method, 5 was properly inserted when it had to. So I was wondering which part of the remove() method went wrong, and how I could solve it. Thanks.
These are the interfaces.
Interface Stack.
package ds.stack;
public interface Stack<E> {
/*
* Removes all of the elements in this stack.
*/
public void clear();
/*
* Pushes an item onto the top of this stack.
*
* #param item
* the item to be pushed onto this stack
*/
public void push(E item);
/**
* Removes the item at the top of this stack and returns that item as the
* value of this method.
*
* #return the item at the top of this stack, or null if this stack is empty
*/
public E pop();
/**
* Returns the number of elements in this stack.
*
* #return the number of elements in this stack
*/
public int length();
/**
* Returns true if this stack contains no elements.
*
* #return true if this stack contains no elements
*/
public boolean isEmpty();
}
Interface List.
package ds.list;
public interface List<E> {
/**
* Removes all of the elements from this list.
*/
public void clear();
/**
* Inserts the specified element at the specified position in this list.
*
* #param pos
* index at which the specified element is to be inserted
* #param item
* element to be inserted
*/
public void insert(int pos, E item);
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* #param pos
* the index of the element to be removed
* #return the element previously at the specified position
*/
public E remove(int pos);
/**
* Returns the number of elements in this list.
*
* #return the number of elements in this list.
*/
public int length();
/**
* Returns the element at the specified position in this list.
*
* #param pos
* index of the element to return
* #return the element at the specified position in this list
*/
public E getValue(int pos);
}
Here is my LinkedList Class
package ds.list;
public class LinkedList<E> implements List<E> {
private E element;
private LinkedList<E> next;
private LinkedList<E> head;
private LinkedList<E> tail;
private LinkedList<E> curr;
public int cnt=0; //length of the list
/*
* constructors below
*/
public LinkedList() { //The very initial constructor
curr = tail = head = this;
}
public LinkedList(LinkedList<E> nextval) { //when you start making more bundles
next = nextval;
}
public void setNext(LinkedList<E> nextval) {
next = nextval;
}
public void goNext() {
curr = next;
} // curr becomes the next bundle
public void setValue(E item) {
element = item;
}
#Override
public void clear() {
tail = head = new LinkedList<E>();
next = null;
cnt = 0;
}
#Override
public void insert(int pos, E item) {
if(pos<0||pos>cnt+1) {
return;
}
if(pos==0) {
curr = head;
head = new LinkedList<E>(curr);
curr = head;
curr.setValue(item);
}
curr = head;
for(int i=0;i<pos-1;i++) {
goNext();
} //curr points right before the index of pos
LinkedList<E> temp = curr.next;
curr.setNext(new LinkedList<E>(temp));
curr.goNext();
curr.setValue(item);
cnt++;
}
#Override
public E remove(int pos) {
if(pos<0||pos>cnt)
return null;
curr = head;
if(cnt==1) {
E it = element;
curr = head = tail = null;
cnt--;
return it;
}
for(int i=0;i<pos-1;i++) {
goNext();
}
E it = next.element;
curr.setNext(next.next);
cnt--;
return it;
}
#Override
public int length() {
return cnt;
}
#Override
public E getValue(int pos) {
if(pos<0||pos>cnt)
return null;
curr = head;
for(int i=0;i<pos-1;i++) {
goNext();
}
return next.element;
}
}
And this is my LinkedStack Class, utilizing the LinkedList Class
package ds.stack;
import ds.list.LinkedList;
public class LinkedStack<E> implements Stack<E> {
private LinkedList<E> stack = new LinkedList<E>();
#Override
public void clear() {
stack.clear();
}
#Override
public void push(E item) {
if(stack.cnt == 0) {
stack.setValue(item);
stack.cnt++;
return;
}
stack.insert(stack.length(),item);
}
#Override
public E pop() {
if(stack.length()==0) {
return null;
}
else {
return stack.remove(stack.length()-1);
}
}
#Override
public int length() {
return stack.length();
}
#Override
public boolean isEmpty() {
if(stack.length()==0)
return true;
return false;
}
}
Then this is my BabyCalculator Class that uses the LinkedStack Class
package ds.test;
import ds.stack.LinkedStack;
import ds.stack.Stack;
public class BabyCalculator {
Stack<Character> stack = new LinkedStack<Character>();
private int value=0;
public int murmurAdd(String polynomial) {
char[] charPol=polynomial.toCharArray();
int count=0;
for(int i=0;i<polynomial.length();i++) {
if(!(Character.isDigit(charPol[i])))
count++;
} // This counts the total number of ( and )s.
int numOf=count/2;
if (numOf==0) {
for(int i=0;i<polynomial.length();i++) {
stack.push(charPol[i]);
}
}
else {
for(int i=0;i<numOf;i++) {
int num1=0, num2 = 0; //will become the index of last ( and first )
for(int j=0;j<polynomial.length();j++) {
if(charPol[j]=='(')
num1 = j;
if(charPol[j]==')') {
num2 = j;
break;
}
}
for(int index=num1+1;index<num2;index++) {
stack.push(charPol[index]);
}
StringBuilder polytemp = new StringBuilder(polynomial);
polynomial=polytemp.replace(num1, num2+1, "").toString();
}
if(polynomial.length()>0) {
charPol = polynomial.toCharArray();
for(int i=0;i<polynomial.length();i++) {
stack.push(charPol[i]);
}
}
}
System.out.print(value);
while(!(stack.isEmpty())) {
Character a = stack.pop();
System.out.println(" a is "+a);
value += Character.getNumericValue(a);
System.out.print("+"+a);
}
System.out.println();
return value;
}
public int getValue() {
// TODO Implement this method
return value;
}
public void setValue(int newValue) {
// TODO Implement this method
value = newValue;
}
}
Finally, the main() method that uses BabyCalculator.
package ds.test;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BabyCalculator babyCalculator = new BabyCalculator();
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String command = sc.next();
if ("ADD".equals(command)) {
String equation = sc.next();
babyCalculator.murmurAdd(equation);
System.out.println("RESULT "+babyCalculator.getValue());
// TODO
} else if ("SHOW".equals(command)) {
System.out.println("VALUE "+babyCalculator.getValue());
// TODO
} else if ("CLEAR".equals(command)) {
babyCalculator.setValue(0);
System.out.println("VALUE CLEARED");
// TODO
} else if ("SET".equals(command)) {
int newValue = sc.nextInt();
babyCalculator.setValue(newValue);
System.out.println("VALUE SET TO "+babyCalculator.getValue());
// TODO
} else if ("EXIT".equals(command)) {
System.out.println("FINAL VALUE "+ babyCalculator.getValue());
return;
// TODO
}
}
sc.close();
}
}
EDIT : When I tried ADD (2345), the result was
0+5+5+5+2
RESULT 17
Which means 5 kept popping out only until it was time for 2 to pop out. Why does this keep happening?I'm assuming it's a deep pointing issue in LinkedList class.
Well, I can say with certainty that your LinkedList is not correctly implemented. You need to do unit testing of your foundational classes before you build on top of them. A basic test involving nothing more than inserting a few elements into position 0 and then trying to get the value of items in positions 0, 1, and 2 fails.
This was a basic test I wrote and it fails with NullPointerException.
LinkedList<String> list = new LinkedList<>();
list.insert(0, "A");
list.insert(0, "B");
list.insert(0, "C");
System.out.println(list.getValue(0));
System.out.println(list.getValue(1));
System.out.println(list.getValue(2));
Add more logging throughout your code, use a debugger, implement toString methods on your classes to help you find the problems.
I can tell you that your LinkedList method getValue does not work as intended. To get my test above to work I had to change from this:
for(int i=0;i<pos-1;i++) {
goNext();
}
return next.element;
to this:
for (int i = 0; i < pos; i++) {
goNext();
}
return curr.element;
The reason is because "next" refers to the next element of whatever LinkedList you called getValue on, not the next element after the current one.
I can also tell you that you have a similar bug in your goNext method of LinkedList:
public void goNext() {
curr = next;
}
should be:
public void goNext() {
curr = curr.next;
}
There are almost certainly more issues with this class, so I highly recommend you thoroughly test and debug it as this will probably solve many of your problems.
I see more issues than one. The insert is wrong, the remove is wrong (you can validate) by calling ADD twice in the same run.
One such issue is in insert I changed your code as below:
//LinkedList<E> temp = curr.next;
//curr.setNext(new LinkedList<E>(temp));
LinkedList<E> temp = new LinkedList<E>(curr.next);
temp.setValue(curr.element);
And removed the loop
for(int i=0;i<pos-1;i++) {
goNext();
}
in remove method Atleast add test works. But you have more problems at hand. I didn't test much of other usecases.
A) Define the following method in MyList and implement it in MyAbstractList.
// Adds the elements in otherList to this list.
// Returns true if
// this list changed as a result of the call.
public boolean addAll(MyList<E> otherlist)
B) Add code to “TestMyArrayList.java” to demonstrate that this method works correctly.
Display the modified list using a java.util.Iterator object and a while loop.
OK so I've already finished the Part A and I'm confused on part B. I don't understand what my professor wants me to do. I've done some stuff in it but I'm pretty sure it's not correct. Anybody knows if I'm even doing it correctly?
This is my MyList class
package listapi;
/**
* #author Y. Daniel Liang
*/
public interface MyList<E> extends java.lang.Iterable<E> {
/** Add a new element at the end of this list*/
public void add(E e);
/**Add a new element at the specified index in this list*/
public void add(int index, E e);
/**Clear the list*/
public void clear();
/**Return true if this list contains the element*/
public boolean contains(E e);
/**Return the element from this list at the specified index*/
public E get(int index);
/**Return the index of the first matching element in this list. Return -1 if
* no match.*/
public int indexOf(E e);
/**Return true if this list contains no elements*/
public boolean isEmpty();
/**Return the index of the last matching element in this list Return -1 if
* no match.*/
public int lastIndexOf(E e);
/**Remove the first occurrence of the element o from this list. Shift any
* subsequent elements to the left. Return true if the element is removed.*/
public boolean remove(E e);
/**Remove the element at the specified position in this list Shift any
* subsequent elements to the left. Return the element that was removed from
* the list.*/
public E remove(int index);
/**Replace the element at the specified position in this list with the
* specified element and returns the new set.*/
public Object set(int index, E e);
/** Return the number of elements in this list */
public int size();
public boolean addAll(MyList<E> otherList);
}
This is my MyAbstractList class
package listapi;
/**
* #author Y. Daniel Liang
*/
public abstract class MyAbstractList<E> implements MyList<E> {
protected int size = 0; // The size of the list
/**
* Create a default list
*/
protected MyAbstractList() {
}
/**
* Create a list from an array of objects
*/
protected MyAbstractList(E[] objects) {
for (int i = 0; i < objects.length; i++) {
add(objects[i]);
}
}
#Override
/**
* Add a new element at the end of this list
*/
public void add(E e) {
add(size, e);
}
#Override
/**
* Return true if this list contains no elements
*/
public boolean isEmpty() {
return size == 0;
}
#Override
/**
* Return the number of elements in this list
*/
public int size() {
return size;
}
#Override
/**
* Remove the first occurrence of the element e from this list. Shift any
* subsequent elements to the left. Return true if the element is removed.
*/
public boolean remove(E e) {
if (indexOf(e) >= 0) {
remove(indexOf(e));
return true;
} else {
return false;
}
}
public boolean addAll(MyList<E> otherList) {
for (E e : otherList) {
add(e);
}
if (otherList.size() > 0)
return true;
return false;
}
}
This is where I need to add code to demonstrate that my addAll method is working correctly by displaying modified list using java.lang.iterator and a while loop
package listapi;
/**
* #author Y. Daniel Liang
*/
public class TestMyArrayList {
public TestMyArrayList() {
// Create a list
MyList<String> list = new MyArrayList<>();
// Add elements to the list
list.add("America"); // Add it to the list
System.out.println("(1) " + list);
list.add(0, "Canada"); // Add it to the beginning of the list
System.out.println("(2) " + list);
list.add("Russia"); // Add it to the end of the list
System.out.println("(3) " + list);
list.add("France"); // Add it to the end of the list
System.out.println("(4) " + list);
list.add(2, "Germany"); // Add it to the list at index 2
System.out.println("(5) " + list);
list.add(5, "Norway"); // Add it to the list at index 5
System.out.println("(6) " + list);
// Remove elements from the list
list.remove("Canada"); // Same as list.remove(0) in this case
System.out.println("(7) " + list);
list.remove(2); // Remove the element at index 2
System.out.println("(8) " + list);
list.remove(list.size() - 1); // Remove the last element
System.out.print("(9) " + list + "\n(10) ");
for (String s : list) {
System.out.print(s.toUpperCase() + " ");
}
Iterator itr = list.iterator();
while(itr.hasNext()){
Object a = itr.next();
System.out.println(a);
}
public static void main(String[] args){
new MyArrayList();
}
}
I've written my own implementations of a Stack and a Queue, but I've made them work specifically for integers. I am well aware of the Java implementations, java.util.Stack and java.util.Queue, but I'm doing this as a learning experience... just want to learn something new. How would I make these generic implementations such that I can store any object in my Stack/Queue, not just integers?
Below is the code, but I also welcome all critique and suggestions on improvements. I would like to know what I've done well and what I haven't done well.
STACK NODE IMPLEMENTATION
public class StackNode {
public Integer value;
public StackNode() {
this.value = null;
}
public StackNode(StackNode node) {
this.value = node.value;
}
public StackNode(Integer data) {
this.value = data;
}
}
STACK IMPLEMENTATION
/**
* Stack Data Structure.
*
* A Stack is a last in, first out (LIFO) data structure. A Stack can have any abstract data type as an element, but is
* characterized by two fundamental operations: push() and pop(). The push() operation adds an element to the top of the Stack,
* hiding any elements already on the Stack, or initializing the Stack if it is empty. The pop() operation removes an element
* from the top of the Stack, and returns this element's value to the caller. Elements are removed from the Stack in the reverse
* order to the order of their addition to the Stack; therefore, lower elements are those that have been on the Stack the
* longest, thus, the first element added to the Stack will be the last one to be removed.
*
* #author Hristo
*/
public class Stack {
private int size;
private int capacity;
private int topNodeIndex;
private Object[] theStack;
/**
* Default Constructor. Initalizes this Stack with initial size = 0 and capacity = 1.
*/
public Stack() {
this.size = 0;
this.capacity = 1;
this.topNodeIndex = -1;
this.theStack = new Object[capacity];
}
/**
* Constructor. Initializes a Stack to have the given capacity.
*
* #param capacity - the capacity of the Stack-to-be
*/
public Stack(int capacity) {
this.size = 0;
this.capacity = capacity;
this.topNodeIndex = -1;
this.theStack = new Object[capacity];
}
/**
* Returns the size of this Stack, i.e., how many elements are in this Stack.
*
* #return int - the size of this Stack
*/
public int size() {
return this.size;
}
/**
* Returns the capacity of this Stack, i.e., the maximum number of elements this Stack can hold.
*
* #return int - the capacity of this Stack
*/
public int capacity() {
return this.capacity;
}
/**
* Returns whether or not this Stack is empty, i.e., size == 0.
*
* #return boolean - true if this Stack is empty, false otherwise
*/
public boolean isEmpty() {
return ((this.topNodeIndex == -1) && (this.size == 0)) ? true : false;
}
/**
* Returns whether or not this Stack is full, i.e., size == capacity.
*
* #return boolean - true if this Stack is full, false otherwise
*/
public boolean isFull() {
return (this.size == this.capacity) ? true : false;
}
/**
* Pushes the given value onto the top of this Stack.
*
* #param value - the data to push
*/
public void push(Integer value) {
if (value == null) {
return;
} else {
if (isFull()) {
resize();
}
insert(value);
return;
}
}
/**
* Removes the top element of this Stack and returns the corresponding value.
*
* #return Integer - the value of the top element of this Stack
*/
public Integer pop() {
if (isEmpty()) {
return null;
} else {
return remove();
}
}
/**
* Returns the top element of this Stack without removing it.
*
* #return Integer - the top element of this Stack
*/
public Integer peek() {
return (isEmpty()) ? null : (((StackNode) theStack[this.topNodeIndex]).value);
}
/**
* Inserts the given value onto this Stack.
*
* #param value - the value to insert
*/
private void insert(Integer value) {
theStack[this.topNodeIndex + 1] = new StackNode(value);
this.topNodeIndex++;
this.size++;
return;
}
/**
* Removes the top element of this Stack and returns the corresponding value.
*/
private Integer remove() {
StackNode topNode = (StackNode) theStack[this.topNodeIndex];
theStack[this.topNodeIndex] = null;
this.topNodeIndex--;
this.size--;
return topNode.value;
}
/**
* Creates an array with double the size of the original and copies over the contents from the original.
*/
private void resize() {
Object[] doubleStack = new Object[this.capacity * 2];
for (int index = 0; index < this.size; index++) {
doubleStack[index] = theStack[index];
}
theStack = doubleStack;
capacity *= 2;
return;
}
}
QUEUE NODE IMPLEMENTATION
public class QueueNode {
public Integer value;
public QueueNode() {
this.value = null;
}
public QueueNode(QueueNode node) {
this.value = node.value;
}
public QueueNode(Integer data) {
this.value = data;
}
}
QUEUE IMPLEMENTATION
/**
* Queue Data Structure.
*
* A Queue is a first in, first out (FIFO) data structure. A Queue can have any abstract data type as an element, but is
* characterized by two fundamental operations: enqueue() and dequeue(). The enqueue() operation adds an element to the front of
* the Queue, hiding any elements already in the Queue, or initializing the Queue if it is empty. The dequeue() operation
* removes an element from the front of the Queue, and returns this element's value to the caller. Elements are removed from the
* Queue in the same order to the order of their addition to the Queue; therefore, the first element added to the Queue will be
* the first one to be removed.
*
* #author Hristo
*/
public class Queue {
private int size;
private int capacity;
private int theEndIndex;
private int theFrontIndex;
private Object[] theQueue;
/**
* Default Constructor. Initalizes this Queue with initial size = 0 and capacity = 1.
*/
public Queue() {
this.size = 0;
this.capacity = 1;
this.theEndIndex = -1;
this.theFrontIndex = -1;
this.theQueue = new Object[this.capacity];
}
/**
* Constructor. Initializes a Queue to have the given capacity.
*
* #param capacity - the capacity of the Queue-to-be
*/
public Queue(int capacity) {
this.size = 0;
this.capacity = capacity;
this.theEndIndex = -1;
this.theFrontIndex = -1;
this.theQueue = new Object[capacity];
}
/**
* Returns the size of this Queue, i.e., how many elements are in this Queue.
*
* #return int - the size of this Queue
*/
public int size() {
return this.size;
}
/**
* Returns the capacity of this Queue, i.e., the maximum number of elements this Queue can hold.
*
* #return int - the capacity of this Queue
*/
public int capacity() {
return this.capacity;
}
/**
* Returns whether or not this Queue is empty, i.e., size == 0.
*
* #return boolean - true if this Queue is empty, false otherwise
*/
public boolean isEmpty() {
return ((this.theEndIndex == this.theFrontIndex) && (this.size == 0)) ? true : false;
}
/**
* Returns whether or not this Queue is full, i.e., size == capacity.
*
* #return boolean - true if this Queue is full, false otherwise
*/
public boolean isFull() {
return (this.size == this.capacity && this.theEndIndex == this.theFrontIndex) ? true : false;
}
/**
* Inserts the given value onto the end of this Queue.
*
* #param value - the data to insert
*/
public void enqueue(Integer value) {
if (value == null) {
return;
} else {
if (isEmpty()) {
this.theEndIndex = 0;
this.theFrontIndex = 0;
}
if (isFull()) {
resize();
}
insert(value);
return;
}
}
/**
* Removes the front element in this Queue and returns it.
*
* #return Integer - the front element in this Queue
*/
public Integer dequeue() {
if (isEmpty()) {
return null;
} else {
return remove();
}
}
/**
* Returns the front element of this Queue without removing it.
*
* #return Integer - the front element of this Queue
*/
public Integer peek() {
return (isEmpty()) ? null : (((QueueNode) theQueue[this.theFrontIndex]).value);
}
/**
* Inserts the given value into this Queue.
*
* #param value - the value to insert
*/
private void insert(Integer value) {
this.theQueue[this.theEndIndex] = new QueueNode(value);
/*
* 'theEndIndex' pointer indicates where to insert new QueueNodes in 'theQueue' array. If incrementing this pointer goes
* beyond the size of 'theQueue' array, then pointer needs to wrap around to the beggining of 'theQueue' array.
*/
this.theEndIndex++;
if (this.theEndIndex >= this.theQueue.length) {
this.theEndIndex = 0; // wrap around
}
this.size++;
return;
}
/**
* Removes the front element in this Queue and returns the corresponding value.
*/
private Integer remove() {
QueueNode node = (QueueNode) this.theQueue[this.theFrontIndex];
theQueue[this.theFrontIndex] = null;
/*
* 'theFrontIndex' pointer indicates where to remove QueueNodes from 'theQueue' array. If incrementing this pointer goes
* beyond the size of 'theQueue' array, then pointer needs to wrap around to the beggining of 'theQueue' array.
*/
this.theFrontIndex++;
if (this.theFrontIndex >= this.theQueue.length) {
this.theFrontIndex = 0; // wrap around
}
this.size--;
return node.value;
}
/**
* Creates an array with double the size of the original and copies over the contents from the original.
*/
private void resize() {
Object[] doubleQueue = new Object[this.capacity * 2];
int count = 0;
int iter = this.theFrontIndex;
while (count < this.size) {
doubleQueue[count] = (QueueNode) theQueue[iter];
iter++;
count++;
if (iter >= this.size && this.size > 1) {
iter = 0;
}
}
this.theQueue = doubleQueue;
this.capacity *= 2;
this.theEndIndex = this.size;
this.theFrontIndex = 0;
return;
}
}
Like this (you add the rest):
public class StackNode<T>
{
public T value;
}
public class Stack<T>
{
private int size;
private int capacity;
private int topNodeIndex;
private StackNode<T>[] theStack;
}
The placeholder T describes the type of value help by the node class. So you can create a Stack<Double> or a Stack<Process> or any other type that you wish.