Implementing specific java MaxHeap using priorityQueue - java

I am going to implement specific java maxHeap using priorityQueue as follows:
Suppose I have a "Customer" class which has a double variable name "marginalGain".
PriorityQueue<Customer> marginalGainHeap=new PriorityQueue<Customer>();
How can I heapify "marginalGainHeap" using the natural order of "marginalGain" variable? Is it possible with using PriorityQueue or I need to re-implement MaxHeap myself?
Regards.

You can use PriorityQueue, however it is worth remembering only the first entry will be sorted. Most likely you want TreeSet as a SortedSet.
In any case you will need to make Customer Comparable, or a better solution more likely it is good idea to create a Comparator<Customer> as you might want to sort Customers in more than one order. Note: You will want to order all Customers, i.e. even if their marginGain is the same, you need to give them an order.
You can use a Comparator with PriorityQueue like this.
PriorityQueue<Customer> pq = new PriorityQueue<Customer>(new Comparator<Customer>() {
public int compare(Customer c1, Customer c2) {
return Double.compare(c1.getMarginGain(), c2.getMarginGain());
}
});
An advantage of PriorityQueue is you don't have to ensure the comparator doesn't return 0 for different Customers (in a TreeSet it would treat these as duplicates and discard them)

I tried to write a class implementing max heap using PriroityQueue, as follows, which might be of help for your problem:
class MaxHeapUsingPriorityQueue<T>{
int capacity;
Comparator<T> pqc;
Queue<T> q;
public MaxHeapUsingPriorityQueue(int capacity, Comparator<T> comparator){
this.capacity = capacity;
this.pqc = comparator;
q = new PriorityQueue<T>(comparator);
}
void add(T t){
if(q.size() < capacity) q.offer(t);
else{
if(pqc.compare(t, q.peek()) > 0){
q.poll();
q.offer(t);
}
}
}
void displayMaxHeapContent(){
// in ascending order
while(!q.isEmpty()) System.out.println(q.poll().toString());
}
}

Related

How to build Priority Queue with customized comparator in linear time

In the constructor of PriorityQueue, we can pass in a collection like List or Set, which builds the PriorityQueue in linear time.
However, this also means the PriorityQueue will use a default Comparator.
I want to use my own comparator, so I can have something else other than a min heap.
The only way I can think of is to wrap the collection in a SortedSet and put a customized comparator in it.
Is there any other good way to do this?
Assume you have class A (or a pojo)
with an int priority; field which holds your priority for this object and its getter getPriority()
then you have it something like this:
Queue<A> queue = new PriorityQueue<>(
4 //initialCapacity
, new Comparator<A>() {
public int compare(A p1, A p2) {
return Integer.valueOf(p1.getPriority()).compareTo(p2.getPriority());
}
});
Create proxy class that contains your data object and implements Comparable interface. Create list of such objects, pass it to PriorityQueue constructor.
I don't know of effective SortedSet implementations with garanteed creation time of O(n) for comparable objects. It is possible to sort array in O(n) for radix-friendly key though (in reality linear sort tends to be not-so-fast in general case), so you can make customized SortedSet with fast creation compatible to your special comparators.
Heap constructor for comparable objects can do it in O(n) only because it does not fully sort the list.
In the constructor of PriorityQueue, we can pass in a collection like List or Set, which builds the PriorityQueue in linear time.
Wrong.
However, this also means the PriorityQueue will use a default Comparator.
Wrong.
The javadoc says
If the specified collection is an instance of a SortedSet or is another PriorityQueue, this priority queue will be ordered according to the same ordering.
So when starting from a recognized sorted collection, you get its Comparator. Moreover, you get linear time.
Otherwise, you don't. The source shows it rather clearly (look for heapify()).
If you have an unsorted list, there's no way to obtain a priority queue in linear time (unless the priority queue is ensuring the heap property lazily; but that's cheating).
I have the same problem.
The only thing that I think is create a wrapper class that contains an object T and implements Comparable interface like this:
class ModifiedPriorityQueue<T> extends PriorityQueue<Wrapper<T>> {
public ModifiedPriorityQueue(Collection<T> collection, Comparator<T> comparator) {
super(collection.stream().map(x -> new Wrapper<>(x, comparator)).collect(Collectors.toList()));
}
}
class Wrapper<T> implements Comparable<Wrapper<T>> {
private final T object;
private Comparator<T> comparator;
public Wrapper(T object, Comparator<T> comparator) {
this.object = object;
this.comparator = comparator;
}
#Override
public int compareTo(Wrapper<T> o) {
return comparator.compare(object, o.object);
}
#Override
public String toString() {
return object.toString();
}
}
class Main {
public static void main(String[] args) {
Collection<Integer> elements = Arrays.asList(1, 2, 3, 4);
ModifiedPriorityQueue<Integer> p = new ModifiedPriorityQueue<>(elements, Comparator.reverseOrder());
while (!p.isEmpty()) {
System.out.println(p.poll());
}
}
}

