Can't add objects to priority queue - java

I need to add a Jedi object to a queue. None of the add methods that I know are working and all give the "cannot find symbol - method add(jedi1).I didn't learn much about Queues in my last class so I'm not exactly sure what I'm doing. Other things to note are 3 specifics of this.
1)Modify the heap operations to keep the maximum – rather than the minimum – element in the root. Refer to the Heap lab assignment for the algorithm.
2) Utilize an array with a varying size limit (if <10% utilization reduce it by half; if full, double the size).
3) Implement the heap to receive any generic object with a comparable method.
4) Allow for duplicate value with the following rule: If a duplicate value is entered, the new element with similar value should be considered to have less priority than an existing element.
public class PriorityQueue<JediQ>
{
Scanner reader = new Scanner(System.in);
public void main(String[] args)
{
while (true)
{
System.out.println("Please select an option");
System.out.println("1 - Add a Jedi ");
System.out.println("2 - Remove an element");
System.out.println("3 - Print head value");
System.out.println("4 - Compare value to head value");
System.out.println("5 - Print Array");
System.out.println("6 - Exit");
int x = 0;
x = reader.nextInt();
if (x == 1)
{
PriorityQueue<JediQ> line = new PriorityQueue<JediQ>();
System.out.println("Enter the name of the Jedi");
String Name = reader.next();
System.out.println("Enter the midi count");
double midi = reader.nextInt();
Jedi jedi1 = new Jedi(Name, midi);
line.add(jedi1);
System.out.print("Jedi was added");
}
if (x == 6)
{
System.exit(0);
}
}
}
}

