PriorityQueue not working [duplicate] - java

This question already has answers here:
Java Priority Queue reordering when editing elements
(7 answers)
Closed 5 years ago.
I'm trying to implement Dijkstra algorithm on my own in java. I have a min-priority queue that stores nodes ordered by their current shortest path.
The first step goes smoothly, I set starting node with distance 0 and others with Integer.MAX_VALUE. The starting node was polled out correctly. However, after i removed the first node, the second node that been removed is not the node with smallest distance. I cant figure out why. Any opinions?
Here is my code
public void Dijkstra(Node s){
initialize(s);
List<Node> set = new ArrayList<Node>();
Comparator<Node> c = new CompareNode();
PriorityQueue<Node> Q = new PriorityQueue<Node>(V,c);
for (Node q: Nodes){
Q.add(q);
}
while (Q.size()!=0){
Node u = Q.remove();
System.out.println();
System.out.println(u + " is removed with dis " + u.getD());
set.add(u);
for (Node w: u.getWeightedAdj().keySet()){
relax(u,w);
}
}
}
public void initialize(Node s){
for (Node v: Nodes){
v.setD(Integer.MAX_VALUE);
v.setPredecessor(null);
}
s.setD(0);
}
public void relax(Node u, Node w){
if (w.getD()>u.getD()+u.getWeightedAdj().get(w)){
w.setD(u.getD()+u.getWeightedAdj().get(w));
w.setPredecessor(u);
}
}
And comparator class
import java.util.Comparator;
public class CompareNode implements Comparator<Node> {
#Override
public int compare(Node o1, Node o2) {
if (o1.getD()>o2.getD())
return 1;
if (o1.getD()<o2.getD())
return -1;
return 0;
}
}
when I ran it, the outcome looks like this
A is removed with dis 0
E is removed with dis 2147483647
C is removed with dis 2
D is removed with dis -2147483648
B is removed with dis 3

The problem is that the PriorityQueue orders the elements when they are added with the assumption that the order cannot change.
In your example all your distances are MaxInt when the nodes are added to the queue (except for the start node), and so they are placed into the queue in effectively a random order.
You then adjust the distances, but the PriorityQueue does not know about these adjustments so continues to return the elements in the original order.
The standard approach to this is to insert elements in the priority queue when the distance changes. (When an element is removed from the queue, you need to test whether you have already visited this element because the same element can appear multiple times in the queue.)

It would be easier to add the nodes to the queue as they get discovered. I.e. in the beginning only add the root node, and then in each iteration add the newly discovered nodes that haven't been processed. In the iteration step you need to check if new nodes are in the queue or not and possibly update them if the new distance is shorter.

Related

Problem with elements at same level with same vertical height in Vertical Order Traversal of a Binary Tree

Pseudocode
Created a class that will hold the node and its horizontal height
Using BFS, so create a queue and inserted the first node having a horizontal height of 0
Popped the element from the queue, if the horizontal height doesn't exist in the map then created an entry for it
get the ArrayList of horizontal height and add the value of the node to it
check for the left and right child, if they are not null then add them to the queue
class Solution {
class Node{
TreeNode key;
int h;
Node(TreeNode key,int h){
this.key=key;
this.h=h;
}
}
public List<List<Integer>> verticalTraversal(TreeNode root) {
if(root==null)
return null;
TreeMap<Integer, ArrayList<Integer>> map = new TreeMap<>();
Queue<Node> q=new LinkedList<>();
q.add(new Node(root,0));
while(!q.isEmpty()){
Node tmp=q.poll();
if(!map.containsKey(tmp.h))
map.put(tmp.h,new ArrayList<Integer>());
map.get(tmp.h).add(tmp.key.val);
if(tmp.key.left!=null)
q.add(new Node(tmp.key.left,tmp.h-1));
if(tmp.key.right!=null)
q.add(new Node(tmp.key.right,tmp.h+1));
}
List<List<Integer>> ans=new ArrayList<>();
for(ArrayList<Integer> al:map.values()){
ans.add(al);
}
return ans;
}
}
Problem
Failing for input
Input:
[0,2,1,3,null,null,null,4,5,null,7,6,null,10,8,11,9]
First of all you are probably talking about horizontal height not vertical height as your output suggest. Output you got seems to be correct since when making BFS traversal you are first looking on the left element then the right from up to bottom independently on horizontal heights. Left node of the tree level will always be processed sooner (therefore also its child will be sooner added to the queue) so at level 3 (from up to bottom indexing from 0) node with value 7 will be sooner added to the queue for processing then node with value 6. Therefore output seems to be correct in my eyes, can you tell us why your are expecting different output ?
According to this sentence in your task link (https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/):
"If two nodes have the same position, then the value of the node that is reported first is the value that is smaller."
It seems that you need to sort your sublists inside resulting list. You can do that with following code:
sortedResult = resultList.stream()
.map(list -> list.stream().sorted().collect(Collectors.toList()))
.collect(Collectors.toList());

