So I was trying to return the max value within an type "T" array list and got an error while using compareTo. This is the full code.
package myUtil;
public class SimpleListAry<T extends java.lang.Comparable<T>> extends java.lang.Object implements SimpleList<T> {
private T[] myList;
private int size;
public SimpleListAry(){
myList = (T[])new Comparable[10];
}
public SimpleListAry(int capacity){
if (capacity <= 0){
throw new IllegalArgumentException();
}
myList = (T[]) new Object [capacity];
}
#Override
public int size() {
size = myList.length;
return size;
}
#Override
public T get(int i) {
return myList[i];
}
#Override
public T set(int i, T item) {
return myList[i] = item;
}
#Override
public int indexOf(Object item) {
for (int i = 0; i < size; i++){
if (get(i).equals(item)){
return i;
}
}
return -1;
}
#Override
public void add(int at, T item) {
if (at < 0 || at > size)
throw new ArrayIndexOutOfBoundsException(at);
for (int i = size; i > at; i--){
myList[i] = myList [i-1];
}
// myList[at] = item;
size++;
}
#Override
public T remove(int at) {
if (at < 0 || at >= size)
throw new ArrayIndexOutOfBoundsException(at);
T item = myList[at];
for (int i = at; i<size-1; i++)
myList[i] = myList[i+1];
size--;
return item;
}
#Override
public T max() {
T max = myList[0];
for (int i = 1; i < myList.length; i++){
if(myList[i].compareTo(max) == 1)
max = myList[i];
}
return max;
}
#Override
public T min() {
T min = myList[0];
for (int i = 1; i < size -1; i++){
if (myList[i].compareTo(min) == -1)
min = myList[i];
}
return min;
}
}
and the error is at Public T max():
public T max() {
T max = myList[0];
for (int i = 1; i < myList.length; i++){
if(myList[i].compareTo(max) == 1)
max = myList[i];
}
return max;
}
I also tried using ">" to compare them but that was not working either. It may be because of the data type but there's no error in the IDE only when I attempt to run it and it points directly to this line in T max(){
if(myList[i].compareTo(max) == 1)
Three possibilities of null pointer in if(myList[i].compareTo(max) == 1)
myList - being initialized in constructor, not null
myList[i] - list initially filled with null !
max, depending on how compareTo is implemented - initialized to myList[0], can be null if list empty
The second case is the problem since the elements of the whole underlying array are being compared without considering the real size of the list.
The size() method is wrong since it sets the size variable, which is returned, to the length of the array overwriting the correct value.
Just remove the assignment statement inside the size() method (and use that method in the comparison loop)
Related
In our midterm exam teacher asked us to do this question below:
Write a generic Queue class which uses an array(not a link list) as a memory storage. It should support generic type parameter and array resizing (both growing and shrinking), but it doesn't have to support iterators.Hints:Queue is a FIFO data structure ; the API for a queue contains enqueue, dequeue,size and isEmpty methods in addition to the constructor; you don't have to implement toString.
I tried to write this code and here's what I wrote. But I don't know how should I check this code. Is it correct or how can I check it?
public class Queue<T> {
public T[] array;
public int N;
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N;
}
public void resize(int max) {
T[] temp = (T[]) new Object[max];
for (int i = 0; i < N; i++) {
temp[i] = array[i];
}
array = temp;
}
public void enqueue(T item) {
if (isEmpty()) {
array[0] = item;
N++;
} else if (N == array.length) {
resize(array.length * 2);
array[N] = item;
N++;
} else {
array[N] = item;
N++;
}
}
public T dequeue() {
T value = array[0];
for (int i = 1; i < N; i++) {
array[i - 1] = array[i];
}
array[--N] = null;
return value;
}
}
here is the code with my revisions. I preserved your general approach I just made some fixes.
Of course other optimizations are possible but I'll leave them to you ;)
import java.lang.reflect.Array;
public class Queue<T> {
//never expose directly as public internal variables of your classes. So they should be private
private final Class<T> clazz;
private T[] array;
private int n;
//these 2 variables define the expansion and reducing policy so that may be changed dynamically
private final float policyToExpand = 3.0f/4.0f;
private final float policyToReduce = 1.0f/4.0f;
//you didn't implement the constructor of your class that was required. This should do the work.
//Just mind that the 4 it's the initial capacity of the array.
public Queue(Class<T> clazz) {
this.clazz = clazz;
this.array = (T[]) Array.newInstance(clazz, 4);
this.n = 0;
}
public boolean isEmpty() {
return n == 0;
}
public int size() {
return n;
}
//cleaned a bit enqueue and dequeue method and extrapolating the logic for resize.
public void enqueue(T item) {
array[n] = item;
n++;
if(expansionIsNeeded()) performResizeExpanding();
}
public T dequeue() {
T value = array[0];
slideBackArray();
n--;
if(reduceIsNeeded()) performResizeReducing();
return value;
}
//logic for sliding back items when dequeueing
private void slideBackArray() {
for (int i = 1; i < n; i++) {
array[i - 1] = array[i];
}
array[n] = null;
}
//these 2 methods take care of triggering resize
private boolean expansionIsNeeded() {
float currentFilling = (float) n / array.length;
return currentFilling >= policyToExpand;
}
private boolean reduceIsNeeded() {
float currentFilling = (float) n / array.length;
return currentFilling <= policyToReduce;
}
//these 2 instead perform the actual resize
private void performResizeExpanding() {
T[] tempArray = (T[]) Array.newInstance(clazz, this.array.length*2);
System.arraycopy(this.array, 0, tempArray, 0, n);
this.array = tempArray;
}
private void performResizeReducing() {
T[] tempArray = (T[]) Array.newInstance(clazz, this.array.length/2);
System.arraycopy(this.array, 0, tempArray, 0, n);
this.array = tempArray;
}
}
Some issues:
The first enqueue call will already produce an Null Pointer Exception. A minimal test would have revealed this. Your array is not initialised and so access to array.length or array[0] or similar will trigger a NPE. You need to initialise the array upon construction.
array.length * 2 will not change the array size when it is 0, it is probably best to initialise your array with a size of at least 1, and never allow it to be come less.
Code that shrinks the array is lacking.
dequeue should not have to move every element every time you call it. Typically, an array-based queue keeps track of the start of the data and the end, so that the used part of the array does not necessarily have to start at index 0. Instead of an N member, define start and end members.
Here is a possible adjustment of your class:
public class Queue<T> {
private T[] array;
private int start, end; // Instead of N, so to gain efficiency in dequeue
Queue() {
array = (T[]) new Object[1]; // Initialise!
}
public boolean isEmpty() {
return start == end;
}
public int size() {
return (end + array.length - start) % array.length;
}
public void resize(int max) {
T[] temp = (T[]) new Object[max];
if (end > start) {
end -= start;
System.arraycopy(array, start, temp, 0, end);
start = 0;
end %= max;
} else {
System.arraycopy(array, 0, temp, 0, end);
int size = array.length - start;
System.arraycopy(array, start, temp, max - size, size);
start = max - size;
}
array = temp;
}
public void enqueue(T item) {
array[end] = item;
end = (end + 1) % array.length;
if (start == end) {
resize(array.length * 2);
}
}
public T dequeue() {
if (array.length > 1 && size() <= array.length / 2) {
resize(array.length / 2); // Shrink
}
T value = array[start];
array[start] = null;
start = (start + 1) % array.length;
return value;
}
}
This is my Arraylist I'm having trouble how to make a new class to check if my methods work.
Any help will be useful I need to know how to make a start my new class .
I create a class but I keep getting it wrong.
Do I have to extend it our in my new class am only?
Any assistance will be greatly useful.
public class MyArray<E extends Comparable<E>> {
// No other data fields necessary.
private E[] data;
private int size;
public MyArray(int size) {
this.data = (E[]) (new Comparable[size]);
size = 0;
}
public void add(E item) {
if (size == data.length)
resize();
data[size] = item;
size++;
}
private void resize() {
int len = data.length * 2;
E[] temp = (E[]) new Comparable[len];
for (int i = 0; i < size; i++)
temp[i] = data[i];
data = temp;
}
public boolean contains(E item) {
for (int i = 0; i < size; i++) {
if (data[i].equals(item))
return true;
}
return false; // not found
}
public void delete(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException();
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
}
public boolean delete(E item) {
if (item == null)
return false;
for (int i = 0; i < size; i++) {
if (data[i].equals(item)) {
delete(i); // delete at index i
return true;
}
}
return false;// not found
}
}
Since your class is defined with generics (the E), you have to provide an actual type for E. Actually, it should work pretty much like ArrayList class.
MyArray<String> a = new MyArray<String>(10);
a.add("Foo");
a.add("Bar");
I have a jagged array.
How can I override next(), so I can get its elements step-by-step?
This might be a wrong answer to your question. I'll remove it in that case, but maybe you can use it for what you want to achieve:
int[][] it = {{1,2}, {3,4,5}};
OfInt iterator = Arrays.stream(it).flatMapToInt(x -> IntStream.of(x)).iterator();
iterator.forEachRemaining((IntConsumer) System.out::print);
Stream the jagged array, flatmap it into one single IntStream and then do what you want with it. In this example I fetched the iterator but you might only want:
Arrays.stream(it).flatMapToInt(x -> IntStream.of(x)).forEach((IntConsumer) System.out::print);
In forEach you can do what you need, or use some other method of IntStream
Thank you all for your answers, I've found my answer in russian stackoverflow:
https://ru.stackoverflow.com/questions/867881/java-iterator-%D0%B4%D0%BB%D1%8F-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0
public class IteratorFor2DArray implements Iterator {
private int size;
private int i = 0;
private int j = 0;
private int[][] values = new int[i][j];
private int position = 0;
public IteratorFor2DArray(int[][] values) {
this.values = values;
this.size = countOfElements(values);
}
private int countOfElements(int[][] values) {
int count = 0;
for (int[] row : values) {
count += row.length;
}
return count;
}
#Override
public boolean hasNext() {
return position < size;
}
#Override
public Integer next() {
if (position >= size) {
throw new NoSuchElementException();
}
int element = values[i][j];
position++;
j++;
while (i < values.length && j >= values[i].length) {
j = 0;
i++;
}
return element;
}
}
I've also found another way:
public class IteratorFor2DArray implements Iterator {
private int[][] data;
private int i, j;
public IteratorFor2DArray(int[][] data) {
this.data = data;
}
#Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int element = data[i][j];
j++;
while (i < data.length && j >= data[i].length) {
j = 0;
i++;
}
return element;
}
#Override
public boolean hasNext() {
return (i < data.length && j < data[i].length);
}
}
I am developing a big example case for teaching generics. A group of classes and interfaces that mimic the collections class in Java. Here's one of the source files:
package edu.brandeis.cosi12b.listdemo;
public class ArrayList<E extends Comparable<E>> extends AbstractList<E> implements List<E> {
private E[] list;
private int size;
private int capacity;
public ArrayList() {
this(20);
}
#SuppressWarnings("unchecked")
public ArrayList(int initialCapacity) {
list = (E[]) (new Object[initialCapacity]);
size = 0;
capacity = initialCapacity;
}
public int capacity() {
return capacity;
}
public int size() {
return size;
}
public void add(E val) {
list[size] = val;
size++;
}
public String toString() {
StringBuffer s = new StringBuffer();
s.append("[");
for (int i = 0; i < size - 1; i++) {
s.append(list[i]);
s.append(", ");
}
s.append(list[size - 1]);
s.append("]");
return (s.toString());
}
public void set(int index, E value) {
expandIfNecessary(index);
for (int i = size; i > index; i--) {
list[i] = list[i - 1];
}
list[index] = value;
if (index > size)
size = index + 1;
}
#SuppressWarnings("unchecked")
private void expandIfNecessary(int index) {
if (index < capacity)
return;
int newCapacity = capacity * 2 + index;
E[] oldArray = list;
list = (E[]) (new Object[newCapacity]);
for (int i = 0; i < size; i++)
list[i] = oldArray[i];
capacity = newCapacity;
}
public E get(int index) {
if (index < 0 || index >= size)
throw new ArrayIndexOutOfBoundsException("i: " + index + " s: " + size);
return list[index];
}
public void remove(int index) {
for (int i = index; i < size; i++)
list[i] = list[i + 1];
size--;
}
public boolean isEmpty() {
return size() == 0;
}
public int indexOf(E value) {
for (int i = 0; i < size; i++) {
if (list[i] == value)
return i;
}
return -1;
}
public boolean contains(E value) {
return (indexOf(value) != -1);
}
#Override
public void add(int index, E value) {
// TODO Auto-generated method stub
}
}
When I run this in a test case I get this error. I know it's something pretty subtle and it exceeds my knowledge of Java.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at edu.brandeis.cosi12b.listdemo.ArrayList.<init>(ArrayList.java:14)
at edu.brandeis.cosi12b.listdemo.ArrayList.<init>(ArrayList.java:9)
at edu.brandeis.cosi12b.listdemo.TestSuite.arrayListtest1(TestSuite.java:134)
at edu.brandeis.cosi12b.listdemo.TestSuite.runArrayListTests(TestSuite.java:15)
at edu.brandeis.cosi12b.listdemo.TestSuite.runAll(TestSuite.java:9)
at edu.brandeis.cosi12b.listdemo.ListDemo.runTests(ListDemo.java:13)
at edu.brandeis.cosi12b.listdemo.ListDemo.main(ListDemo.java:6)
Use
list = (E[]) new Comparable<?>[initialCapacity];
and
list = (E[]) (new Comparable<?>[newCapacity]);
Java doesn't have fully reified generics at runtime (it uses erasure), so it doesn't actually know what E is - only that it extends Comparable, so that is what the compiler inserts for the casts.
The bytecode generated by the compiler for your code looks like this if decompiled:
list (Comparable[]) new Object[initialCapacity];
which fails.
For the below program:
public class MinHeap<T extends Comparable<? super T>>
implements HeapInterface<T> {
private T[] backingArray;
private int size;
// Do not add any more instance variables
/**
* Creates a Heap.
*/
public MinHeap() {
backingArray = (T[]) new Comparable[STARTING_SIZE];
size = 0;
}
#Override
public void add(T item) {
if (item == null) {
throw new IllegalArgumentException("Item was null.");
}
if (size + 1 >= backingArray.length) {
resize();
}
backingArray[size + 1] = item;
int i = size + 1;
while (i > 1 && backingArray[i].compareTo(backingArray[i / 2]) <= 0) {
swap(backingArray[i], backingArray[i / 2], i, i / 2);
i = i / 2;
}
size++;
}
private void resize() {
T[] backingArrayTemp = backingArray;
backingArray = (T[]) new Comparable[backingArrayTemp.length * 2];
for (int i = 1; i < size + 1; i++) {
backingArray[i] = backingArrayTemp[i];
}
}
private void swap(T item1, T item2, int i, int parent) {
backingArray[parent] = item1;
backingArray[i] = item2;
}
#Override
public T remove() {
if (isEmpty()) {
throw new NoSuchElementException("Heap is empty.");
}
T temp = backingArray[1];
backingArray[1] = backingArray[size + 1];
size--;
heapify(1);
return temp;
}
private void heapify(int i) {
int left = 2*i;
int right = 2*i + 1;
int min = i;
if (left < size && backingArray[left].compareTo(backingArray[min])
< 0) {
min = left;
}
if (right < size
&& backingArray[right].compareTo(backingArray[min]) < 0) {
min = right;
}
if (min != i) {
swap(backingArray[i], backingArray[min], i, min);
heapify(min);
}
}
#Override
public boolean isEmpty() {
return size == 0;
}
#Override
public int size() {
return size;
}
#Override
public void clear() {
size = 0;
backingArray = (T[]) new Comparable[STARTING_SIZE];
}
We start indexing at i = 1.
My add method works fine, and I've tried changing from backingArray[1] = backingArray[size + 1]; to backingArray[1] = backingArray[size]
in the remove method, but that doesn't seem right and also didn't work. It got rid of the null pointer but didn't pass all my tests. I'm getting null pointers at
backingArray[left].compareTo(backingArray[min]) < 0)
because backingArray[min] is null.
Stack trace
java.lang.NullPointerException
at java.lang.Integer.compareTo(Integer.java:1216)
at java.lang.Integer.compareTo(Integer.java:52)
at MinHeap.heapify(MinHeap.java:68)
at MinHeap.remove(MinHeap.java:60)
I can't really test this, right now, but I think the main problem is in the resize() method. When you create the temporary array to hold the data
T[] backingArrayTemp = backingArray;
you actually tell the new array to point to the same address in the memory as the original backingArray. Then you reallocate backingArray and also the temp array, since they point to the same place in memory. Then, of course, all the elements will not be initialized and the bеhaviour will not be as expected.
The correct way to do this is to create a "new" array and then copy the values:
T[] backingArrayTemp = new T[backingArray.length];
for(int i = 0; i < backingArray.length; ++i)
backingArrayTemp[i] = new T(backingArray[i]);
Where each element is copied with a constructor to avoid similar issues.
About heapify() - I don't know how exactly you will use that min heap, but I guess you will always put the elements one at a time. If you ever need to create the heap from a random array you will need a more complex routine that goes through the entire heap. I can provide you with some more information, if interested.
The problem was I didn't set backingArray[size] = null.