Your problem is a vast lack of basic knowledge about everything; so I give you some things to start with:
First of all, that error message means: your implementation of that PriorityQueue ... does not have an add() method. Because: you didn't write it! So you start with something like:
public class PriorityQueue<T> {
public void add(T newElement) { ...
Which leads to the second major problem: the usage of generic types. As you can see in my example, you say: "my queue class, should be accepting any kind of object". And only later on, when instantiating a queue object; then you declare that this instance should be for Jedis, like:
PriorityQueue<Jedi> jedis = new PriorityQueue<>();
jedies.add(lukeSkywalkerHisUnknownCousin);
But of course, the real fun within this exercise is the implementation of a priority queue, so that it provides all the methods that a queue should have; and that they work as outlined in your assignment! And obviously, that is your assignment, so I leave that as exercise to the reader!
Final hint: if you want to understand the methods you ought to implement, you can have a look at java's own PriorityQueue and its methods!

Use below method.
line.offer(yourObject);
Please read the basics of collections framework. You able to add/ modify / delete objects out of any collections because the wrapper classes have provided the methods for that.
For eg. When you add int ( that becomes Integer as collection only stores Object). the default Comparator is used. as below:
public class PriorityQueueExample
{
public static void main(String[] args)
{
//Creating a PriorityQueue with default Comparator.
PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>();
//Inserting elements into pQueue.
pQueue.offer(21);
pQueue.offer(17);
//Removing the head elements
System.out.println(pQueue.poll());
To add custom objects in any collection you need to use either Comparator or Comparable.
class JediQ
{
String name;
int midi;
//Constructor Of JediQ
public JediQ(String name, int midi)
{
this.name = name;
this.midi = midi;
}
#Override
public String toString()
{
return name+" : "+midi;
}
}
and then adding the object as below:
class MyComparator implements Comparator<JediQ>
{
#Override
public int compare(JediQ e1, JediQ e2)
{
return e1.name - e2.name;
}
}
MyComparator comparator = new MyComparator();
PriorityQueue<JediQ> pQueue = new PriorityQueue<JediQ>(7, comparator);
pQueue.offer(new JediQ("AAA", 150));

Related

Need advise on how to print the remaining capacity of ArrayList

I'm trying to figure out how I can get an output of remaining slots available when 1 object is removed.
ListOfMembers = new ArrayList<>(100); which caps my list at 100.
Whenever I delete 1 from the list, I need to print out the remaining space in the ArrayList.
public boolean DeleteMember() {
Scanner in = new Scanner(System.in);
System.out.println("Enter the membership number: ");
String pno = in. nextLine();
for(int i=0;i<ListOfMembers.size();++i) {
if(ListOfMembers.get(i).getMembershipNumber().equals(pno)) {
ListOfMembers.remove(i);
System.out.println("Space available: " +?????);
return true;
}
}
System.out.println("Numbership number does not exist");
return false;
}
Using System.out.println("Space available: " +ListOfMembers.size()) will provide the count of entries and I'm trying to have the opposite.
You seem to misunderstand how arraylist works.
new ArrayList<>(100) does not cap the list. The 100 is merely a hint.
ArrayList is defined as allowing infinite* growth, and it has no facilities to limit how many items can be in them.
ArrayList works 'under the hood' by having an array that holds your elements. The problem is, java does not allow arrays to grow or shrink. ArrayList solves this problem with two tricks:
By keeping track of the length of the ArrayList internally, the ArrayList impl can use an array that is 'too large'.
If you've filled up your arraylist to have as many items in it as the 'backing array is large', and you add another item, arraylist has a problem - the backing array is out of room. ArrayList will then make a new, larger array, copy over all the elements from the old array, now add the new item (as there is room; this new array is larger), and then get rid of the old array.
The only thing that 100 does in your constructor is serve as a hint: How large should the backing array be made initially. Out of the box (just new ArrayList<>()), you get the default hint of 10.
Try it! run this:
List<String> list = new ArrayList<String>(100);
for (int i = 0; i < 200; i++) list.add("" + i);
System.out.println(list.size());
That code will compile fine, run fine, and print 200. Thus proving that the '100' has absolutely nothing to do with capping the size of this list.
So, how DO you cap a size of an arraylist?
You don't. Arraylist cannot do that. Instead, you wrap, or extend. For serious code bases, I strongly recommend wrapping, but for a simple exercise, extending can make your code a little shorter:
public class LimitedList<T> extends ArrayList<T> {
private final int limit;
public LimitedList(int limit) {
this.limit = limit;
}
#Override public boolean add(T in) {
if (size() >= limit) throw new IllegalStateException("List is full");
super.add(in);
}
#Override public boolean addAll(Collection<T> in) {
// left as an exercise for the reader
}
#Override public boolean addAll(int index, Collection<T> in) {
// left as an exercise for the reader
}
#Override public boolean add(int idx, T in) {
// left as an exercise for the reader
}
#Override public List<T> subList(int from, int to) {
// this one gets complicated!
// let's just not allow it.
throw new UnsupportedOperationException();
}
public int available() {
return limit - size();
}
}
NB: As you can see, you have to be very careful and override every method that may grow the list; this is why making a new type that doesn't extend ArrayList at all, and instead has 1 field of type ArrayList (and 1 field of int for the limit, of course), can be better: Now you explicitly have to think about every method list has, instead of praying you covered all the ones that add things.
*) well, pragmatically speaking, you can't have more than 2^31-1 elements.
Reading the specification of List, it says that implementations can simply not implement add; or refuse to add elements based on type, or some property of the element; but it doesn't say that a list can refuse to add an element based on the list's current size. Placing a cap on the size thus violates Liskov Substitutability.
You can define a LimitedSizeList implements Collection, but it can't be a true implementation of java.util.List.
You can easily implement LimitedSizeList by extending AbstractCollection:
class LimitedSizeList<E> extends AbstractCollection<E> {
private final List<E> list = new ArrayList<>();
private final int capacity;
LimitedSizeList(int capacity) {
this.capacity = capacity;
}
// Fill in the methods described in the Javadoc:
#Override
public Iterator<E> iterator() { return list.iterator(); }
#Override
public int size() { return list.size(); }
#Override
public boolean add(E element) {
// Collection.add does allow you to throw an IllegalStateException
// https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#add-E-
if (remainingCapacity() <= 0) throw new IllegalStateException("Full");
return list.add(element)
}
// You don't have to, but you might want to consider overriding
// addAll, in order to make trying to add too-large a collection
// failure atomic (that is, it fails to add any rather than some).
// And then provide a method to report the free capacity:
int remainingCapacity() {
return capacity - size();
}
}
This is a far cleaner way to approach the problem than attempting to extend ArrayList (not just because of the contract violation, but also for all the reasons to prefer composition over inheritance).
Of course, if you really want it to be an invalid List (or you can guarantee that it won't need to be treated as a general-purpose List), you can instead extend AbstractList: the methods you need to implement are different, but there are relatively few, and they're quite easy. However, violating contracts is a good way to get surprising bugs in surprising places in your code.
Capacity is an internal metric that is used to dynamically increase the available space used by the ArrayList<>() Usually, it is of no consequence to the user how this is managed since it is an internal issue.
However, being able to set the capacity allows the user to specify a value indicative of the initial contents that the list will hold. The advantage is that it allows the list to fill the backing array without having to continually readjust the capacity resulting in a lot of copying of objects.
Adjust capacity
At any time you can also increase the capacity by using the ensureCapacity() method.
Reduce capacity
And you can also release unused capacity by using trimToSize() method. This may free up memory within the JVM.
But none of the above will prevent you from adding addtional entries to the list. They simply allow one to make optimum choices based on a priori knowledge of the data.
You can use reflection to achieve this task to get the capacity first, then subtract the actual size
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("h");
try {
Field field = list.getClass().getDeclaredField("elementData");
field.setAccessible(true);
int cap = Array.getLength(field.get(list));
System.out.println("The capacity: " + cap);
System.out.println("The size: " + list.size());
System.out.println("The remaining capacity: " + (cap - list.size()));
} catch (Exception e) {
e.printStackTrace();
}
}
, output
The capacity: 10
The size: 6
The remaining capacity: 4

