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;
}
}
Related
I am working with implement arraylist. I want to write a method that takes the last element and inserts it at the front. So far I got it to take the last element and insert it in front, and shift everything over. But, I can't seem to be able to delete the last element that was inserted in front. for example: (1,2,5) to (5,1,2) but I got (5,1,2,5). I am missing something in my replaceArray() method, but I don't really know what. Thanks for the help.
Constructor for the class:
public KWArrayList() {
capacity = INITIAL_CAPACITY;
theData = (E[]) new Object[capacity];
}
public void replaceArray(int index, E anElement) {
for (int i = size; i > index; i--){
theData[i] = theData[i - 1];
}
theData[index] = anEntry;
size--;
for (int i = 0; i < theData.length; i++){
System.out.println(theData[i]);
}
}
I would use this simple way of rotating the array (I think the method should be called rotate instead of replaceAll, because it's actually rotation the array by one position).
Here's the method rotate():
#SuppressWarnings("unchecked")
public void rotate() {
Object[] temp = new Object[theData.length];
//copy each element, except the first, from theData into temp by shifting one position off to the right
for (int i = temp.length - 1; i > 0; i--) {
temp[i] = theData[i - 1];
}
//move the last element into the first position
temp[0] = theData[theData.length - 1];
//update theData
theData = (T[]) temp;
}
Complete testable example
public class MyArrayList<T> {
int INITIAL_CAPACITY = 10;
int capacity;
T[] theData;
#SuppressWarnings("unchecked")
public MyArrayList() {
capacity = INITIAL_CAPACITY;
theData = (T[]) new Object[capacity];
}
#SuppressWarnings("unchecked")
public MyArrayList(int capacity) {
this.capacity = capacity;
theData = (T[]) new Object[this.capacity];
}
#SuppressWarnings("unchecked")
public void rotate() {
Object[] temp = new Object[theData.length];
//copy each element, except the first, from theData into temp by shifting one position off to the right
// to the right
for (int i = temp.length - 1; i > 0; i--) {
temp[i] = theData[i - 1];
}
// move the last element into the first position
temp[0] = theData[theData.length - 1];
// update theData
theData = (T[]) temp;
}
/**
* For testing purposes only. It doesn't handle out of bounds values of
* index.
*/
private void insert(T t, int index) {
theData[index] = t;
}
public void print() {
for (T t : theData) {
System.out.print(t + ", ");
}
System.out.println();
}
#SafeVarargs
public static <E> MyArrayList<E> of(E... elements) {
MyArrayList<E> m = new MyArrayList<>(elements.length);
for (int i = 0; i < elements.length; i++) {
m.insert(elements[i], i);
}
return m;
}
}
Test the rotate() method:
public class TestMyArrayList {
public static void main(String[] args) {
MyArrayList<Integer> m = MyArrayList.of(1, 2, 3, 4, 5);
m.print();
m.rotate();
m.print();
}
}
It will print out:
1, 2, 3, 4, 5,
5, 1, 2, 3, 4,
import java.util.Arrays;
public class KWArrayList <E>{
private E[] data; /* your list */
private int nbElt = 0; /* nb of element in your list */
/* no need to store the capacity since data.length give it */
KWArrayList(int capacity){
data = (E[]) new Object[capacity]; /* create */
}
private void resize() {
E[] tmp = (E[]) new Object[2 * data.length]; /* if the number of element >= capacity you double the capacity and copy old elt */
data = Arrays.copyOf(data, 2 * data.length);
}
public void add(E elt) {
if(nbElt >= data.length) {
resize();
}
data[nbElt++] = elt; /* add an elt */
}
public void add(E ... elt) { /* add multiple elt */
for(E e : elt) {
add(e);
}
}
public E removeLast() { /* remove the last elt and return it */
if(nbElt == 0) {
throw new IllegalStateException("nothing to remove");
}
return data[--nbElt];
}
public void removeLastAndInsertFront() {
data[0] = removeLast();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
if(nbElt == 0) {
return sb.append("]").toString();
}
for(int i = 0; i < nbElt; i++) {
sb.append(data[i]).append(", ");
}
sb.setLength(sb.length() - 2);
return sb.append("]").toString();
}
public static void main(String[] args) {
KWArrayList<Integer> data = new KWArrayList(1);
data.add(1, 2, 5);
System.out.println(data);
System.out.println("first delete");
data.removeLastAndInsertFront();
System.out.println(data);
System.out.println("second delete");
data.removeLastAndInsertFront();
System.out.println(data);
System.out.println("third delete");
data.removeLastAndInsertFront();
System.out.println(data);
}
}
public class MyArrayList extends ArrayList<Object>{
public void rotateRight(){
this.add(0, this.remove(this.size()-1));
}
public void rotateLeft(){
this.add(this.remove(0));
}
}
I've written this implementation. I'm assuming theData is of type int but you can change it to whatever. I also removed the parameters in the function since I don't use them.
First we copy the array into a temp variable.
Second, we save the first value in theData into another temp variable.
We then begin to shift starting from the beginning of theData until the second to last index.
Finally, we copy the first index saved from theData into first and assign it to the last index of the array.
Print
public void replaceArray() {
int [] temp = theData;
int last = theData[theData.length - 1];
for (int i = theData.length - 1; i > 0; i--){
temp[i] = theData[i - 1];
}
temp[0] = last;
for (int i = 0; i < theData.length; i++){
System.out.println(temp[i]);
}
}
use queue
if you waht your own, have a 2 ints of the positions of the begin and end of the list, while replaceArray just copy the element to position end; then end = (end+1) % capacity;begin = (begin +1) % capacity; (without removing - no need)
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)
I have created method for quick sort algorithm using generics, I am trying to implement this method but I am trying to implement the so it will quick sort any variables with in the array such as numbers, string, char and so on. i have implemented this class.
this is my AssertRayTool class.
package arraySorter;
import RandomArray.RandomArray;
public abstract class ArraySortTool<T extends Comparable<T>> implements ArraySort<T>
{
private double timeTakenMillis(T[] array) {
double startTime = System.nanoTime();
sort(array);
return ((System.nanoTime()-startTime)/1000000.0);
}
public void timeInMillis(RandomArray<T> generator,int noPerSize,int maxTimeSeconds)
{
int size = 1; // initial size of array to test
int step = 1; // initial size increase
int stepFactor = 10; // when size reaches 10*current size increase step size by 10
double averageTimeTaken;
do {
double totalTimeTaken = 0;
for (int count = 0; count < noPerSize; count++) {
T[] array = generator.randomArray(size);
totalTimeTaken += timeTakenMillis(array);
}
averageTimeTaken = totalTimeTaken/noPerSize;
System.out.format("Average time to sort %d elements was %.3f milliseconds.\n",size,averageTimeTaken);
size += step;
if (size >= stepFactor*step) step *= stepFactor;
} while (averageTimeTaken < maxTimeSeconds*1000);
System.out.println("Tests ended.");
}
public boolean isSorted(T[] array) {
int detectedDirection = 0; // have not yet detected increasing or decreasing
T previous = array[0];
for (int index = 1; index < array.length; index++) {
int currentDirection = previous.compareTo(array[index]); // compare previous and current entry
if (currentDirection != 0) { // if current pair increasing or decreasing
if (detectedDirection == 0) { // if previously no direction detected
detectedDirection = currentDirection; // remember current direction
} else if (detectedDirection * currentDirection < 0) { // otherwise compare current and previous direction
return false; // if they differ array is not sorted
}
}
previous = array[index];
}
// reached end of array without detecting pairs out of order
return true;
}
public void sort(T[] array) {
// TODO Auto-generated method stub
}
}
this is my Quicksort class which extends the above class.
package arraySorter;
public class QuickSort<T extends Comparable<T>> extends ArraySortTool<T>
{
private T array[];
private int length;
public void sort(T[] array) {
if (array == null || array.length == 0) {
return;
}
this.array = array;
length = array.length;
quickSort(0, length - 1);
}
private void quickSort(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
// calculate pivot number, I am taking pivot as middle index number
int pivot = [lowerIndex+(higherIndex-lowerIndex)/2];
// Divide into two arrays
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeValues(i, j);
//move index to next position on both sides
i++;
j--;
}
}
// call quickSort() method recursively
if (lowerIndex < j)
quickSort(lowerIndex, j);
if (i < higherIndex)
quickSort(i, higherIndex);
}
private void exchangevalues(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
From what I can see you're treating your generic array only as an array of integers. To fix that
int pivot = [lowerIndex+(higherIndex-lowerIndex)/2];
Becomes
T pivot = [lowerIndex+(higherIndex-lowerIndex)/2];
And
while (array[i] < pivot)
i++;
while (array[j] > pivot) {
j--;
Becomes
while (array[i].compareTo(pivot) < 0)
i++;
while (array[j].compareTo(pivot) > 0)
j--;
Also, don't forget that your T class must implement Comparable, otherwise you won't be able to compare objects.
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.
For this generic array I added method reverse() that has to reverse the array without using an additional array of elements and I am trying to perform the reverse “in situ” using only swap operations. But I may have gotten it wrong and if so how can it be reversed “in situ” using only swap operations?
import java.util.Collections;
class GenericArray<E> {
private E[] array;
private int size;
public GenericArray() {
array = (E[]) new Object[10];
size = 0;
}
public E get(int i) {
return array[i];
}
public void set(int i, E value) {
if (i < size)
array[i] = value;
}
public void add(E value) {
array[size++] = value;
}
public boolean isFull() {
return size == array.length;
}
public void remove(int i) {
for (int j = i; j < size; j++)
array[j] = array[j + 1];
size--;
}
public void insert(int i, E value) {
for (int j = size; j >= i; j--)
array[j + 1] = array[j];
array[i] = value;
size++;
}
public void display() {
for (int i = 0; i < size; i++)
System.out.print(array[i] + " ");
System.out.println();
}
public E reverse() {
Collections.reverse(array);
}
}
If you mean that you want to do it manually without using Collections.reverse (that code shouldn't even compile btw, reverse needs a List as parameter), just traverse the array from the beginning to the middle swapping elements at the opposite sides of the range:
public E[] reverse() {
for (int i = 0; i < size/2; i++){
E tmp=array[i];
array[i] = array[size - i - 1];
array[size - i - 1]=tmp;
}
return array; // If you really want to return it
}
More info on in situ algorithms on wikipedia.
Regarding an add implementation that ensures that there is enough space:
public void add(E value) {
int newsize=size+1;
if(newsize<size){
//The array is big enough, add the element
array[newsize]=value;
}else{
//The array is too small, create a new one with
//the old content but twice as bigger and add
//the new element
array=Arrays.copyOf(array,size*2);
array[newsize]=value;
}
size=newsize;
}
Collections.reverse() does reversal "in situ"; you just need to give it the array as a list:
Collections.reverse(Arrays.asList(array));