Java: Priority Queue implementation iterable in proper order - java

I'm looking for some implementation of PQ in Java which allows iteration in PQ order - top element first, next one next etc. I tried using TreeSet (which implements NavigableSet) but it causes one problem. In my case:
I'm using Comparator for my objects
priority changes due to some external actions
if priority changes I know for which object, but I don't know it's previous priority
As a result to the last point - I can't find my element in TreeSet when I would like to update its priority:/
Do you happen to know: smart way to obey this? or some implementation of PQ that is iterable in "good" way? or should I create some linked data structure that will match objects with their positions in tree ?
UPDATE:
concurrency is not an issue
object can't be removed from TreeSet because it's priority changed so Comparator will evaluate differently and object won't be found in this data structure. Inserting is not a problem.
I can't use compareTo method as this priority is not proper way to compare those objects. That is why I need to use Comparator
POSSIBLE SOLUTION:
create class PrioritizedObject which will be compared by priority and keep my object
use map: my object -> PrioritizedObject
keep PrioritizedObject in some NavigableSet
I would use this map to remove objects from NavigableSet. And of course update it with new elements if I add something.
Problem is that I will have to wrap iterator from this NavigableSet to get iterator returning my objects.
Is there any better solution?

if priority changes I know for which object, but I don't know it's previous priority
You don't need to know its previous priority. All you have to do is remove it and re-insert it.