Sorting Student names

im having a trouble finishing my work because i dont know how to do the sorting of names together with the grade in ascending and descending. i hope you guys can help.
import java.util.Scanner;
public class SortingStudents {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Enter the number of students: ");
int capacity = s.nextInt();
String [] name = new String[capacity];
Double [] grade = new Double[capacity];
for(int i = 0; i < capacity; i++) {
System.out.print("student's name: ");
name [i] = s.next();
System.out.print("grade: ");
grade [i] = s.nextDouble();
}
Scanner input = new Scanner(System.in);
System.out.println("Type A for Ascending D for Descending:");
char a=input.nextLine().charAt(0);
if(a == 'A' || a == 'a'){
for(int i = 0; i<grade.length;i++){
System.out.println(grade[i]+"\t" +grade[i]);
}
}
}
You are using Java, which is an object-oriented programming language. This means you can think about your problem in terms of classes which represent state in your problem domain and have behavior (methods) which manipulate this state.
In this case your code shows several responsabilities, for which you could create useful classes and/or methods:
entering data via the command line (number of students, name and grade and desired sorting direction)
a registry of students with a fixed size
sorting the student registry in the desired direction
Class names that come to mind are: DataEntry, Student, StudentRegistry. For sorting the students in different ways the standard approach is creating a Comparator class, see below.
The classes could look roughly like this:
public class Student {
private String name;
private Double grade;
// getters and setters ommitted for brevity
}
The registry:
public class StudentRegistry {
// it's easier to use a List because you are adding students one by one
private List<Student> students;
public StudentRegistry(int capacity) {
// ...constructor code initializes an instance of StudentRegistry
}
public void addStudent(Student student) {
// add a student to the list
}
public Student[] getStudents(Comparator<Student> comparator) {
// sort the list using the comparator and Collections.sort()
// use List.toArray() to convert the List to an array
// alternatively (java 8) return a Stream of Students
// or return an unmodifiable List (using Collections.unmodifiableList())
// you don't want to expose your modifiable internal List via getters
}
}
A comparator which can sort Ascending or Descending. You could consider adding the capability to sort either by grades or by names, that would be quite easy.
public class StudentComparator implements Comparator<Student> {
public enum Direction {
ASCENDING, DESCENDING
}
// optional addition:
//public enum Field{
// NAME, GRADE
//}
// if used, add Field parameter to the constructor
public StudentComparator(Direction direction) {
// initialize instance
}
#Override
public int compare(Student a, Student b) {
// implement Comprator method, see JavaDoc
}
#Override
public boolean equals(Object o) {
// implement equals, see JavaDoc
}
}
Class for letting the user enter data:
public class DataEntry {
public int getNumberOfStudents() {
// ...
}
public Student getStudent() {
// ...
}
public StudentComparator.Direction getSortingDirection() {
// ...
}
}
And a main class:
public class Main {
public static void main(String[] args) {
DataEntry dataEntry = new DataEntry();
int capacity = dataEntry.getCapacity();
StudentRegistry studentRegistry = new StudentRegistry(capacity);
for(int i=0; i<= capacity; i++) {
studentRegistry.addStudent(dataEntry.getStudent());
}
StudentComparator comparator = new StudentComparator(dataEntry.getSortingDirection());
Student[] students = studentRegsitry.getStudents(comparator);
}
}
This approach separates concerns of your problem in separate classes and methods, making the code much easier to understand, debug and test.
For example, to test the Main class you could set up a mock DataEntry class which provides predetermined values to your test. See the topic of unit testing.
If you want to do it your way without changing how the arrays are stored separately. You will not be able to use the Arrays.sort() method to sort your grades because that will not take the name array into account and you will lose the link between them so that the grades will no longer match with the names.
You could very quickly code up your own bubble sorter to quickly sort the array, and then you could use your loop to affect the name array at the same time. But if you don't want to code your own sorter, you will need to organise your grades and names array so that can be treated as one unit i.e in a separate class.
If you choose to code your own sorter then here is a great link to learn that: http://www.java-examples.com/java-bubble-sort-example
If you choose to change the way that you store the grades and names, here is how you can use the Arrays.sort() method:
http://www.homeandlearn.co.uk/java/sorting_arrays.html
You could just concatenate the name and grade and sort them, that way it could be a lot easier.