What is the fastest way to search the maximum element in a stack in Java?

I have a problem in which I have to search for the maximum element in a stack. I've created my own stack class and used the following approach:
Node node = top; //created a new node which points to the top of stack
int max = node.data; //max contains the value of the top node
while(node != null) {
if(node.data > max) {
max = node.data;
}
node = node.next;
}
//Print the value of max.
Can anybody suggest a more efficient way to do this?
Maintain two stack :
consist of all Nodes.
always keep Max node at top of it, which makes it easier to get max element every time.
The code goes like this :
import java.util.Stack;
public class StackWithMax extends Stack<Integer> {
Stack<Integer> s2;
public StackWithMax() {
s2 = new Stack<Integer>();
}
public void push(int value){
if (value >= max()) {
s2.push(value);
}
super.push(value);
}
public Integer pop() {
int value = super.pop();
if (value == max()) {
s2.pop();
}
return value;
}
public int max() {
if (s2.isEmpty()) {
return Integer.MIN_VALUE;
} else {
return s2.peek();
}
}
}
If you are fine with using an extra space, we can do getMax() in O(1) time. The idea is to use a PriorityQueue based on a comparator that returns the maximum of two elements. Your PriorityQueue will consist of elements arranged ina sorted way based on your comparator. Anytime you push an element in your stack, you push the maximum element corresponding to that element in the PriorityQueue as well. Lets take an example:
Suppose in your stack you are pushing the element 3. Then in your priorityQueue pQ, you would offer 3. At this time, 3 will be the max element corresponding to 3 in the stack.
Lets insert 5 in stack S. Offer 5 in pQ. Since 5 > 3, order of elements in pQ will be 5 3.
Lets push 4 in S. Offer 4 in pQ as well. pQ will now contain elements: 5 4 3. If you do getMax(), you get head of pQ which takes O(1) time since maximum element is always at top of pQ.
In case of S.pop(), you can remove the corresponding popped element from pQ as well in O(1) time if you store the pQ in the form of LinkedList. Hence, all these operations would take O(1) time really.
Going by same logic, you can also do popMax() too in O(1) time. Just return the head of pQ and delete the corresponding node from Stack as well, which again can be done in O(1) of time.
Here is how the structure of both can be:
public class Node{
int data;
Node next;
Node(int data){
this.data = data;
next = null;
}
}
PriorityQueue<Node> pQ = new PriorityQueue<Node>();
Stack<Node> S = new Stack<Node>();

Sorting edges of a graph (based on Adjacency List representation) in Java