If concurrency is not an issue all you need to do is to reorder the tree right after updating an element's priority. If I understood the problem right, this sketch should suit you.
Example element:
public class Element implements Comparable<Element> {
private final Integer id;
private Integer priority;
public Element(Integer id, Integer priority) {
this.id = id;
this.priority = priority;
}
#Override
public String toString() {
return "Element{" + "id=" + id + ", priority=" + priority + '}';
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
#Override
public int compareTo(Element o) {
if (o == null) {
throw new NullPointerException();
}
return priority.compareTo(o.priority);
}
}
The sketch:
public class Tree {
public static TreeSet<Element> priorityQueue = new TreeSet<Element>();
public static void dump(TreeSet<Element> in) {
for (Element e : in) {
System.out.println(e);
}
}
public static void updatePriority(Element e, int newPriority) {
if (priorityQueue.remove(e)) {
e.setPriority(newPriority);
priorityQueue.add(e);
}
}
public static void main(String[] args) {
int id;
Element lastElement = null;
for (int i = 0;i < 10 ; i++) {
id = (int)(Math.random()*1000);
priorityQueue.add(lastElement = new Element(id, id));
}
dump(priorityQueue);
updatePriority(lastElement, 0);
System.out.println("updating "+lastElement+ " priority to 0");
dump(priorityQueue);
}
}
You update the element by removing it from the treeset, setting the new priority and then reinserting it. The complexity of the update operation with this scenario is 2*O(log(n)) = O(log(n))
UPDATE:
The best I could understand is: you have two criterias upon which you need to sort/index. When I had the same problem I used this approach but this is a very interesting approach that I strongly recommend reading.

I recommend ConcurrentSkipListSet instead of TreeSet since it's thread-safe. If you know the object whose priority is changing, you can call remove(objToChange), change its priority, then re-add it to the set.
Be very careful adding to a set any objects whose equals, hashcode, and compareTo methods depend on mutable fields.
Edit: I think any solution will end up looking like your PrioritizedObject which seems fine to me. If you want to iterate through your objects, use Map.keySet.

Related

How to calculate the element total change times in an ArrayList

the scenario is I have a class as below,
#Data
class Operation
{
private String id;
private String name;
private String description;
}
and an ArrayList which contains lots of Operation instances.
For example, there're five instance in the ArrayList,
{"id":"0001", "name":"up"}
{"id":"0002", "name":"down"}
{"id":"0003", "name":"left"}
{"id":"0004", "name":"left"}
{"id":"0005", "name":"up"}
I want to know how many times the name changed in the ArrayList, in this case, the second name is down, it is different with the first one, the change times is 1, the third name is also different with the sceond name, then the change times is 2, but the fourth name as same as the third one, so the change times is still 2, the fifth is different with the fourth, so the change times of this ArrayList is 3.
Is there a way to calculate it without traverse the ArrayList?
List<Operation> operations = List.of(
new Operation("0001", "up"),
new Operation("0002", "down"),
new Operation("0003", "left"),
new Operation("0004", "left"),
new Operation("0005", "up"));
// Don’t include index 0 since it has no previous name to compare with
long numberOfNameChanges = IntStream.range(1, operations.size())
.filter(i -> ! operations.get(i - 1).getName()
.equals(operations.get(i).getName()))
.count();
System.out.println("Count is " + numberOfNameChanges);
Output is:
Count is 3
And it does traverse the list.
For the sake of a complete example I used List.of() (since Java 9) rather than ArrayList, but the stream operation will work just as well with ArrayList too.
I generally say that stream operations don’t work well when operations on more list elements are involved. This seems to be the exception; I find the stream solution just fine myself. If you prefer, you can code it with a loop instead.
PS I’m not very fond of giving working code away when you haven’t shown that much of an effort on your part. Only I found this was easier to explain with code, so I compromised.
Edit
how about we collect set of the values …
No, that won’t work. I give two examples to show you. The simpler one first, I have just removed the final up from your list so there are only 2 value changes:
List<Operation> operations = List.of(
new Operation("0001", "up"),
new Operation("0002", "down"),
new Operation("0003", "left"),
new Operation("0004", "left"));
Set<String> collect = operations.stream()
.map(operation -> operation.name.toLowerCase())
.collect(Collectors.toSet());
System.out.println(collect);
[left, up, down]
Even when I have removed one value change, there are still 3 elements in the set. You may tihnk that you can just subtract 1. Not so. Look at the next and last example:
List<Operation> operations = List.of(
new Operation("0001", "up"),
new Operation("0003", "left"),
new Operation("0002", "up"),
new Operation("0003", "left"),
new Operation("0004", "left"));
Now there are three value changes but only two elements in the set:
[left, up]
And if you subtracted 1, you’d end up with 1.
As you may have realized by now, the problem with the Set approach is it doesn’t take into account when the same name appears again later causing a new value change.
Is there a way to calculate it without traverse the ArrayList?
No.
To look at each value in a list, and compare to the adjacent value, requires traversing the list. There is no magic shortcut.
When you use if(setEvent(index,object)) For exmaple you can make from that event like if(object == "meow) return true; return false;
and if is true it will set if not will not.
You can use abstract class for add events(listener)
public abstract class MyList<Object> {
private ArrayList<Object> list = new ArrayList<>();
public void set(int index,Object object){
if(setEvent(index,object)) list.set(index,object);
}
public void add(Object object){
if(addEvent(object)) list.add(object);
}
public void remove(Object object){
if(removeEvent(object)) list.remove(object);
}
public void remove(int index){
if(removeEvent(index)) list.remove(index);
}
public Object get(int index){
if(getEvent(index)) return list.get(index);
return null;
}
public void clear(){
if(clearEvent()) list.clear();
}
//Abstract
public abstract boolean setEvent(int index, Object object);
public abstract boolean addEvent(Object object);
public abstract boolean removeEvent(Object object);
public abstract boolean removeEvent(int index);
public abstract boolean getEvent(int index);
public abstract boolean clearEvent();
}

How to implement a sorted table (order by a field of the element) by using java TreeSet?

I used TreeSet for this and it works in a per snapshot style. In other words, sort once displays once.
Now, I want to implement a realtime sorted table.
Whenever there is a value change in any elements, the sorted table will be updated accordingly.
To make the sorting work on a per update style, I tried to remove the element and add it to the TreeSet again.
quotes.remove(quote);
quotes.add(quote);
It doesn't work because I have to implement the sorting logic in compareTo() but it breaks the contract for identifying the object which makes the remove() work. TreeSet never call equals() and hashcode() as described in the Java Doc.
Any idea? Please advise.
code:
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String args[]) {
TreeSetTest test = new TreeSetTest();
test.onQuoteUpdate("appl", 1000d);
test.onQuoteUpdate("msft", 2000d);
test.onQuoteUpdate("face", 3000d);
test.printTopStocks();
test.onQuoteUpdate("msft", 5000d);
test.printTopStocks();
}
private Set<Quote> quotes = new TreeSet<Quote>();
public void onQuoteUpdate(String symbol, double turnover) {
final Quote quote = new Quote(symbol, turnover);
quotes.remove(quote);
quotes.add(quote);
}
public void printTopStocks() {
System.out.println("--Top Stocks By Turnover--");
for (final Quote quote : quotes) {
System.out.println(quote);
}
}
public static class Quote implements Comparable<Quote> {
private String symbol;
private double turnover;
public Quote(String symbol, double turnover) {
this.symbol = symbol;
this.turnover = turnover;
}
#Override
public int compareTo(Quote o) {
return Double.compare(o.turnover, turnover);
// return symbol.compareTo(o.symbol);
}
}
}
Update 1:
As proposed I tried this:
public static void main(String args[]) {
TreeMapTest test = new TreeMapTest();
test.onQuoteUpdate("appl", 1000d);
test.onQuoteUpdate("msft", 2000d);
test.onQuoteUpdate("face", 3000d);
test.printTopStocks();
test.onQuoteUpdate("face", 50d);
test.printTopStocks();
}
public int compareTo(Quote o) {
if(o.symbol.equals(symbol)) return 0;
return Double.compare(o.turnover, turnover);
}
The remove() return false which eventually there are four elements (expected 3) in the Set.
--Top Stocks By Turnover--
Quote [symbol=face, turnover=3000.0]
Quote [symbol=msft, turnover=2000.0]
Quote [symbol=appl, turnover=1000.0]
remove symbol face : false
add symbol face : true
--Top Stocks By Turnover--
Quote [symbol=face, turnover=3000.0]
Quote [symbol=msft, turnover=2000.0]
Quote [symbol=appl, turnover=1000.0]
Quote [symbol=face, turnover=50.0]
Update 2:
I tried PriorityQueue and here is the code:
https://code.sololearn.com/cb38Eo036c8y/#java
It doesn't work because PriorityQueue doesn't store elements in order. The ordering only works when you poll element from the Queue.
Update 3:
Tried user54321's suggestion that by using a custom collection(see below answer). However, it doesn't look good if there are two more elements having the same value of 'turnover'.
My requirement is a very ordinary one. It seems that none of a collection from JDK fits my case.
Update 4:
The solution from user54321 fits for my interim need.
https://code.sololearn.com/c14Ybab7AOFm/#java
Deleted my previously added answer. Looks like a wrong data structure is being used for the scenario.
Here is why.
When an item is being added or removed, TreeSet does a binary search through the available elements using compareTo().
In your case,
After adding first 3 elements, set looks like this.
[{appl, 1000d}, {msft, 2000d}, {face, 3000d}]
Now when you try to remove the element {face, 50d},
It starts searching at {msft, 2000d},
From compareTo() result it determines {face, 50d} should come before {msft, 2000d}.
And continues to search towards start of the elements ( checking with {appl, 1000d} next).
Since the search doesn't find {face, 3000d}, that element remains without being removed.
Next when you add the element {face,50}, similar search happens and since the search does not find {face, 3000},
It adds {face, 50} to the beginning.
Now the set looks like this.
[{face, 50}, {appl, 1000d}, {msft, 2000d}, {face, 3000d}]
Now the problem here is that compareTo() isn't capable of considering both symbol and turnover for a sensible sorting.
TreeSet can be used for getting a sorted collection of unique elements.
If you need to get a sorted collection of different objects with a particular sorting criteria, in this case turnover value, you can use a PriorityQueue
Update: Using a List and a Set in custom data structure
The problem here is that we have to maintain two conditions.
1. Symbol has to be unique
2. Collection should be sorted by turnover value
compareTo() in Quote can check one at a time and not both.
So in this case we may have to go for a custom data structure.
First use only turnover in compareTo();
#Override
public int compareTo(Quote o) {
return Double.compare(o.turnover, turnover);
}
Then implement the custom data structure.
Note that we are using a HashSet to keep track of the symbol alone.
Using a list so that duplicate turnover values can be kept.
static class QuoteCollection {
Set<String> symbols = new HashSet<>();
List<Quote> quotes = new LinkedList<>();
public void onQuoteUpdate(Quote q) {
if (symbols.contains(q.getSymbol())) {
// this requires quotes.equals() to be implemented
quotes.remove(q);
} else {
symbols.add(q.getSymbol());
}
insertToCollection(q);
}
// inserting at correct position to remain sorted
private void insertToCollection(Quote q) {
int index = Collections.binarySearch(quotes, q);
if (index < 0)
index = ~index; // bitwise compliment to find insert position if it is not available in the list
quotes.add(index, q);
}
public List<Quote> getQuotes() {
return quotes;
}
}
Then use it in the main(). Note that printTopStocks() has been changed a little.
public static void main(String args[]) {
Main test = new Main();
QuoteCollection quoteCollection = new QuoteCollection();
quoteCollection.onQuoteUpdate(new Quote("appl", 1000d));
quoteCollection.onQuoteUpdate(new Quote("msft", 2000d));
quoteCollection.onQuoteUpdate(new Quote("face", 3000d));
test.printTopStocks(quoteCollection.getQuotes());
quoteCollection.onQuoteUpdate(new Quote("face", 50d));
test.printTopStocks(quoteCollection.getQuotes());
}
public void printTopStocks(List<Quote> quotes) {
System.out.println("--Top Stocks By Turnover--");
for (final Quote quote : quotes) {
System.out.println(quote);
}
}
This approach does involve data duplication. However a sorted collection can be maintained at linear time complexity(since it uses 'List.remove()')
Couple of points :
Trying to remove elements even when you are adding it first time.
While updating you are trying to remove new element which does not exist in TreeSet. final Quote quote = new Quote(symbol, turnover); here you are building new element which is Quote("face","50d") which does not exist when you are calling quotes.remove(quote);
Below is the one of the way to solve it, I am hard coding oldQuote to keep it short but you can update it:
public void onAdd(String symbol, double turnover) {
final Quote quote = new Quote(symbol, turnover);
quotes.remove(quote);
quotes.add(quote);
}
public void onQuoteUpdate(String symbol, double turnover) {
final Quote newQuote = new Quote(symbol, turnover);
final Quote oldQuote = new Quote("face", 3000d);
quotes.remove(oldQuote);
quotes.add(quote);
}
public static void main(String args[]) {
TreeSetTest test = new TreeSetTest();
test.onAdd("appl", 1000d);
test.onAdd("msft", 2000d);
test.onAdd("face", 3000d);
test.printTopStocks();
test.onQuoteUpdate("face", 50d);
test.printTopStocks();
}

