In my program i have a collection of edges ,they have to be ordered by the weight.
Somewhere in the program i have to process the collection , and each time i have to remove the maximum of the collection.
I have already used an ArrayList but i'm looking for a better solution(time efficiency):
public class Edge implements Comparable<Edge> {
private int weight;
public void setWeight(int weight) {
this.weight = weight;**
}
#Override
public int compareTo(Edge o) {
return o.weight - this.weight;
}
}
what i did :
private ArrayList<Edge> listOfEdges = new ArrayList<>();
// i suppose here adding some edges in the list
Collections.sort(listOfEdges);
for (int i = 0; i < listOfEdges.size(); i++) {
System.out.println(listOfEdges.get(i).getWeight() + " ");
}
how can i get&remove the maximum of the list.
I have tested a treeSet but the edges can have the same weight, So what is the perfect Sorted Collection that accept a duplicate values.
Thank you
In my program i have a collection of edges ,they have to be ordered by the weight... I have already used an ArrayList but i'm looking for a better solution(time efficiency):
A binary tree like structure, such as a heap or priority queue, is what you are looking for. Once you have your object ordering (by the Comparable interface) specified, the maximum can be obtained in O(1) time, and removed in O(log n) time for n edges.
how can i get&remove the maximum of the list.
peek and pop are the respective methods of a queue object implementation
Related
I was trying to implement MST with Priorityqueue with custom comparator, but I am facing problem in building min-heap with it in O(n) time. The problem is only one constructor of Priorityqueue allows to create PriorityQueue in O(n), but it does not take any comparator as argument. I want it to use my custom comparator. Is there workaround for this problem ? PriorityQueue.addAll() will lose the purpose of using Min-heap for MST as it is O(nlogn) method. Here is my code.
ArrayList <edge>ar=new ArrayList<>();
for(int i=0;i<e;i++)
{
int u=ss.nextInt();
int v=ss.nextInt();
int w=ss.nextInt();
ar.add(new edge(u,v,w));
}
PriorityQueue <edge>pr=new PriorityQueue<edge>(ar);
And the comparator that I want to use:-
PriorityQueue <edge>ar=new PriorityQueue(11,new Comparator() {
#Override
public int compare(Object o1, Object o2) {
edge n1=(edge) o1;
edge n2=(edge) o2;
if(n1.w<n2.w)
{
return -1;
}
else if(n1.w==n2.w)
{
if((n1.u+n1.v+n1.w)<=(n2.u+n2.v+n2.w))
{
return -1;
}
else
{
return 1;
}
}
else
{
return 1;
}
}
});
If you have not min-heap-ordered your list elsewhere, you will not be able to new PriorityQueue(...) anything and somehow avoid the hit of creating your heap. The math here says it's O(n) for the average case, but it is still more than just iterating.
PriorityQueue<edge> pr = new PriorityQueue<edge>(ar, comp) {
PriorityQueue(List<edge> ar, Comparator<edge> c) {
this(c);
for(int i = 0; i < queue.length; i++) {
queue[i] = ar.get(i);
}
this.size = queue.length;
heapify(); // O(n), except that heapify is private and thus you can't call it!!!
}
}
Now I haven't tested this, it's just off the top of my head with some guidance from the PriorityQueue source, but it should point you in the right direction.
But sometime you have to pay the piper and create the heap-order and that be more than just iteration. It should still be on O(n) though, because of heapify.
Another option is to have edge implement Comparable<edge>. Then you can just PriorityQueue<edge> pr = new PriorityQueue(ar);
If you cannot control edge implements Comparable<edge> then you could compose a container class:
class EdgeContainer implements Comparable<EdgeContainer> {
private static final Comparator<edge> comp = ; // that comparator above
private final edge edge;
EdgeContainer(Edge edge) { this.edge = edge; }
public int compareTo(EdgeContainer e) { return comp.compare(edge, e.edge); }
public edge getEdge() { return edge; }
}
List <EdgeContainer>ar=new ArrayList<>();
for(int i=0;i<e;i++)
{
int u=ss.nextInt();
int v=ss.nextInt();
int w=ss.nextInt();
ar.add(new EdgeContainer(new edge(u,v,w)));
}
PriorityQueue<EdgeContainer> qr = new PriorityQueue(ar);
Java's PriorityQueue takes O(n) time to create a priority queue out of a collection passed to it. The mathematical proof has been given in CLSR chapter 6.4 (page 157 in 3rd edition). Intuitively, as the underlying array is mutated into a heap using siftDown or siftUp, the size of the number of the elements to loop over for the next sift operation also decreases leading to an O(n) time complexity.
But as discussed in the comments and as you have mentioned in your question, you cannot achieve this time complexity by using addAll(). The reason is adAll() is inherited from AbstractQueue and works by adding elements in the collection one by one to the queue which can lead to O(nlogn) time complexity.
So if having O(n) time complexity is an absolute requirement, you will have no option but to implement the Comparator interface for the class of objects contained in the collection. #corsiKa's answer nicely details this approach. Also note that even if you pass a collection directly to PriorityQueue, it will convert it to an array which is basically another O(n) operation.
Here is the sample code to go with the question. This API is trying to implement a graph with an adjacency-list representation as an array of Bags indexed by each of vertices in the graph.
public class Graph{
private final int V; //no. of vertices
private Bag<Integer>[] adj; // A bag for each vertex to store all adjacent vertices
.
.
.
}
Is there any advantage of using a Bag here over a linked list or a Set. I know that bags are unordered but why go with an unordered list when they don't save us time or space?
Each data structure can be used under different circumstances:
Set (specifically HashSet) can be list of unordered unique elements. On the other hand, Bags are multisets (unordered collections that may contain duplicate elements).
As for LinkedList they provide easier link manipulation i.e. adding elements at different places, is much easier (constant time).
A Bag is likely implemented with a binary search tree or hash table, giving us O(log n) or O(1) searches. A linked list is going to give O(n) searches.
A Set only allows unique elements, so if you need to store duplicates you need a Bag. The TreeSet or HashSet in the Java Collections library will give us O(log n) or O(1) searches, respectively.
In general, the Set or Bag interfaces will be more suitable when you often need to perform search or delete operations. If you just need to add to the end of the collection and iterate over it, there wouldn't be much difference.
In addition to the other answers, the major difference between a Bag and other unordered data structures i.e. a Set - is that Bags do not support the removal of items once they've been added.
An example use case would be a special logging system where we never intend on deleting past insertions. Or to ensure immutability in highly concurrent systems.
Please see https://algs4.cs.princeton.edu/13stacks/ for an accurate description and comparison of bags against other data structures.
Data types like bag, queue, and stack, differ in the specification of which object is to be removed or examined next.
A bag is a collection where removing items isn't supported. Bags purpose is to provide clients with the ability to collect items and then to iterate through the them.
API Bag (Java)
public class Bag<Item> implements Iterable<Item>
Bag() // creates an empty bag
void add(Item item)
boolean isEmpty()
int size()
Bag.java
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Bag<Item> implements Iterable<Item> {
private Node<Item> first;
private int n;
private static class Node<Item> {
private Item item;
private Node<Item> next;
}
public Bag() {
first = null;
n = 0;
}
public boolean isEmpty() {
return first == null;
}
public int size() {
return n;
}
public void add(Item item) {
Node<Item> oldfirst = first;
first = new Node<Item>();
first.item = item;
first.next = oldfirst;
n++;
}
public Iterator<Item> iterator() {
return new LinkedIterator(first);
}
private class LinkedIterator implements Iterator<Item> {
private Node<Item> current;
public LinkedIterator(Node<Item> first) {
current = first;
}
public boolean hasNext() { return current != null; }
public void remove() { throw new UnsupportedOperationException(); }
public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
}
I'm using a priority queue to sort and use a large number of custom objects. The objects have a "weight" that is their natural ordering. However, different objects that are inserted into the priority queue may have the same "weight". In such cases, I want the priority queue to order them in the same order in which they were put into the queue.
For example, if I add in CustomObjects A,B,C,D in that order, all with the same "weight", than the priority queue should return them in that order as well - even if I poll one or more of the objects before adding in the others.
Here is the CompareTo for my custom object:
public int compareTo(CustomObject o) {
int thisWeight = this.weight;
int thatWeight = o.weight;
if(thisWeight < thatWeight){
return -1;
}
else{
return 1;
}
}
While I thought that this would maintain that initial order, it doesn't. This occurs when I input A,B,C with weight 1; poll A; and add D,E also with weight 1. Somehow, D and E are sorted after B, but before C.
I am aware that the Iterator for PriorityQueues doesn't return the correct ordering, so I am limited in my ability to look at the ordering - however I can see the order that the elements leave the queue and it clearly doesn't follow the path that I want it to.
Suggestions?
If you need to have an ordering according the insertion order you need to use an extra element for timestamp.
I.e. on insertions and equal weight use timestamp to see which element was inserted first.
So CustomObject should be something like:
class CustomObject {
int weight;
long timestamp;
}
And the comparison should be:
public int compareTo (CustomObject o) {
int thisWeight = this.weight;
int thatWeight = o.weight;
if (thisWeight != thatWeight) {
return thisWeight - thatWeight;
}
else {
return this.timestamp - o.timestamp;
}
}
The smaller timestamp means it was inserted earlier so you keep in the insertion order.
You could also use a "logical" time by maintaining a counter that you update on each add or remove.
You could use an automatically-incremented sequence number as a secondary key, and use it to break ties.
Javadoc for PriorityBlockingQueue includes an example of this technique:
Operations on this class make no guarantees about the ordering of elements with equal priority. If you need to enforce an ordering, you can define custom classes or comparators that use a secondary key to break ties in primary priority values. For example, here is a class that applies first-in-first-out tie-breaking to comparable elements. To use it, you would insert a new FIFOEntry(anEntry) instead of a plain entry object.
class FIFOEntry<E extends Comparable<? super E>>
implements Comparable<FIFOEntry<E>> {
final static AtomicLong seq = new AtomicLong();
final long seqNum;
final E entry;
public FIFOEntry(E entry) {
seqNum = seq.getAndIncrement();
this.entry = entry;
}
public E getEntry() { return entry; }
public int compareTo(FIFOEntry<E> other) {
int res = entry.compareTo(other.entry);
if (res == 0 && other.entry != this.entry)
res = (seqNum < other.seqNum ? -1 : 1);
return res;
}
}
I want to augment or lower the priority of items in a PriorityQueue: for example, I might be downloading a long list of images and suddenly want the thirtieth one to have highest priority.
As I understand it, poll() always returns the queue object with the lowest value (as determined by a comparator). If I can lower the value of an item already in a queue (e.g. if this value is determined by an int in the object and I reduce the int value in some other function), will it be returned first by poll(), or is the sorting that allows poll() to do this done at insert time (e.g. by bubbling new queue elements down a list till they reach their "natural" depth)?
If this is done on a PriorityBlockingQueue, could it cause concurrency issues?
None of the collections in Java automatically reorders elements if you change the property that determine their order. For collections that depend on the .hashCode() , .equals() or some comparator, you are not allowed to change the object while it resides in the collection so that the hashcode/equals or comparator would yield different values.
You have to remove, change, re-insert the object if you want to change its priority within a PriorityQueue.
If you look at the source code, every time you poll() on a PriorityQueue it resifts, but it always returns the item that was at the top before the sift.
public class PQ {
int priority;
public PQ(int priority) {
this.priority = priority;
}
public static void main(String[] args) {
PQ one = new PQ(1);
PQ two = new PQ(2);
PQ three = new PQ(3);
PQ four = new PQ(4);
PQ five = new PQ(5);
PriorityQueue<PQ> q = new PriorityQueue<PQ>(3, new Comparator<PQ>() {
#Override
public int compare(PQ o1, PQ o2) {
return o1.priority-o2.priority;
}
});
q.add(three);
q.add(one);
q.add(four);
q.add(two);
q.add(five);
//Prints;
//PQ-1
//PQ-2
//PQ-3
//PQ-4
//PQ-5
while (!q.isEmpty()) {
System.out.println(q.poll());
}
q.add(three);
q.add(one);
q.add(four);
q.add(two);
q.add(five);
//Change the priority after it has been queued
four.priority = 10;
//Prints;
//PQ-1
//PQ-2
//PQ-3
//PQ-5
//PQ-10
while (!q.isEmpty()) {
System.out.println(q.poll());
}
//Reset the priority
four.priority = 4;
q.add(three);
q.add(one);
q.add(four);
q.add(two);
q.add(five);
//Change the priority after it has been queued
four.priority = 0;
//Prints;
//PQ-1
//PQ-0
//PQ-2
//PQ-3
//PQ-5
while (!q.isEmpty()) {
System.out.println(q.poll());
}
}
public String toString() {
return "PQ-" + priority;
}
}
If you iterate over a priority queue, you will find it is in no particular order (except the first element) If you want to change the order, I suggest you create another priority queue.
If you wan to change the position of one entry, I suggest you remove it, change its fields as required and add it again.
I am working on a traveling salesman problem here and my p-queue isn't operating it is simply taking the last item added. I was wonder if anyone could help me figure out the error. here is my Node class (nodes which are added to the queue):
import java.util.*;
public class Node implements Comparable< Node >{
//level of node
int level;
//stores path of node
ArrayList< Integer > path = new ArrayList< Integer >();
//bound of node
int bound;
/** Over-rides compareTo for priority queue handling
* #return int desired sorting value
*/
public int compareTo(Node aNode)
{
if (this.bound<aNode.bound)
{
return 1;
}
if (this.bound>aNode.bound)
{
return -1;
}
else
{
return 0;
}
}
}
and here is the p-queue implementation:
PriorityQueue< Node > theQ = new PriorityQueue< Node >();
The algorithm is implemented correctly the p-queue simply is not putting the lowest bound as the head. I even reversed the the returns on the compareTo with no effect on the p-queue output (signifying to me that the queue is not sorting. I have wasted hours trying to figure it out and also asking some classmates (no-one can discern the problem) taking a shot here to see if anyone knows why the queue is acting like this..
Your code works perfectly fine for me.
What I suspect you're doing is changing the the bound value of a single object and repeatedly adding it, giving you a queue full of the same object (lots of references to it) which of course has the single (last) value you set it to.
public static void main(String[] args)
{
PriorityQueue< Node > theQ = new PriorityQueue< Node >();
Node n = new Node();
n.bound = 6;
theQ.add(n);
n = new Node();
n.bound = 9;
theQ.add(n);
n = new Node();
n.bound = 4;
theQ.add(n);
while ((n = theQ.poll()) != null)
System.out.println("Bound = " + n.bound);
}
Output:
Bound = 9
Bound = 6
Bound = 4
Make sure you are iterating through the PriorityQueue by using the methods provided by the Queue interface, ex. remove to pop an element off the top. In pseudo code:
for each element in some other collection
priorityQueue.add(element)
while priorityQueue is not empty
Set node to priorityQueue.remove()
Do stuff with node
If you are trying to iterate through a for-each loop or PriorityQueue.iterator:
The Iterator provided in method
iterator() is not guaranteed to
traverse the elements of the priority
queue in any particular order.
Alternatively, if you don't want to destroy/remove elements from your PriorityQueue to iterate in order, you could use, as the documentation suggests,
Arrays.sort(pq.toArray())