Java PriorityQueue and Comparator Not Ordering correctly

I am new to Java and am trying to implement a priority queue with a custom comparator. I want to put the Sentences in the queue and have them removed in order to highest score.
For the comparator class I have:
public class SentenceScoreComparator implements Comparator<Sentence> {
#Override
public int compare(Sentence o1, Sentence o2) {
if (o2.getScore() > o1.getScore()) return -1;
//fixed typo
if (o2.getScore() < o1.getScore()) return 1;
return 0;
}
}
I then print out the sentences like so:
PriorityQueue<Sentence> allSentences = new PriorityQueue<Sentence>(new SentenceScoreComparator());
//add sentences
for(Sentence s :allSentences){
System.out.println(s.getScore());
}
but they are not in order
0.34432960587450223
0.47885099912108975
0.10991840331015199
0.36222267254836954
0.05164923572003221
0.5366117828694823
0.3891453014131773
0.0961512261934429
0.5566040852233918
0.5079687049927742
0.7628021620154812
0.6023121606121791
0.25695632228681914
0.15701049878801304
0.1260031244674359
0.36516025683986736
0.3846995962155155
I checked that the queue is using the comparator with the correct comparator method. Can someone explain what I am missing?
You have a typo in the comparator in the second if where o2 score is compared to itself.
Replace it with:
#Override
public int compare(Sentence o1, Sentence o2) {
return Double.compare(o1.getScore(), o2.getScore());
}
On top of that, as bradimus answered, PriorityQueue does not guarantee any sorted traversal. Use a regular list and sort it for that.
PriorityQueue never promised to traverse them in order. From the javadocs:
This class and its iterator implement all of the optional methods of the Collection and Iterator interfaces. The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).

How to sort bidimensional ArrayList?

I have an ArrayList<ArrayList<String>> that is a list of couple of values:
John, 12.3
Marcus, 35.0
Sue, 11.4
How to sort the list by amount?
If in this case there is a better way than using an ArrayList of an ArrayList, please tell me and tell me then how to sort it. Thank you.
Instead I will recommend you to use a class and use class like comparable or comparator to sort.
Something like this:
class Person implements Comparable<Person> {
String name;
double amount;
Person(String n, double d) {
name = n;
amount = d;
}
public int compareTo(Person other) {
if (amount != other.amount)
return Double.compare(amount, other.amount);
return name.compareTo(other.name);
}
}
and this is easy to implement and understand.
Use a Comparator:
A comparison function, which imposes a total ordering on some
collection of objects. Comparators can be passed to a sort method
(such as Collections.sort or Arrays.sort) to allow precise control
over the sort order. Comparators can also be used to control the order
of certain data structures (such as sorted sets or sorted maps), or to
provide an ordering for collections of objects that don't have a
natural ordering.
It'd be great if you could add more information about why you are using those values then I am sure a better approach can be suggested.
I solved with this:
Collections.sort(data, new Comparator<ArrayList<String>>() {
#Override
public int compare(ArrayList<String> one, ArrayList<String> two) {
// Replacements for using Double.parseDouble(string) later
String value1 = one.get(1).replace(",", ".");
String value2 = two.get(1).replace(",", ".");
if (Double.parseDouble(value1) < Double.parseDouble(value2))
return -1;
else if (Double.parseDouble(value1) > Double.parseDouble(distanza2))
return 1;
else
return 0;
}
});