Java peek next element in hashmap

I have a hashmap with a queue object and I want to peek different objects in the different queue in the order they are located in queue each time i peek an object, typically consumer-producer problem;
public class MainQueue {
public static Map<Integer, SingleQueue> list = new ConcurrentHashMap<>();
public MainQueue() {
}
public Map getQueue() {
return this.list;
}
public void addToMainQueue(SendObject sfo) {
int ohashcode = sfo.hashCode();
if (!list.containsKey(ohashcode)) {
list.put(ohashcode, new SingleQueue());
list.get(ohashcode).addQueue(sfo);
} else {
list.get(ohashcode).addQueue(sfo);
}
}
public SendObject getFromQueue() {
???
return TempFax;
}
}
---------HashMap-------------
423532,queue1:{1,2,3,4,5,6,7,8,9}
564898,queue2:{a,b,c,d,e}
039894,queue3:{x,y,z}
When I call getFromQueue function, it should return '1'
after I call, return 'a'
after I call, return 'x'
finally= 1,a,x,2,b,y,3,c,z,4,d,5,e,6,7,8,9
How can I do this?
Based on your question you are interested in retrieving those elements in a FIFO order and you need some way to group them into hashcodes.
I suggest adding those SendObject into a single queue like LinkedList<SendObject>, this way you can poll() those elements one by one.
If you need to have some way to group different items into categories (or hashcodes in your case), you can add a Category field for example in SendObject so you can keep track of those.