I have a graph which stores it's edges using a HashMap as follows :
HashMap<Integer,LinkedList<Node>> adj;
where Node is defined ;
class Node
{
int number;
int weight;
}
eg
0 : <1,55> -> <2,54> //node 0 is connected to node 1 with edge weight 55 and node 2 with edge weight 54
1 : <0,43> -> <2,44> //node 1 is connected to node 0 with edge weight 43 and node 2 with
edge weight 44
I need to get a list of edges in sorted order by weight and I have no clue how to go about it. I am trying to implement Kruskal's MST.
Is it possible to sort the graph I have defined? If not please suggest a better way of storing it.
Let's start by creating an Edge class:
class Edge implements Comparable<Edge> { // Important: must implement Comparable. More on this later
public Node first; // first connected node
public Node second; // second connected node
public int weight; // move edge weight to Edge class
#Override
public int compareTo(Edge e) {
if (weight < e.weight) {
return -1;
} else if (weight > e.weight) {
return 1;
} else {
return 0;
}
}
}
Because the weight variable is in the Edge class, it isn't needed in Node, so you can remove it:
class Node {
public int number;
// add more variables later is you need here
}
Now, for your program (if there isn't a requirement against it), I would define your list like this:
HashMap<Node, List<Edge>> adj; // use any list implementation you want
This will represent the graph like this inside your program (copied from your example):
Node 0: Edge(Node 0, Node 1, 55), Edge(Node 0, Node 2, 54)
Node 1: Edge(Node 1, Node 0, 43), Edge(Node 1, Node 2, 44)
To answer your question, lets find the edges sorted by edge weight:
ArrayList<Edge> sortedEdges = new ArrayList<Edge>();
for (List<Edge> connectedEdges : adj.values()) {
sortedEdges.addAll(connectedEdges);
}
Collections.sort(sortedEdges);
This simply takes all the Edges in adj and puts them all in one list, and then sorts them according to their weight (because we made Edge extend Comparable<Edge>). As per the Javadoc on Collections.sort(), the sort() method uses merge sort, which runs in O(nlog(n)) time:
Implementation note: This implementation is a stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when the input array is partially sorted, while offering the performance of a traditional mergesort when the input array is randomly ordered.
Getting the list of all Edges by adj.values takes O(n) time (see this), so the total time complexity of getting the list of edges sorted by weight will be O(n) + O(nlog(n)) = O(nlog(n)).
So there you go. I hope this helped :)
If you have the freedom to change the way nodes are represented, I would like to suggest changing it. Currently the Node class really represents an edge (and a node is represented by Integer, i.e., keys to the adj variable.
For example, the following seems more natural:
Set<Node> nodes = new HashSet<>(); // The enclosing class keeps track of all nodes.
// Represents each node.
class Node {
int nodeId = /* ... */;
// The Node class keeps track of its neighbors, sorted by their weights.
SortedMap<Integer,Node> edges = new TreeMap<>(Collections.reverseOrder());
}
Then, whenever you need to do things in the descending order of the weight, you could do something like:
void method(Node node) {
Iterator<Integer> iter = node.edges.keySet().iterator(); // Iterates in descending order.
while(iter.hasNext()) {
int weight = iter.next();
Node neighbor = node.edges.get(weight);
doSomething( /* ... */ );
}
}

Iteratively traverse through tree to find size

I need to find the number of elements in a tree using an iterative algorithm, but I'm finding the code conceptually very difficult to write.
My approach is to start at the root node and visit the child nodes, then the children of these child nodes, and so on.
This is the code I've written which works for a small tree, but isn't a real solution because I'd need to add an additional block for each level of depth:
// Start the counter at 1 because the root node counts
int size = 1;
for(ITree child1 : root) {
size++;
for(ITree child2 : child1) {
size++;
for(ITree child3 : child2) {
size++;
for(ITree child4 : child3) {
size++;
for(ITree child5 : child4) {
size++;
}
}
}
}
}
return size;
Conceptually, keep a stack (LinkedList, etc.). For each child (now, your child loops), add to the stack. Continue looping through the stack until it is finally empty.
This isn't tested, but this should do exactly what you're looking for. I'm just using java.io.File instead of your "ITree", as it's something I can compile against:
int sizeOfTree(File root){
// Start the counter at 1 because the root node counts
int size = 1;
LinkedList<File> stack = new LinkedList<File>();
stack.add(root);
while(!stack.isEmpty()){
File f = stack.remove();
for(File child : f.listFiles()){
size++;
stack.add(child);
}
}
return size;
}
Using a recursive data structure
It is not practically possible to iteratively traverse a recursive data structure, like a tree with pointers - this is because of the fact that the objects "hide" their underlying data elements.
Using a different data structure
All trees can be stored/implemented as to linear, array data structures, where indices can be calculated using exponential mathematics :
For example, a tree [0, 1, 2, 3, null, 4,null] would describe a tree with 0 at the root, where 0 had direct children 1 and 2. And then 1 has left child "3", and 2 has left child "4".
Thus, if you store the tree this way, the number of elements is, naturally, the number of non-null elements in the array.
Put more simply : Store the tree in a linear structure , and you can know the length at any given time without having to make any kind of fancy algorithm.
The key word for your task is recursion. Tree is a classical recursive structure, so you should write recursive method that accepts root nodes, counts size of this node and then calls itself for all children. Here is pseudo code:
public int getSize(ITree root) {
return getSize(root, 0);
}
private int getSize(ITree node, int size) {
size++;
for(ITree child : node.children()) {
size += getSize(child, size)
}
return size;
}

Java priority queue help needed

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())

Categories