List with fast contains

I wonder if there's a List implementation allowing fast contains. I'm working with quite a long List and I can't switch to Set since I need the access by index. I can ignore the performance, which may be acceptable now and may or may not be acceptable in the future. I can create a HashSet and do all modifying operations on both, but doing it manually is quite boring and error prone.
I know that it's impossible to have a class working like both List and Set (because of the different equals semantics), but I wonder if there's List implementing RandomAccess and employing an HashSet for speeding up contains.
I know that it's impossible to have a class working like both List and Set
Have you tried LinkedHashSet? Technically it's a set but it preserves order which might be just enough for you. However access by index is linear and not built-in.
Other approach would be to wrap List with a custom decorator that both delegates to List and maintains a n internalSet for faster contains.
you can wrap a list and hashSet that combines best of both worlds
public class FastContainsList<T> extends AbstractSequentialList<T> implements RandomAccess{
//extending sequential because it bases itself of the ListIterator(int) and size() implementation
private List<T> list=new ArrayList<T>();
private Set<T> set=new HashSet<T>();
public int size(){
return list.size();
}
public boolean contains(Object o){//what it's about
return set.contains(o);
}
public ListIterator<T> listIterator(int i){
return new ConIterator(list.listIterator(i));
}
/*for iterator()*/
private ConIterator implements ListIterator<T>{
T obj;
ListIterator<T> it;
private ConIterator(ListIterator<T> it){
this.it = it
}
public T next(){
return obj=it.next();
}
public T previous(){
return obj=it.previous();
}
public void remove(){
it.remove();//remove from both
set.remove(obj);
}
public void set(T t){
it.set(t);
set.remove(obj);
set.add(obj=t);
}
public void add(T t){
it.add(t);
set.add(t);
}
//hasNext and hasPrevious + indexes still to be forwarded to it
}
}
What about a BiMap<Integer, MyClass>? This can be found in Guava
BiMap<Integer, MyClass> map = HashBiMap.create();
//store by index
map.put(1, myObj1);
//get by index
MyClass retrievedObj = map.get(1);
//check if in map
if ( map.containsValue(retrievedObj) ) {
//...
}
I know it doesn't implement the List interface. The major limitation here is that insertion and removal are not provided in the traditional List sense; but you didn't specifically say whether those were important to you.
Apache Commons TreeList should do the trick:
http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/list/TreeList.html
You can maintain a List and Set. This will give you fast indexed lookup and contains (with a small overhead)
BTW: If your list is small, e.g. 10 entries, it may not make any difference to use a plain List.
I think a class that wraps a HashMap and List (as you said in your post) is probably the best best for fast contains and access.

Define a fixed-size list in Java