Comparator class implementation for priority queue used in Dijkstra's Algorithm?

I'm trying to implement Dijsktra's Algorithm from CLRS - Introduction to Algorithms book,however, i'm having trouble about implementing a priority queue with Comparator interface. This is my Vertex class as you can see;
public class Vertex {
public boolean explored;
public int vertexID;
public LinkedList<Vertex> adjacencyList;
public LinkedList<Edge> edgeSet;
public int shortestDistance;
public Vertex predecessor;
public Vertex(int vertexID){
this.vertexID = vertexID;
this.explored = false;
this.adjacencyList = new LinkedList<>();
this.edgeSet = new LinkedList<>();
this.shortestDistance = Integer.MAX_VALUE;
this.predecessor = null;
}
}
So initially shortestDistance attribute is declared to Integer.MAX_VALUE. Furthermore, you can see the class which implements from Comparator, is used for priority queue.
public class WeightComparator implements Comparator<Vertex> {
#Override
public int compare(Vertex o1, Vertex o2) {
return Math.min(o1.shortestDistance, o2.shortestDistance);
}
}
I'm sure that the whole implementation doesn't have any logical errors due to my some tests,however, in some tests it fails. I create a reference to my queue with this statement
PriorityQueue<Vertex> queue = new PriorityQueue<>(N, weightComparator);
where N is the size of the queue. So please correct me if i'm wrong about the way how it works. When you poll an item from it, it will remove the item which has least priority ?. Hope it had been clear to understand my problem, and i will appreciate a lot if anyone can help about this. So thanks anyway
Math.min gives you the smaller of two values. Returning that as a compare value is wrong.
A compare return value of <0 means the first value is smaller than the second, but if you return Math.Min(5, 3), you will get 3, which is >0, which means that the comparator will tell it that 3 > 5. Which is wrong.
What you are looking for is:
public int compare(Vertex o1, Vertex o2) {
return Integer.compare(o1.shortestDistance, o2.shortestDistance);
}
Unless shortestDistance can be negative, your comparator can never return a negative number. It is therefore not a correct implementation.
Conceptually, a comparator for primitives should return a subtraction:
return o1.shortestDistance-o2.shortestDistance;
or the other way around if you want descending. But you need to beware of overflow issues.

