For class I had to either implement a BST or a heapSort. I did the BST but figured it would be good to know this too but now I'm stuck. This is my first time working with heaps(and really coding with generics/implementing Comparable so I apologize for all the errors) and im running into an issue implementing compareTo.
Essentially I want to be able to add generic objects to my heap Array and then compare them for the Heap sorting. I use compareTo to check a new entry when adding to the heap and for swapping in the reheap method.
My errors returned:
Heap.java:64: error: bad operand types for binary operator '<'
if (this < other)
^
first type: Heap<T>
second type: Heap<T>
where T is a type-variable:
T extends Comparable<T> declared in class Heap
Im not sure how to work around that though. I understand that my binary operator isnt for generics but I dont know how to work around it.
Thanks for any input. Sorry about all the beginners mistakes you may find!
Heres my code:
import java.util.*;
class Heap<T extends Comparable <T>> implements Comparable<Heap<T>>{
private T[] heap;
private int lastIndex;
private static final int CAPACITY = 25;
public Heap(){
this(CAPACITY);
}
public Heap(int capacity){
heap = (T[])new Comparable[capacity+1];
lastIndex = 0;
}
public void add(T newEntry){
lastIndex++;
if(lastIndex>=heap.length)
doubleArray();
int newIndex = lastIndex;
int parentIndex = newIndex/2;
while((parentIndex>0)&&(heap[parentIndex].compareTo(newEntry)>0))
{
heap[newIndex] = heap[parentIndex];
newIndex = parentIndex;
parentIndex = newIndex/2;
}
heap[newIndex] = newEntry;
}
public void display()
{
for(int i=1;i<heap.length;i++)
{
System.out.println(heap[i]);
}
}
private void doubleArray()
{
T[] oldHeap = heap;
int oldSize = heap.length;
heap = (T[]) new Object[2*oldSize];
for(int i =0; i < oldSize-1;i++)
{
heap[i] = oldHeap[i];
}
}
public int compareTo(Heap<T> other)
{
int sort = 0;
if (this < other)
{
sort = -1;
}
else if (this> other)
{
sort = 1;
}
else
{
sort = 0;
}
return sort;
}
private <T extends Comparable<T>> void reheap(T[] heap, int rootIndex, int lastIndex)
{
boolean done=false;
T orphan = heap[rootIndex];
int leftChildIndex = 2 * rootIndex + 1;
while(!done && (leftChildIndex<=lastIndex))
{
int largerChildIndex = leftChildIndex;
int rightChildIndex = leftChildIndex + 1;
if(rightChildIndex<=lastIndex && (heap[rightChildIndex].compareTo(heap[largerChildIndex])>0))
largerChildIndex = rightChildIndex;
if(orphan.compareTo(heap[largerChildIndex])<0)
{
// System.out.println(orphan+ "--" + largerChildIndex);
heap[rootIndex] = heap[largerChildIndex];
rootIndex = largerChildIndex;
leftChildIndex = 2 * rootIndex+1;
}
else
done = true;
}
heap[rootIndex] = orphan;
}
public <T extends Comparable<T>> void heapSort(int n)
{
for(int rootIndex = n/2-1;rootIndex >=0;rootIndex--)
reheap(heap,rootIndex,n-1);
swap(heap,0,n-1);
for(int lastIndex = n-2;lastIndex > 0;lastIndex--)
{
reheap(heap,0,lastIndex);
swap(heap,0,lastIndex);
}
}
private <T extends Comparable<T>> void swap(T[] a,int first, int last)
{
T temp;
temp = a[first];
a[first] = a[last];
a[last] = temp;
}
}
Any help with any of this is very very appreciated
You don't want your heap to be Comparable; you want to compare its members. Therefore remove implements Comparable<Heap<T>> from your class declaration and remove the compareTo method.
Many of your methods (reheap, heapSort, swap) redundantly declare <T extends Comparable<T>> where you are already in the context of your class parameterized with T. Remove those declarations.
I think you need to implement the compareTo on you T object, not on the heap itself. You have to
make sure T is comparable for it to be in the heap.
Related
I'm trying to write a Linear List based on arrays, but make the list be able to store any value by using Java Generics. This way I can create other programs that utilize it, but pass in different data types. I'm not entirely sure how to do this, any help would be appreciated.
I guess Im struggling trying to set it up and create the functions. The generic type really messes me up.
For example, trying to add a removeFirst() function, I cant use a loop like this:
for (int i = 0; i < n - 1; i++)
newList[i] = newList[i + 1];
— as it says The type of the expression must be an array type but it resolved to ArrayList.
Fair warning, I'm still learning data structures. This is what I have so far:
import java.util.ArrayList;
public class LinearList<T> {
private static int SIZE = 10;
private int n = 0;
private final ArrayList<T> newList = new ArrayList<T>(SIZE);
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public void add(T value, int position) {
newList.add(position, value);
n++;
}
public void addFirst(T value) {
newList.add(0, value);
n++;
}
public void removeLast() {
T value = null;
for (int i = 0; i < newList.size(); i++)
value = newList.get(i);
newList.remove(value);
n--;
}
public void removeFirst() {
newList.remove(0);
n--;
}
public T first() {
return newList.get(0);
}
public T last() {
int value = 0;
for (int i = 0; i < newList.size() - 1; i++)
value++;
return newList.get(value);
}
public int count() {
return n;
}
public boolean isFull() {
return (n >= SIZE);
}
public boolean isEmpty() {
return (n <= 0);
}
//part 4
public void Grow() {
int grow = SIZE / 2;
SIZE = SIZE + grow;
}
public void Shrink() {
int grow = SIZE / 2;
SIZE = SIZE - grow;
}
public String toString() {
String outStr = "" + newList;
return outStr;
}
}
A good start would be to make it non-generic with a class you are comfortable with, such as an Integer.
Once you have it set up, you can then make it generic by adding <T> to the class name, then replacing all references of Integer with T.
public class MyArray{ becomes public class MyArray<T>{
public Integer add(Integer value){ becomes public T add(T value){
See What are Generics in Java? for more help
I have a question for the more advanced OOP developers here.
I am currently a CS student. We learned a Procedural Programming in Java the first semester where ADT was introduced. I understand the theory and the idea of why ADT is good and what are the benefits of it but it seems quite difficult for me to implement it in code. I get confused and lost.
In addition to that our exit test was on paper (we had to write around 200 line of code on paper) and I found it difficult.
Are there any tips before starting to construct the program?
For instance, do you guys already know how many methods and what method what it will return and have as a formal argument before you start to write the code?
You can approach it programming-style.
First, you need to define an interface for the ADT. Just write down its name and what it does.
Example:
ADT: Integer Stack
void push(int element) - adds an element to the top of stack
int pop() - removes and returns an element from the top of stack
int peek() - returns the value of top. no removal of value
boolean isEmpty() - returns true if the stack is empty
int size() - returns the number of element in the stack.
void print() - print all values of stack
Next is you need to decide on its implementation. Since ADT is about storage, it will be good to decide on storage strategy first.
Example:
ADT: Integer Stack
Implementation: Array Integer Stack
Implements an int stack using Java's built-in array functionality.
Since array is a static collection, i need to use an integer variable to track "top"
When everything is set, you can now proceed to coding.
public interface IntegerStack {
void push(int e);
int pop();
int peek();
boolean isEmpty();
int size();
void print();
}
public class ArrayIntegerStack implements IntegerStack {
private static final int INITIAL_TOP_INDEX = -1;
private int topIndex = INITIAL_TOP_INDEX;
private int[] stackValue = new int[Integer.MAX_VALUE];
#Override
public void push(int element) {
stackValue[++topIndex] = element;
}
#Override
public int pop() {
return stackValue[topIndex--];
}
#Override
public int peek() {
return stackValue[topIndex];
}
#Override
public boolean isEmpty() {
return INITIAL_TOP_INDEX == topIndex;
}
#Override
public int size() {
return topIndex + 1;
}
#Override
public void print() {
for (int i = 0; i <= topIndex; i++) {
System.out.println(stackValue[i]);
}
}
}
Adding on to the answer of KaNa001, you could use a modified HashMap where the key is the index and the value is the integer in the stack. This wont cause an Exception, as the HashMap object can change its length.
public class OrderSet<T> {
private HashMap<Integer, T> array;
public OrderSet() {
array = new HashMap<Integer, T>();
}
public void addAt (T o, int pos) {
// uses Array indexing
HashMap<Integer, T> temp = new HashMap<Integer, T>();
if (!(array.size() == 0)) {
for (int i = 0; i < array.size(); i++) {
temp.put(i, array.get(i));
}
array.put(pos, o);
int size = array.size();
for (int i = pos + 1; i < size + 1; i++) {
array.put(i, temp.get(i - 1));
}
} else {
array.put(0, o);
}
}
public T getPos (int pos) {
if (array.size() == 0) {
return null;
} else {
return array.get(pos);
}
}
}
I am making a priority queue heap of type T. When I add more than one integer to my heap, I get a null pointer exception on line 55, which is where the reheapUp method uses the comparator to decide which integer gets priority.
I've been stuck on this for hours. At first I thought I had to implement a generic compare method but that doesn't make sense because there would be nothing specific enough to compare. The compare method I am using is from an old project where I made a binary search tree map that compared strings.
/*
* PQHeap.java
* 11/12/18
*/
import java.util.Comparator;
import java.util.*;
public class PQHeap<T>{
private Object[] heap; //hash table
private int heapSize;
private int capacity;
private Comparator<T> comparator;
public PQHeap(Comparator<T> comparator){
heapSize = 0;
capacity = 100;
heap = new Object[capacity];
}
public int size(){
return this.heapSize;
}
public void add(T obj){
ensureCapacity();
//add to lower right most leaf
heap[heapSize++] = obj;
reheapUp();
}
public void ensureCapacity(){
if(heapSize < heap.length/2)
return;
Object newHeap[] = new Object[2*heap.length];
for(int i=0; i<heap.length; i++)
newHeap[i] = heap[i];
heap = newHeap;
}
#SuppressWarnings("unchecked")
private void reheapUp(){
int outOfPlaceInd = heapSize - 1;
while(outOfPlaceInd > 0){
int parentInd = (outOfPlaceInd - 1)/2;
**if (comparator.compare((T)heap[outOfPlaceInd], (T)heap[parentInd]) < 0)**
{
swap(outOfPlaceInd, parentInd);
outOfPlaceInd = (outOfPlaceInd-1)/2;
}
else{
return;
}
}
}
private void swap(int i, int j){
Object copy = heap[i];
heap[i] = heap[j];
heap[j] = copy;
}
#SuppressWarnings("unchecked")
public T remove(){
if(heapSize == 0)
throw new IllegalStateException("Trying to remove from an empty PQ!");
Object p = heap[0];
heap[0] = heap[--heapSize];
reheapDown();
return (T)p;
}
#SuppressWarnings("unchecked")
private void reheapDown(){
int outOfPlaceInd = 0;
int leftInd = 2*outOfPlaceInd+1; //left child
int rightInd = 2*outOfPlaceInd+2; //right child
while(leftInd <= heapSize-1){
int smallerChildInd = leftInd;
if ((rightInd < heapSize) && (comparator.compare((T)heap[rightInd], (T)heap[leftInd]) < 0))
smallerChildInd = rightInd;
// is the parent smaller or equal to the smaller child
int compare = comparator.compare((T)heap[outOfPlaceInd], (T)heap[smallerChildInd]);
// if the parent is larger than the child...swap with smaller child
if (compare > 0)
{
swap(outOfPlaceInd, smallerChildInd);
// update indices
outOfPlaceInd = smallerChildInd;
leftInd = 2*outOfPlaceInd + 1;
rightInd = 2*outOfPlaceInd + 2;
}
else
{
return;
}
}
}
public static void main( String[] args ) {
PQHeap<Integer> pq = new PQHeap<Integer>(new TestIntComparator());
pq.add( 10 );
pq.add( 20 );
System.out.println(pq.size());
pq.add( 20 );
pq.add( 30 );
class TestIntComparator implements Comparator<Integer> {
public TestIntComparator() {;}
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
}
}
}
// class NaturalComparator<T extends Comparable<T>> implements Comparator<T> {
// public int compar(T a, T b) {
// return a.compareTo(b);
// }
// }
In PQHeap constructor you don't assign input comparator object to class field. Add line like this:
this.comparator = comparator;
in your constructor
This question already has answers here:
How to create a generic array in Java?
(32 answers)
Closed 7 years ago.
This is an array based Queue , for int :
/**
* Array based
* #author X220
*
*/
public class MyQueue {
private int[] _data;
private int MAX_SIZE;
private int front = -1;
private int back = 0;
private int elementsCount = 0;
public void printQueue()
{
int j = this.front + 1;
int i = 0;
while (i < this._data.length && i < elementsCount)
{
System.out.println("At location " + j % MAX_SIZE + " element :" + this._data[j % MAX_SIZE]);
j++;
i++;
}
}
public MyQueue(int _size)
{
MAX_SIZE = _size > 0 ? _size : 10;
this._data = new int[MAX_SIZE];
}
public boolean IsEmpty()
{
return this.elementsCount == 0;
}
public boolean IsFull()
{
return this.elementsCount == MAX_SIZE;
}
public void Push(int pushMe) throws QueueIsFullException
{
if (IsFull())
{
throw new QueueIsFullException("Queue is full");
}
this.elementsCount++;
_data[back++ % MAX_SIZE] = pushMe;
}
public int Pop() throws QueueIsEmptyException
{
if (IsEmpty())
{
throw new QueueIsEmptyException("Queue is full");
}
elementsCount--;
return _data[++front % MAX_SIZE];
}
public static void main(String args[])
{
try
{
MyQueue q1 = new MyQueue(15);
q1.Push(1);
q1.Push(2);
q1.Push(3);
q1.Push(4);
q1.Push(5);
q1.Pop();
q1.Pop();
q1.Pop();
q1.Pop();
q1.Pop();
q1.Push(6);
q1.Pop();
q1.Push(7);
q1.Push(8);
q1.Push(9);
q1.Push(10);
q1.Push(11);
q1.Push(12);
// q1.Push(1);
// q1.Push(2);
// q1.Push(3);
// q1.Push(4);
// q1.Push(5);
// q1.Push(7);
// q1.Push(8);
// q1.Push(9);
// q1.Push(10);
// q1.Push(11);
// q1.Push(12);
// q1.Push(40);
// q1.Push(50);
q1.printQueue();
}
catch (Exception e)
{
System.out.println(e);
}
}
#SuppressWarnings("serial")
class QueueIsFullException extends Exception
{
public QueueIsFullException(String message){
super(message);
}
}
#SuppressWarnings("serial")
class QueueIsEmptyException extends Exception
{
public QueueIsEmptyException(String message){
super(message);
}
}
}
I wanted to use generics so I changed the int to T but then I got for this :
public class MyQueue <T>{
private T[] _data;
private int MAX_SIZE;
private int front = -1;
private int back = 0;
private int elementsCount = 0;
public void printQueue()
{
int j = this.front + 1;
int i = 0;
while (i < this._data.length && i < elementsCount)
{
System.out.println("At location " + j % MAX_SIZE + " element :" + this._data[j % MAX_SIZE]);
j++;
i++;
}
}
public MyQueue(int _size)
{
MAX_SIZE = _size > 0 ? _size : 10;
this._data = new T[MAX_SIZE];
}
....
}
That :
Cannot create a generic array of T
And from the answers to this post I see that I can't use generics with arrays .
Does this mean that there is no work around for a generics Queue based on array ? Must I switch to some other data structure ?
The root cause of your problem is not with your MyQueue class, I think you misunderstand the way Java handles generics. Generic types exist only at compile time, after that they are simply erased from the byte code and at runtime only real Java types exist behind the scenes.
This is why you cannot instantiate a generic type, because at runtime this parameterized type simply doesn't exist.
What you can do is to provide a real class (extending T) as a parameter in your MyQueue class an instantiate this class type, since this is a first-class Java type.
Here is a very similar StackOverflow question and a solution:
Instantiating a generic class in Java
It is also recommended to read the Java reference about generics, like the answer for you original question is here:
https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createObjects
No there is a work around for this the ugly cast, change your array generic creation to:
this._data = (T[])new Object[MAX_SIZE];
Due to the implementation of Java generics, you can't have code like this:
this._data = new T[MAX_SIZE];
Have a look at this How to create a generic array in Java?
The method I prefer is using
#SuppressWarnings("unchecked")
T[] arr = (T[]) Array.newInstance(clazz,length);
where clazz is the Class<T> object corresponding to the generic type. Note that the cast is unchecked, but Array.newInstance ensures you that you won't be able to insert invalid types into your array.
To me this is the best solution because :
you handle the type consistency to the Array class by passing a Class<T> instance which will be used to cast all the objects inserted in the array. This is thus type-safe without needing you to do anything.
this is relatively small and self-contained, it won't force you to manually cast objects over and over everytime you use the array. This would be the case if you were using an Object[] under the hood.
I have defined my own compare function for a priority queue, however the compare function needs information of an array. The problem is that when the values of the array changed, it did not affect the compare function. How do I deal with this?
Code example:
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
public static final int INF = 100;
public static int[] F = new int[201];
public static void main(String[] args){
PriorityQueue<Integer> Q = new PriorityQueue<Integer>(201,
new Comparator<Integer>(){
public int compare(Integer a, Integer b){
if (F[a] > F[b]) return 1;
if (F[a] == F[b]) return 0;
return -1;
}
});
Arrays.fill(F, INF);
F[0] = 0; F[1] = 1; F[2] = 2;
for (int i = 0; i < 201; i ++) Q.add(i);
System.out.println(Q.peek()); // Prints 0, because F[0] is the smallest
F[0] = 10;
System.out.println(Q.peek()); // Still prints 0 ... OMG
}
}
So, essentially, you are changing your comparison criteria on the fly, and that's just not the functionality that priority queue contracts offer. Note that this might seem to work on some cases (e.g. a heap might sort some of the items when removing or inserting another item) but since you have no guarantees, it's just not a valid approach.
What you could do is, every time you change your arrays, you get all the elements out, and put them back in. This is of course very expensive ( O(n*log(n))) so you should probably try to work around your design to avoid changing the array values at all.
Your comparator is only getting called when you modify the queue (that is, when you add your items). After that, the queue has no idea something caused the order to change, which is why it remains the same.
It is quite confusing to have a comparator like this. If you have two values, A and B, and A>B at some point, everybody would expect A to stay bigger than B. I think your usage of a priority queue for this problem is wrong.
Use custom implementation of PriorityQueue that uses comparator on peek, not on add:
public class VolatilePriorityQueue <T> extends AbstractQueue <T>
{
private final Comparator <? super T> comparator;
private final List <T> elements = new ArrayList <T> ();
public VolatilePriorityQueue (Comparator <? super T> comparator)
{
this.comparator = comparator;
}
#Override
public boolean offer (T e)
{
return elements.add (e);
}
#Override
public T poll ()
{
if (elements.isEmpty ()) return null;
else return elements.remove (getMinimumIndex ());
}
#Override
public T peek ()
{
if (elements.isEmpty ()) return null;
else return elements.get (getMinimumIndex ());
}
#Override
public Iterator <T> iterator ()
{
return elements.iterator ();
}
#Override
public int size ()
{
return elements.size ();
}
private int getMinimumIndex ()
{
T e = elements.get (0);
int index = 0;
for (int count = elements.size (), i = 1; i < count; i++)
{
T ee = elements.get (i);
if (comparator.compare (e, ee) > 0)
{
e = ee;
index = i;
}
}
return index;
}
}