Is it possible to define a list with a fixed size that's 100? If not why isn't this available in Java?
This should do it if memory serves:
List<MyType> fixed = Arrays.asList(new MyType[100]);
A Java list is a collection of objects ... the elements of a list. The size of the list is the number of elements in that list. If you want that size to be fixed, that means that you cannot either add or remove elements, because adding or removing elements would violate your "fixed size" constraint.
The simplest way to implement a "fixed sized" list (if that is really what you want!) is to put the elements into an array and then Arrays.asList(array) to create the list wrapper. The wrapper will allow you to do operations like get and set, but the add and remove operations will throw exceptions.
And if you want to create a fixed-sized wrapper for an existing list, then you could use the Apache commons FixedSizeList class. But note that this wrapper can't stop something else changing the size of the original list, and if that happens the wrapped list will presumably reflect those changes.
On the other hand, if you really want a list type with a fixed limit (or limits) on its size, then you'll need to create your own List class to implement this. For example, you could create a wrapper class that implements the relevant checks in the various add / addAll and remove / removeAll / retainAll operations. (And in the iterator remove methods if they are supported.)
So why doesn't the Java Collections framework implement these? Here's why I think so:
Use-cases that need this are rare.
The use-cases where this is needed, there are different requirements on what to do when an operation tries to break the limits; e.g. throw exception, ignore operation, discard some other element to make space.
A list implementation with limits could be problematic for helper methods; e.g. Collections.sort.
FixedSizeList
Yes,
The Apache Commons library provides the FixedSizeList class which does not support the add, remove and clear methods (but the set method is allowed because it does not modify the List's size). Ditto for FixedSizeList in Eclipse Collections. If you try to call one of these methods, your list remains the same size.
To create your fixed size list, just call
List<YourType> fixed = FixedSizeList.decorate(Arrays.asList(new YourType[100]));
You can use unmodifiableList if you want an unmodifiable view of the specified list, or read-only access to internal lists.
List<YourType> unmodifiable = java.util.Collections.unmodifiableList(internalList);
Yes. You can pass a java array to Arrays.asList(Object[]).
List<String> fixedSizeList = Arrays.asList(new String[100]);
You cannot insert new Strings to the fixedSizeList (it already has 100 elements). You can only set its values like this:
fixedSizeList.set(7, "new value");
That way you have a fixed size list. The thing functions like an array and I can't think of a good reason to use it. I'd love to hear why you want your fixed size collection to be a list instead of just using an array.
Typically an alternative for fixed size Lists are Java arrays. Lists by default are allowed to grow/shrink in Java. However, that does not mean you cannot have a List of a fixed size. You'll need to do some work and create a custom implementation.
You can extend an ArrayList with custom implementations of the clear, add and remove methods.
e.g.
import java.util.ArrayList;
public class FixedSizeList<T> extends ArrayList<T> {
public FixedSizeList(int capacity) {
super(capacity);
for (int i = 0; i < capacity; i++) {
super.add(null);
}
}
public FixedSizeList(T[] initialElements) {
super(initialElements.length);
for (T loopElement : initialElements) {
super.add(loopElement);
}
}
#Override
public void clear() {
throw new UnsupportedOperationException("Elements may not be cleared from a fixed size List.");
}
#Override
public boolean add(T o) {
throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
}
#Override
public void add(int index, T element) {
throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
}
#Override
public T remove(int index) {
throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
}
#Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
}
#Override
protected void removeRange(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
}
}
Create an array of size 100. If you need the List interface, then call Arrays.asList on it. It'll return a fixed-size list backed by the array.
If you want some flexibility, create a class that watches the size of the list.
Here's a simple example. You would need to override all the methods that change the state of the list.
public class LimitedArrayList<T> extends ArrayList<T>{
private int limit;
public LimitedArrayList(int limit){
this.limit = limit;
}
#Override
public void add(T item){
if (this.size() > limit)
throw new ListTooLargeException();
super.add(item);
}
// ... similarly for other methods that may add new elements ...
You can define a generic function like this:
#SuppressWarnings("unchecked")
public static <T> List<T> newFixedSizeList(int size) {
return (List<T>)Arrays.asList(new Object[size]);
}
And
List<String> s = newFixedSizeList(3); // All elements are initialized to null
s.set(0, "zero");
s.add("three"); // throws java.lang.UnsupportedOperationException
This should work pretty nicely. It will never grow beyond the initial size. The toList method will give you the entries in the correct chronological order. This was done in groovy - but converting it to java proper should be pretty easy.
static class FixedSizeCircularReference<T> {
T[] entries
FixedSizeCircularReference(int size) {
this.entries = new Object[size] as T[]
this.size = size
}
int cur = 0
int size
void add(T entry) {
entries[cur++] = entry
if (cur >= size) {
cur = 0
}
}
List<T> asList() {
List<T> list = new ArrayList<>()
int oldest = (cur == size - 1) ? 0 : cur
for (int i = 0; i < this.entries.length; i++) {
def e = this.entries[oldest + i < size ? oldest + i : oldest + i - size]
if (e) list.add(e)
}
return list
}
}
FixedSizeCircularReference<String> latestEntries = new FixedSizeCircularReference(100)
latestEntries.add('message 1')
// .....
latestEntries.add('message 1000')
latestEntries.asList() //Returns list of '100' messages
If you want to use ArrayList or LinkedList, it seems that the answer is no. Although there are some classes in java that you can set them fixed size, like PriorityQueue, ArrayList and LinkedList can't, because there is no constructor for these two to specify capacity.
If you want to stick to ArrayList/LinkedList, one easy solution is to check the size manually each time.
public void fixedAdd(List<Integer> list, int val, int size) {
list.add(val);
if(list.size() > size) list.remove(0);
}
LinkedList is better than ArrayList in this situation. Suppose there are many values to be added but the list size is quite samll, there will be many remove operations. The reason is that the cost of removing from ArrayList is O(N), but only O(1) for LinkedList.
The public java.util.List subclasses of the JDK don't provide a fixed size feature that doesn't make part of the List specification.
You could find it only in Queue subclasses (for example ArrayBlockingQueue, a bounded blocking queue backed by an array for example) that handle very specific requirements.
In Java, with a List type, you could implement it according to two scenarios :
1) The fixed list size is always both the actual and the maximum size.
It sounds as an array definition. So Arrays.asList() that returns a fixed-size list backed by the specified array is what you are looking for. And as with an array you can neither increase nor decrease its size but only changing its content. So adding and removing operation are not supported.
For example :
Foo[] foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput);
foos.add(new Foo()); // throws an Exception
foos.remove(new Foo()); // throws an Exception
It works also with a collection as input while first we convert it into an array :
Collection<Foo> foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput.toArray(Foo[]::new)); // Java 11 way
// Or
List<Foo> foos = Arrays.asList(foosInput.stream().toArray(Foo[]::new)); // Java 8 way
2) The list content is not known as soon as its creation. So you mean by fixed size list its maximum size.
You could use inheritance (extends ArrayList) but you should favor composition over that since it allows you to not couple your class with the implementation details of this implementation and provides also flexibility about the implementation of the decorated/composed.
With Guava Forwarding classes you could do :
import com.google.common.collect.ForwardingList;
public class FixedSizeList<T> extends ForwardingList<T> {
private final List<T> delegate;
private final int maxSize;
public FixedSizeList(List<T> delegate, int maxSize) {
this.delegate = delegate;
this.maxSize = maxSize;
}
#Override protected List<T> delegate() {
return delegate;
}
#Override public boolean add(T element) {
assertMaxSizeNotReached(1);
return super.add(element);
}
#Override public void add(int index, T element) {
assertMaxSizeNotReached(1);
super.add(index, element);
}
#Override public boolean addAll(Collection<? extends T> collection) {
assertMaxSizeNotReached(collection.size());
return super.addAll(collection);
}
#Override public boolean addAll(int index, Collection<? extends T> elements) {
assertMaxSizeNotReached(elements.size());
return super.addAll(index, elements);
}
private void assertMaxSizeNotReached(int size) {
if (delegate.size() + size >= maxSize) {
throw new RuntimeException("size max reached");
}
}
}
And use it :
List<String> fixedSizeList = new FixedSizeList<>(new ArrayList<>(), 3);
fixedSizeList.addAll(Arrays.asList("1", "2", "3"));
fixedSizeList.add("4"); // throws an Exception
Note that with composition, you could use it with any List implementation :
List<String> fixedSizeList = new FixedSizeList<>(new LinkedList<>(), 3);
//...
Which is not possible with inheritance.
You need either of the following depending on the type of the container of T elements you pass to the builder (Collection<T> or T[]):
In case of an existing Collection<T> YOUR_COLLECTION:
Collections.unmodifiableList(new ArrayList<>(YOUR_COLLECTION));
In case of an existing T[] YOUR_ARRAY:
Arrays.asList(YOUR_ARRAY);
Simple as that
To get a fixed-size list, you can simply use the Stream API. This will result in a fixed-size list :
List<Integer> list = Arrays.stream(new int[100])
.boxed()
.collect(Collectors.toList());
Or the old-fashioned way, This will result in a fixed-size list that is backed by the specified array:
List<Integer> list = Arrays.asList(new Integer[100]);
Yes is posible:
List<Integer> myArrayList = new ArrayList<>(100);
now, the initial capacity of myArrayList will be 100

Categories