I need to implement my own generic binary heap in java using an arraylist. It needs to support max heaps and min heaps. This should be implemented by passing a Comparator to the BinaryHeap constructor.
So I guess depending on what the compare-method in the passed Comparator does, it's either a min or a max heap. I thought I'd make a regular PQ (which is default min) and then write a MaxPQ class that extends PQ and pass a Comparator to the super constructor. But I need to call the super in the first line, so I don't know where to initialize the Comparator. Any ideas?
Here's the code for the MaxHeap:
import java.util.Comparator;
public class MaxHeap<Bid> extends BinaryHeap<Bid> {
public MaxHeap(){
MaxComp maxComp = new MaxComp();
super(maxComp);
}
}
class MaxComp implements Comparator<Bid>{
public int compare(Bid a, Bid b){
return (a.val - b.val);
}
}
Tried Dmitrys advice super(new MaxComp());, which produced "BinaryHeap<Bid>(MaxComp) is undefined". This is the super constructor which takes a Comparator:
public class BinaryHeap<E>{
private Comparator<? super E> comp;
private ArrayList<E> array;
private int last; // index of last element
public BinaryHeap(Comparator<? super E> comp){
this.comp = comp;
array = new ArrayList<E>();
}
Just initialize it like follows:
super(new MaxComp());
Also, instead of MaxHeap<Bid> extends ... use MaxHeap extends ..., because you already specified with which type you're working with extends BinaryHeap<Bid>. That's why you can't call super constructor with your Comparator. Reason is that generic type Bid in class MaxHeap<Bid> is used instead of actual class Bid.
Related
I want to know how i can override compareTo method in class which implements Comparable
my structure Tree is declared like this
public class Tree<T extends Comparable<T>>
and class which used that structure is Plane that looks like that
public class Plane implements Comparable<Plane>
with override compareTo method,
the thing is if i want create a tree with default comparator i can do that easily with this
Tree<Plane> planes = new Tree<Plane>();
but i want have another tree structure with planes and with different compareTo method, how i can override that method in plane?
Thanks
Define an overloaded constructor:
public Tree() {
this(Comparator.naturalOrder());
}
public Tree(Comparator<? super T> comparator) {
this.comparator = comparator; // store in a field
}
And then use the comparator instead of the compareTo method on the tree elements.
But note that the ability to supply a comparator removes the restriction that T extends Comparable<T> (which is better as T extends Comparable<? super T> anyway).
But in such a case, you can't have a default constructor type-safely. You would either need to require a comparator always to be passed; or provide a static factory method to create a naturally-ordered tree:
static <T extends Comparable<? super T>> Tree<T> withNaturalOrder() {
return new Tree<>(Comparator.naturalOrder());
}
And invoke like
Tree<String> tree = Tree.withNaturalOrder();
you could make the comparator as a parameter of Plane
public class Plane implements Comparable<Plane> {
private Comparable<Plane> c;
public Plane(Comparable<Plane> c) {
this.c = c;
}
#Override
public int compareTo(Plane another) {
return c.compareTo(another);
}
}
whenever you want to change the compare method,just pass a diffferent Comparable instance or a lambda expression to the constructor
Hi need Help regarding java collection sorting. It gives me this error:
Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<WifiSSID>).
The inferred type WifiSSID is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>
My code looks like:
public class WifiSSID {
public String SSIS;
public double id;
}
public class ScanFilterWifiList {
public ScanFilterWifiList(List<WifiSSID> wifiList) {
Collections.sort(wifiList);
//Collections.sort(wifiList, new SortSSIDByid()); tried this also.
}
}
interface Comparator<WifiSSID>
{
int compare(WifiSSID obj1, WifiSSID obj2);
}
class SortSSIDByid implements Comparator<WifiSSID>
{
#Override
public int compare(WifiSSID ssid1, WifiSSID ssid2)
{
int value = 0;
if (ssid1.id > ssid2.id)
value = 1;
else if (ssid1.id < ssid2.id)
value = -1;
else if (ssid1.id == ssid2.id)
value = 0;
return value;
}
}
Am I doing anything wrong?
You can't sort a List of objects that don't implement the Comparable interface. Or rather, you can, but you have to provide a Comparator to the Collections.sort() method.
Think about it: how would Collections.sort() sort your list without knowing when a WifiSSID is smaller or bigger than another one?
You want to use Collections.sort(wifiList, new SortSSIDByid());
EDIT:
You defined your own proprietary Comparator interface, and implement this proprietary Comparator interface in SortSSIDByid. Collections.sort() wants an intance of java.util.Comparator. Not an instance of your proprietary Comparator interface, that it doesn't know.
Just add this import import java.util.Comparator;
and remove this interface
interface Comparator<WifiSSID>
{
int compare(WifiSSID obj1, WifiSSID obj2);
}
Your SortSSIDByid comparator class will now implement java.util.Comparator and that is what is required by the Collections.sort() method.
I have a problem with defining generics in static methods and fields.
Suppose I have a simple interface, used by all classes that contains a field of type T called value:
public interface HasValue<T> {
// Getter:
public T value();
// Setter:
public void setValue(T value);
}
If I have an array of object of a type N that implements HasValue<T>, I may have necessity to order this array. One classical way is to compare those N objects using their value field: if T implements the Comparable<T> interface and both arg0 and arg1 are of type N, then arg0.compareTo(arg1) will be equal to arg0.value().compareTo(arg1.value()).
The goal is to create a usable, not time-consuming, possible simple way to obtain the aforementioned situation.
A possibility would be to create a custom Comparator<N> every time I need something similar. That would force me to write code each time: definitly time consuming.
I could create that Comparator<N> directly in the interface. The first try is to create a method:
It needs to be a default method. Part of the code will test if the class T implements the Comparable interface or not, and for that I need an example of the T class: using this.value().getClass() is the fastest way. With a static method I could not use this.
I need to explicitate that the N class implements the interface HasValue<T>, otherwise the computer will not know.
public default <N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE() throws Exception{
if(Comparable.class.isAssignableFrom(this.value().getClass()))
return new Comparator<N>() {
public int compare(N arg0, N arg1) {
Comparable value0 = (Comparable) arg0.value(),
value1 = (Comparable) arg1.value();
return value0.compareTo(value1);
}
};
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
This strategy works... barely. It's clumsy, involves rawtypes, creates the Comparator<N> every time.
Second try: creating a static field.
The strategy is to separate the testing problem from the rest. A default method will do the test: in case of success the method will return a static Comparator, otherwise an exception.
public default <N extends HasValue<T>> Comparator<?> COMPARE_BY_VALUE() throws Exception{
if(Comparable.class.isAssignableFrom(this.value().getClass()))
return COMPARE_BY_VALUE;
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
public static Comparator<HasValue> COMPARE_BY_VALUE = new Comparator() {
public int compare(Object arg0, Object arg1) {
Comparable value0 = (Comparable) ((HasValue)arg0).value(),
value1 = (Comparable) ((HasValue)arg1).value();
return value0.compareTo(value1);
}
};
While declaring the static field I (unfortunately) cannot state something like public static <T, N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE. That forces me to return a Comparator<HasValue>: not what I wanted.
Using wildcards I can obtain something close:
public default <N extends HasValue<T>> Comparator<?> COMPARE_BY_VALUE() throws Exception{
if(Confrontable.class.isAssignableFrom(this.value().getClass()))
return COMPARE_BY_VALUE;
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
public static Comparator<? extends HasValue<? extends Comparable<?>>> COMPARE_BY_VALUE
= new Comparator() {
public int compare(Object arg0, Object arg1) {
Comparable value0 = (Confrontable) ((HasValue<?>)arg0).value(), value1 = (Confrontable) ((HasValue<?>)arg1).value();
return value0.compareTo(value1);
}
};
This modification will return (in theory) a Comparator<N> where N extends HasValue<T>, T extends Comparable<U> and U is actually T.
That because every ? in Comparator<? extends HasValue<? extends Comparable<?>>> is interpreted by the JVM as a potential new class: three ? means three new class (N, T and U), and it happens that T implements Comparable<T> - thus U and T are one and the same.
I still have a great amount of rawtypes...
...but at least I have only one Comparator for each N and T.
Now, while the last strategy seems to works, I would like to know if there is a better way to obtain my goal.
My initial idea was to state something like
public static <T extends Comparable<T>, N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE = new Comparator() {
public int compare(N arg0, N arg1) {
return arg0.value().compareTo(arg1.value());
}
};
and obtain a Comparator<N> without wildcars. This however sends all types of errors. Someone has an idea?
Just do:
static <T extends Comparable<T>> Comparator<HasValue<T>> createValueComparator() {
return new Comparator<HasValue<T>>() {
#Override
public int compare(HasValue<T> o1, HasValue<T> o2) {
return o1.value().compareTo(o2.value());
}
};
}
This reads: for every type T which implements Comparable this method returns comparator which can compare HasValue<T>.
Java might not be able to properly infer types in such convoluted constructs. You might have to add the types explicitly:
Collections.sort(list, Main.<Integer> createValueComparator());
or:
Comparator<HasValue<Integer>> comparator = createValueComparator();
Collections.sort(list, comparator);
Keep in mind that a lot of programmers overuse generics. Usually there is a simpler way to achieve the same - while still maintaining type safety.
Comparator<? super E> comparator()
This method is declared in the Sorted Set interface.
What does the super mean?
How is the above method different from a Generic Method, and a method with Wildcard arguments.
This means that the type of comparison can be a supertype of the current type.
Eg. you can have the following:
static class A {
}
static class B extends A {
}
public static void main(String[] args) {
Comparator<A> comparator = new Comparator<A>() {
public int compare(A a1, A b2) {
return 0;
}
};
// TreeSet.TreeSet<B>(Comparator<? super B> c)
SortedSet<B> set = new TreeSet<B>(comparator);
// Comparator<? super B> comparator()
set.comparator();
}
In this case, A is a supertype of B.
I hope this has been helpful.
A SortedSet needs to have some rules that it uses to determine the sorting. The Comparator is the implementation of these rules. The interface provides a method to get a reference to it so that you can use it for other purposes, such as creating another set that uses the same sorting rules.
From the javadoc:
"Returns the comparator used to order the elements in this set, or null if this set uses the natural ordering of its elements."
:)
"Super" here means that the method is not required to return a Comparator for E. It might instead return a Comparator for any superclass of E. So, to make that concrete, if E were String, this method could give you a more general Comparator for Object.
A generic method would declare a new generic parameter of its own. This method merely references the generic parameter E which was declared by the class declaration SortedSet<E>. Generic methods are less common. They are usually static, like the Arrays method
public static <T> List<T> asList(T...)
Here, T is declared and used only in this method. It shows that the type of the objects in the returned list is the same as the type of the objects in the vararg parameter.
I'm not sure the exact definition of wild card arguments. ? Is the wild card character. The general pattern when you get a wild card parameter like List<?> is that you can take objects out of it and cast them to Object but you can't put anything in.
The answer to this is in the interface declaration: public interface SortedSet<E> extends Set<E> { ...
This means that any class that implements SortedSet should specify which Type they will be working with. For example
class MyClass implements SortedSet<AnotherClass>
and this will produce (using eclipse), a bunch of methods such as
public Comparator<? super AnotherClass> comparator()
{
return null;
}
public boolean add( AnotherClass ac)
{
return false;
}
Of cause this will work with all sub-classes of AnotherClass as Paul Vargas pointed out.
The other aspect you might be missing is that Comparator is also an interface: public interface Comparator<T>. So what you are returning is an implementation of this.
Just for interest another useful way to use the Comparator interface is to specify it anonymously as part of the Arrays.sort(Object[] a, Comparator c) method:
If we had an Person class we could use this method to sort on age and name like this:
Person[] people = ....;
// Sort by Age
Arrays.sort(people, new Comparator<Person>()
{
public int compare( Person p1, Person p2 )
{
return p1.getAge().compareTo(p2.getAge());
}
});
// Sort by Name
Arrays.sort(people, new Comparator<Person>()
{
public int compare( Person p1, Person p2 )
{
return p1.getName().compareTo(p2.getName());
}
});
I've been looking around to see if I find something to help me with my problem, but no luck until now. I've got the following classese:
public interface ISort<T> {
public List<T> sort(List<T> initialList);
}
public abstract class Sort<T> implements ISort<T> {
private Comparator<? super T> comparator;
public Sort(Comparator<? super T> comparator) {
this.comparator = comparator;
}
#Override
public List<T> sort(List<T> initialList) {
ArrayList<T> list = new ArrayList<T>(initialList);
Collections.sort(list, comparator);
return list;
}
}
public abstract class InternalTreeItem<T> {
public abstract String getValue();
}
public class D extends InternalTreeItem<Integer> {
private Integer i;
public D(Integer i) {
this.i = i;
}
#Override
public String getValue() {
return i.toString();
}
public Integer getInteger() {
return i;
}
}
public class DComparator implements Comparator<D> {
#Override
public int compare(D o1, D o2) {
return o1.getInteger() - o2.getInteger();
}
}
public class DSort extends Sort<D> {
public DSort(Comparator<D> comparator) {
super(comparator);
}
public DSort() {
super(new DComparator());
}
}
And the test class:
public class TestClass {
#Test
public void test1() {
List<InternalTreeItem<?>> list= new ArrayList<InternalTreeItem<?>>();
list.add(new D(1));
list.add(new D(10));
list.add(new D(5));
ISort<?> sorter = new DSort();
sorter.sort(list);
}
}
The compiler gives an error at the line
sorter.sort(list);
and states
The method sort(List<capture#2-of ?>)
in the type ISort<capture#2-of ?>
is not applicable for the arguments
(List<InternalTreeItem<?>>)
Ok, after a couple of hours and help from a friend, we realized the problem lies with Collections#sort(List<T> list, Comparator<? super T> c) in the abstract class Sort, as I use a Comparator<? extends T>.
I use generics, as I have 2 models, one model's super class is a generic abstract subclassed by 35 classes, and the second model actually has 2 different super classes, which combined, are subclassed by again 35 classes. These hierarchies are given, there's nothing I can do to modify them.
The model here is very simple, but you get the point. Also, there's a factory, that depending on the type of T, returns one sorter, or another.
Can any one please help and provide a solution for my issue (that is to sort a generic list; the parameter type can be a generic superclass or one of it's subclasses).
Thanks and best regards,
Domi
One way to approach this is to use a wrapper class for the classes that you cannot change.
So in your example you want to order a list of object D, based on an Integer value. By putting your objects in a wrapper and then adding this to the list, you can expose the value you wish to sort the list by.
For example, you could define an interface like:
private interface SortableListItem<T> extends Comparable<SortableListItem<T>> {
public T getValue();
}
Then, create a wrapper class for D:
public class DWrapper implements SortableListItem<Integer> {
private D item;
public DWrapper(D item) {
this.item = item;
}
public Integer getValue() {
return item.getInteger();
}
public int compareTo(SortableListItem<Integer> o) {
return getValue().compareTo(o.getValue());
}
}
From here it is pretty simple to create and sort your list:
D item1= new D(1);
D item2= new D(10);
D item3= new D(5);
DWrapper wrapper1 = new DWrapper(item1);
DWrapper wrapper2= new DWrapper(item2);
DWrapper wrapper3= new DWrapper(item3);
List<SortableListItem<Integer>> sortableList = new ArrayList<SortableListItem<Integer>>();
sortableList.add(wrapper1 );
sortableList.add(wrapper2);
sortableList.add(wrapper3);
Collections.sort(sortableList);
You can of course make the wrapper class accept a more generic object - the key is that each object returns a value (in this case an Integer) that the List can be sorted by.
The variable sorter is of type ISort<?>. It could have, say, an ISort<String> assigned to it. The sort method takes an argument of List<T> where T could be String. Clearly you cannot use List<InternalTreeItem<?>> for List<String>, so fortunately the compiler points out the error.
(Note: It's generally a good idea to keep to coding conventions. No I Hungarian prefixes, or single letter class names.)
Running your code what I can deduce is that you get a compile error since it is not possible to capture the wildcard that you specify in below line of class TestClass:
ISort<?> sorter = new DSort();
As I understand an occurrence of wild card is taken to stand for some unknown type and from your code it is not possible to infer the type (for the compiler).
But looking at the code, the class DSort is not written in a way to take type parameters
and any attempt to pass type parameters during creation of instance of DSort gave the error:
The type DSort is not generic; it cannot be parameterized with arguments
But you mention that you cannot alter the code of the modules (i.e I presume of classes DSort etc).
So one way to fix the error would be to not use generics during creation of instance of ISort.
The below code works and the prints the the sorted output (1,5,10)
List<InternalTreeItem<?>> list= new ArrayList<InternalTreeItem<?>>();
list.add(new D(1));
list.add(new D(10));
list.add(new D(5));
// no generic arguments
ISort sorter = new DSort();
List<InternalTreeItem<?>> sortedList = sorter.sort(list);
for(InternalTreeItem i:sortedList) {
System.out.println(i.getValue());
}
but results in a warning of the form ISort is a raw type. References to generic type ISort should be parameterized. But having code that uses generic and having warning of this form is not a good practice . This warning implies that the compiler cannot give cast-iron guarantee about the implicit casts it does to use generics.
If feasible, I think the better solution would be to see how the modules class can re-designed.