Find Range in which value lies in Java

Suppose, I have an unsorted array of ranges.
For e.g
class CreditRange{
long credits;
int id;
}
Now I want to find, given credit count value belongs to which one of the CreditRange.
Possible Set<CreditRange> of values can be
CreditRange :{id:1,credits:0}
CreditRange :{id:2,credits:100}
CreditRange :{id:3,credits:500}
CreditRange :{id:4,credits:250}
Case 1 : Now when user enters Credits = 50, this range comparator should give
answer as
CreditRange :{id:1,credits:0}
Case 2 : Now when user enters Credits = 300, this range comparator should give
answer as
CreditRange :{id:4,credits:250}
Case 3 : Now when user enters Credits = 600, this range comparator should give
answer as
CreditRange :{id:3,credits:500}
We can assume the ranges array takes ~1M and fits the memory. I am looking for an easy algorithm, which uses only standard JDK collections without any 3d-party libraries and special data structures, but works reasonably fast.
What would you suggest?
I guess, it's not the range you are talking about. Rather you want the largest element that is less than your passed element.
You can follow the below steps to solve the problem:
First implement a Comparator for your class, which compares on the basis of credits
Then, use a TreeSet, passing an instance of that comparator to it's constructor. It will sort the item inside it, as per the comparator.
Then use TreeSet#floor(E) method to get the greatest element which is less than E, as per the comparator. Of course, you have to create an object of CreditRange to search. You can't just search for 300.
Demo code:
NavigableSet<Integer> set = new TreeSet<>();
set.add(0); set.add(100);
set.add(250); set.add(500);
System.out.println(set.floor(50)); // 0
System.out.println(set.floor(300)); // 250
And please rename your class. It is not depicting the range in any manner. It should perhaps be better named as CreditBound as specified by Jon Skeet in comments.
As mentioned by Rohit, one easy method is to use TreeSet floor (another is to implement a a modified variant of Binary search. this is a more complete answer:
package test;
import java.util.TreeSet;
class CreditRange implements Comparable<CreditRange> {
long credits;
int id;
public CreditRange(int id, long credits) {
this.id = id;
this.credits = credits;
}
public CreditRange(long credits) {
this.id = -1;
this.credits = credits;
}
#Override
public int compareTo(CreditRange o) {
return credits < o.credits ? -1 : credits > o.credits ? 1 : 0;
}
#Override
public String toString() {
return "id:" + id + ", credits:" + credits;
}
}
public class Test {
public static void main(String[] args) {
TreeSet<CreditRange> set = new TreeSet<>();
set.add(new CreditRange(1, 0));
set.add(new CreditRange(2, 100));
set.add(new CreditRange(3, 500));
set.add(new CreditRange(4, 250));
System.out.println(set.floor(new CreditRange(50)));
System.out.println(set.floor(new CreditRange(300)));
System.out.println(set.floor(new CreditRange(600)));
}
}

Trying to write priority queue in Java but getting "Exception in thread "main" java.lang.ClassCastException"

For my data structure class, I am trying to write a program that simulates a car wash and I want to give fancy cars a higher priority than regular ones using a priority queue. The problem I am having has something to do with Java not being able to type cast "Object" as an "ArrayQueue" (a simple FIFO implementation). What am I doing wrong and how can I fix it?
public class PriorityQueue<E>
{
private ArrayQueue<E>[] queues;
private int highest=0;
private int manyItems=0;
public PriorityQueue(int h)
{
highest=h;
queues = (ArrayQueue<E>[]) new Object[highest+1]; <----problem is here
}
public void add(E item, int priority)
{
queues[priority].add(item);
manyItems++;
}
public boolean isEmpty( )
{
return (manyItems == 0);
}
public E remove()
{
E answer=null;
int counter=0;
do
{
if(!queues[highest-counter].isEmpty())
{
answer = queues[highest-counter].remove();
counter=highest+1;
}
else
counter++;
}while(highest-counter>=0);
return answer;
}
}
EDIT
Thank you both for the quick answer to this question. I solved the problem by following your advice and one other bit of code:
public PriorityQueue(int h)
{
highest=h;
queues = new ArrayQueue[highest+1];
for(int i = 0; i <= highest; i++)
{
queues[i] = new ArrayQueue();
}
}
An Object is an Object and (in most cases) not an ArrayQueue. So indeed the cast is not possible.
Creation of generic arrays is a problem too, but in your case, this should work:
public PriorityQueue(int h)
{
highest=h;
queues = new ArrayQueue[highest+1]; // Gives an ignorable warning
}
EDIT
The way it is explained in your textbook is incorrect, the book needs a new revision cycle ;) The suggested cast is not allowed in Java, it's like an attempt to do
String forEverUseless = (String) new Object(); // this will not give an empty String
// but an ouch-that-hurts-Exception
which is more obvious. You can never cast a class to one of its subtypes (derived classes). This is true for all classes, including arrays and generic classes.
EDIT 2
Two more suggestions:
The 'add' method should get a check whether 'priority' is in the valid range of priorities, otherwise add will throw an exception (like in: queue.add(entry, -1))
A remove method usually has an argument - you might want to call it with the element that shall be removed from the queue. (Or - if you're intention is something else, i suggest using the common queue operation names pop, push and peek)
The problem is almost exactly what you said -- you're making something of type Object[] and trying to cast it to ArrayQueue[], and those aren't compatible types. You should just do:
queues = new ArrayQueue[highest+1];

How do I use a PriorityQueue?

How do I get a PriorityQueue to sort on what I want it to sort on?
Also, is there a difference between the offer and add methods?
Use the constructor overload which takes a Comparator<? super E> comparator and pass in a comparator which compares in the appropriate way for your sort order. If you give an example of how you want to sort, we can provide some sample code to implement the comparator if you're not sure. (It's pretty straightforward though.)
As has been said elsewhere: offer and add are just different interface method implementations. In the JDK source I've got, add calls offer. Although add and offer have potentially different behaviour in general due to the ability for offer to indicate that the value can't be added due to size limitations, this difference is irrelevant in PriorityQueue which is unbounded.
Here's an example of a priority queue sorting by string length:
// Test.java
import java.util.Comparator;
import java.util.PriorityQueue;
public class Test {
public static void main(String[] args) {
Comparator<String> comparator = new StringLengthComparator();
PriorityQueue<String> queue = new PriorityQueue<String>(10, comparator);
queue.add("short");
queue.add("very long indeed");
queue.add("medium");
while (queue.size() != 0) {
System.out.println(queue.remove());
}
}
}
// StringLengthComparator.java
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String> {
#Override
public int compare(String x, String y) {
// Assume neither string is null. Real code should
// probably be more robust
// You could also just return x.length() - y.length(),
// which would be more efficient.
if (x.length() < y.length()) {
return -1;
}
if (x.length() > y.length()) {
return 1;
}
return 0;
}
}
Here is the output:
short
medium
very long indeed
Java 8 solution
We can use lambda expression or method reference introduced in Java 8. In case we have some String values stored in the Priority Queue (having capacity 5) we can provide inline comparator (based on length of String) :
Using lambda expression
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Using Method reference
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
Then we can use any of them as:
public static void main(String[] args) {
PriorityQueue<String> pq=
new PriorityQueue<String>(5, (a,b) -> a.length() - b.length());
// or pq = new PriorityQueue<String>(5, Comparator.comparing(String::length));
pq.add("Apple");
pq.add("PineApple");
pq.add("Custard Apple");
while (pq.size() != 0)
{
System.out.println(pq.remove());
}
}
This will print:
Apple
PineApple
Custard Apple
To reverse the order (to change it to max-priority queue) simply change the order in inline comparator or use reversed as:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
We can also use Collections.reverseOrder:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
So we can see that Collections.reverseOrder is overloaded to take comparator which can be useful for custom objects. The reversed actually uses Collections.reverseOrder:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
offer() vs add()
As per the doc
The offer method inserts an element if possible, otherwise returning
false. This differs from the Collection.add method, which can fail to
add an element only by throwing an unchecked exception. The offer
method is designed for use when failure is a normal, rather than
exceptional occurrence, for example, in fixed-capacity (or "bounded")
queues.
When using a capacity-restricted queue, offer() is generally preferable to add(), which can fail to insert an element only by throwing an exception. And PriorityQueue is an unbounded priority queue based on a priority heap.
Just pass appropriate Comparator to the constructor:
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
The only difference between offer and add is the interface they belong to. offer belongs to Queue<E>, whereas add is originally seen in Collection<E> interface. Apart from that both methods do exactly the same thing - insert the specified element into priority queue.
from Queue API:
The offer method inserts an element if possible, otherwise returning false. This differs from the Collection.add method, which can fail to add an element only by throwing an unchecked exception. The offer method is designed for use when failure is a normal, rather than exceptional occurrence, for example, in fixed-capacity (or "bounded") queues.
no different, as declare in javadoc:
public boolean add(E e) {
return offer(e);
}
Pass it a Comparator. Fill in your desired type in place of T
Using lambdas (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Classic way, using anonymous class:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
#Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
To sort in reverse order, simply swap e1, e2.
Just to answer the add() vs offer() question (since the other one is perfectly answered imo, and this might not be):
According to JavaDoc on interface Queue, "The offer method inserts an element if possible, otherwise returning false. This differs from the Collection.add method, which can fail to add an element only by throwing an unchecked exception. The offer method is designed for use when failure is a normal, rather than exceptional occurrence, for example, in fixed-capacity (or "bounded") queues."
That means if you can add the element (which should always be the case in a PriorityQueue), they work exactly the same. But if you can't add the element, offer() will give you a nice and pretty false return, while add() throws a nasty unchecked exception that you don't want in your code. If failure to add means code is working as intended and/or it is something you'll check normally, use offer(). If failure to add means something is broken, use add() and handle the resulting exception thrown according to the Collection interface's specifications.
They are both implemented this way to fullfill the contract on the Queue interface that specifies offer() fails by returning a false (method preferred in capacity-restricted queues) and also maintain the contract on the Collection interface that specifies add() always fails by throwing an exception.
Anyway, hope that clarifies at least that part of the question.
In here, We can define user defined comparator:
Below code :
import java.util.*;
import java.util.Collections;
import java.util.Comparator;
class Checker implements Comparator<String>
{
public int compare(String str1, String str2)
{
if (str1.length() < str2.length()) return -1;
else return 1;
}
}
class Main
{
public static void main(String args[])
{
PriorityQueue<String> queue=new PriorityQueue<String>(5, new Checker());
queue.add("india");
queue.add("bangladesh");
queue.add("pakistan");
while (queue.size() != 0)
{
System.out.printf("%s\n",queue.remove());
}
}
}
Output :
india
pakistan
bangladesh
Difference between the offer and add methods : link
As an alternative to using Comparator, you can also have the class you're using in your PriorityQueue implement Comparable (and correspondingly override the compareTo method).
Note that it's generally best to only use Comparable instead of Comparator if that ordering is the intuitive ordering of the object - if, for example, you have a use case to sort Person objects by age, it's probably best to just use Comparator instead.
import java.lang.Comparable;
import java.util.PriorityQueue;
class Test
{
public static void main(String[] args)
{
PriorityQueue<MyClass> queue = new PriorityQueue<MyClass>();
queue.add(new MyClass(2, "short"));
queue.add(new MyClass(2, "very long indeed"));
queue.add(new MyClass(1, "medium"));
queue.add(new MyClass(1, "very long indeed"));
queue.add(new MyClass(2, "medium"));
queue.add(new MyClass(1, "short"));
while (queue.size() != 0)
System.out.println(queue.remove());
}
}
class MyClass implements Comparable<MyClass>
{
int sortFirst;
String sortByLength;
public MyClass(int sortFirst, String sortByLength)
{
this.sortFirst = sortFirst;
this.sortByLength = sortByLength;
}
#Override
public int compareTo(MyClass other)
{
if (sortFirst != other.sortFirst)
return Integer.compare(sortFirst, other.sortFirst);
else
return Integer.compare(sortByLength.length(), other.sortByLength.length());
}
public String toString()
{
return sortFirst + ", " + sortByLength;
}
}
Output:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
I was also wondering about print order. Consider this case, for example:
For a priority queue:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
This code:
pq3.offer("a");
pq3.offer("A");
may print differently than:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
I found the answer from a discussion on another forum, where a user said, "the offer()/add() methods only insert the element into the queue. If you want a predictable order you should use peek/poll which return the head of the queue."
Priority Queue has some priority assigned to each element, The element with Highest priority appears at the Top Of Queue. Now, It depends on you how you want priority assigned to each of the elements. If you don't, the Java will do it the default way. The element with the least value is assigned the highest priority and thus is removed from the queue first. If there are several elements with the same highest priority, the tie is broken arbitrarily. You can also specify an ordering using Comparator in the constructor PriorityQueue(initialCapacity, comparator)
Example Code:
PriorityQueue<String> queue1 = new PriorityQueue<>();
queue1.offer("Oklahoma");
queue1.offer("Indiana");
queue1.offer("Georgia");
queue1.offer("Texas");
System.out.println("Priority queue using Comparable:");
while (queue1.size() > 0) {
System.out.print(queue1.remove() + " ");
}
PriorityQueue<String> queue2 = new PriorityQueue(4, Collections.reverseOrder());
queue2.offer("Oklahoma");
queue2.offer("Indiana");
queue2.offer("Georgia");
queue2.offer("Texas");
System.out.println("\nPriority queue using Comparator:");
while (queue2.size() > 0) {
System.out.print(queue2.remove() + " ");
}
Output:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
Else, You can also define Custom Comparator:
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
#Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
Here is the simple example which you can use for initial learning:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
public class PQExample {
public static void main(String[] args) {
//PriorityQueue with Comparator
Queue<Customer> cpq = new PriorityQueue<>(7, idComp);
addToQueue(cpq);
pollFromQueue(cpq);
}
public static Comparator<Customer> idComp = new Comparator<Customer>(){
#Override
public int compare(Customer o1, Customer o2) {
return (int) (o1.getId() - o2.getId());
}
};
//utility method to add random data to Queue
private static void addToQueue(Queue<Customer> cq){
Random rand = new Random();
for(int i=0;i<7;i++){
int id = rand.nextInt(100);
cq.add(new Customer(id, "KV"+id));
}
}
private static void pollFromQueue(Queue<Customer> cq){
while(true){
Customer c = cq.poll();
if(c == null) break;
System.out.println("Customer Polled : "+c.getId() + " "+ c.getName());
}
}
}

Categories