Insert in a sorted Array-Queue

I'm working on sorted Queues like a Priority Queue. I already did it with a List, and it already worked great. Now I'd like to do it with a array. But I have a little logical Problem with add a new Element and insert it into the sorted array.
The final output should be like that:
Priority: 5 Value: x
Priority: 4 Value: iso
.... (and so on)
So the Element with the highest Priorithy should be on index = 0.
I just don't know (and yes I know it's really simply to switch it, but I just can't do it :/) how to do it...
I already tried a few things but I'm stuck... :/ can please anyone help?
Here's my code:
public class Queue {
private QueueElem[] a;
public Queue(int capacity)
{
QueueElem[] tempQueue = new QueueElem[capacity];
a= tempQueue;
}
public void enqueue(int p, String v)
{
QueueElem neu = new QueueElem(p,v);
int i=0;
while(i<a.length)
{
if (a[i] == null)
{
a[i] = neu;
break;
}
i++;
}
}
public void writeQueue()
{
int i=0;
while((i< a.length) && (a[i] != null))
{
System.out.println("Priority: " + a[i].priority + " Value: " + a[i].value);
i++;
}
}
public static void main(String args[])
{
Queue neu = new Queue(10);
neu.enqueue(4,"iso");
neu.enqueue(2,"abc");
neu.enqueue(5,"x");
neu.enqueue(1,"abc");
neu.enqueue(4,"bap");
neu.enqueue(2,"xvf");
neu.enqueue(4,"buep");
}
}//end class Queue
class QueueElem {
int priority;
String value = new String();
public QueueElem(){ }
public QueueElem(int p, String v)
{
this.priority = p;
this.value = v;
}
public int getPrio()
{
return this.priority;
}
public String getValue()
{
return this.value;
}
}
It would be better if you interpreted your array as a max-heap. That is the typical way to implement priority queue.
What you're looking for, if you're trying to maintain a sorted array for your priority queue, is to implement insertion sort (sort of; you don't have an unsorted array to start with. You have an empty array that you simply add to, while maintaining a sorted order). Every time you insert a new element, you will iterate through the array to find the correct spot and then insert it there, after shifting the elment currently at that spot, and everything after it one spot down. Note that this is not as performant as implementing this using a heap, since at worst you have O(n) performance every time you insert, whereas with a heap you have O(logn).
I don't understand why anyone would want to work with raw arrays... especially now that you have implemented it with a List.
If you want to see how to insert an element in a raw array, look in the code of ArrayList, since underneath it uses a raw array. You'll have to move all the elements to right of the insertion point, which you could copy in a loop, or by using System.arraycopy(). But the nastiest part is that you will likely have to create a new array since the array size increases by one when you add an element (it depends if you are using an array that has exactly the size of your data, or a larger array, as is done in ArrayList).

Categories

Resources