For a project I want to generate a tree structure which has x children and is n 'layers' deep. A layer can the best be described in the following figure:
0
1 1
2 2 2 2
The number on each row equals the layer number.
I got the following class named Node:
public class Node {
private String nodeName;
private List<Node> children;
private int layer;
/**
* A node with a name and a list of children on a given layer in a tree or
* web
*
* #param nodeName the name of the node
* #param children the list of children of this node
* #param layer the layer in which this node exists
*/
public Node(String nodeName, List<Node> children, int layer) {
this.nodeName = nodeName;
this.children = children;
this.layer = layer;
}
}
Additionally, I have getters and setters for each field.
After struggling for two full evenings, I came up with this code:
private static Node createTree() {
Node masterNode = new Node();
int childsPerNode = 3;
int amountOfLayers = 5; //meaning 6 layers, 0 is included
//Output = 364
int totalNodeAmount = calculateNodeAmount(childsPerNode, amountOfLayers);
//Loop for each layer, form bottom to top
for (int currentLayer = 5; currentLayer > amountOfLayers; currentLayer--) {
/**
* For each layer, calculate the nodes for this layer, add children
* to each node
*/
int nodesThisLayer = calculateNodeAmount(childsPerNode, amountOfLayers) - calculateNodeAmount(childsPerNode, currentLayer);
for (int nodeCount = 0; nodeCount < nodesThisLayer; nodeCount++) {
List<Node> children = new ArrayList<>();
for (int childCount = 0; childCount < childsPerNode; childCount++) {
String childFunctionName = "name";
Node childNode = new Node(childFunctionName, null, currentLayer);
children.add(childNode);
}
String parentFunctionName = "parent name";
Node parentNode = new Node(parentFunctionName, children, currentLayer);
}
}
return masterNode;
}
Any help regarding my way to end up with one Node which contains the whole tree in its children is greatly appreciated, as I'm out of ideas. I did not find a good source for a tree with x children and n layers (or depth), hence my potential double question.
Kind regards!
EDIT:
Based on the comment of lexicore, I came up with this function:
private static void createTree(Node currentNode, int childrenPerNode, int numberOfLayers) {
if (numberOfLayers == 0) {
//Something is off here
return;
} else if (numberOfLayers > 0) {
//Create sub nodes
List<Node> nodes = new ArrayList<>();
for (int i = 0; i < childrenPerNode; i++) {
Node childNode = new Node("name", nodes, numberOfLayers);
nodes.add(childNode);
}
//Add the children to the current node
currentNode.setChilderen(nodes);
for (int i = 0; i < childrenPerNode; i++) {
//For each of the children per node, call this function again until the number of layers equals zero
createTree(currentNode.getChildren().get(i), childrenPerNode, numberOfLayers - 1);
}
}
This does, however, continue too loop way too 'deep' (too much layers). I'm breaking my head on why that is.
I'll be looking to the other answers right now. Thanks for your time already!
The title says "recursive," so I'll assume you really want to write a recursive method. To write one, you must learn to think recursively.
For the task of building trees, this is pretty straightforward. Trees are recursively defined: a tree may be empty or else a node with trees as children.
In your case the definition is a bit more complicated. A layer N tree may be empty (if N is greater than or equal to the max desired layer number) or else it's a node with layer number N and K subtrees with layer number N+1.
This translates to an algorithm:
Node buildTree(int N) {
// A layer N tree may be empty (if N is more than the max desired layer number)
if (L >= maxLayerNumber) {
return new Node with no children
}
// ... or else it's a node with layer number N and K subtrees with layer number N+1
Let C be an initially empty list of children
for i = 1 to K {
Let c = buildTree(N + 1)
Add c to C
}
return new Node with layer number N and children C
}
To get the whole tree, call buildTree(0).
I'm deliberately not providing Java code. It's important to solve problems yourself.
You might want to avoid calculating the number of children you'll need to create by either using recursion as suggested in the comments or by iterating through the bottom nodes of the tree and keeping them in a separate collection.
List<Node> children = new ArrayList<Node>();
children.add(masterNode);
int layer = amountOfLayers;
while (layer > 0) {
List<Node> allBottomChildren = new ArrayList<Node>();
for (Node child : children) {
List<Node> nextLevelChildren = new ArrayList<Node>();
for (int i = 0;i<childsPerNode;i++) {
Node node = new Node("name", new ArrayList<Node>(), layer - 1);
nextLevelChildren.add(node);
}
child.setChildren(nextLevelChildren);
allBottomChildren.addAll(nextLevelChildren);
}
children = allBottomChildren;
layer = layer - 1;
}
This is obviously not the best design, but a pretty brief solution:
int childsPerNode = 3;
int amountOfLayers = 5;
class AutoNode {
int layer;
List <AutoNode> childs;
public AutoNode (int n) {
layer = n;
if (layer < amountOfLayers) {
childs = new ArrayList<AutoNode> ();
for (int i = 0; i < childsPerNode; ++i) {
childs.add (new AutoNode (n + 1));
}
}
}
public String toString () {return ("layer: " + layer + " <" + ((layer < 5) ? childs.toString () : "()") + ">" );}
}
AutoNode root = new AutoNode (0);
The bounds:
int childsPerNode = 3;
int amountOfLayers = 5;
are somewhat alien to the Nodes. But it works as a first, quick prototype.
You can add methods to the Autonode, and perform different exercises. You may put them as final static into the Autonode definition.
If you want to heat up System, call root with = new AutoNode (-40); but calculate 3^45 first.
Here's an example of a fully encapsulated object-oriented design (i.e. recursive constructor):
public class Tree
{
private int layer;
private int nodeID;
private List<Tree> children;
public Tree(int numOfchildren, int numOfLayers)
{
this(numOfchildren, numOfLayers, 0, new int[1]);
}
private Tree(int numOfchildren, int numOfLayers, int layerIndex, int[] nodeIndex)
{
layer = layerIndex;
nodeID = nodeIndex[0]++;
if (numOfLayers > 0 && numOfchildren > 0) {
children = new ArrayList<Tree> ();
for (int i = 0; i < numOfchildren; i++) {
children.add(new Tree(numOfchildren, numOfLayers - 1, layer + 1, nodeIndex));
}
}
}
}
Some noteworthy concepts:
The Tree class contains one public constructor and one private constructor. The public constructor in just a "clean" interface. The private one does all the "dirty" work.
The layerIndex parameter of the private constructor sets the offset of the root node. Setting it to 0 (as does the public constructor) is best.
The int[] nodeIndex array parameter of the private constructor is a "workaround" for sending an int argument by reference. The array argument (as provided by the public constructor) consists of a single element array that keeps track of the number of children created thus far in order to set the nodeID to a unique value.
Related
Given a rooted tree having N nodes. Root node is node 1. Each ith node has some value , val[i] associated with it.
For each node i (1<=i<=N) we want to know MEX of the path values from root node to node i.
MEX of an array is smallest positive integer not present in the array, for instance MEX of {1,2,4} is 3
Example : Say we are given tree with 4 nodes. Value of nodes are [1,3,2,8] and we also have parent of each node i (other than node 1 as it is the root node). Parent array is defined as [1,2,2] for this example. It means parent of node 2 is node 1, parent of node 3 is node 2 and parent of node 4 is also node 2.
Node 1 : MEX(1) = 2
Node 2 : MEX(1,3) = 2
Node 3 : MEX(1,3,2) = 4
Node 4 : MEX(1,3,8) = 2
Hence answer is [2,2,4,2]
In worst case total number of Nodes can be upto 10^6 and value of each node can go upto 10^9.
Attempt :
Approach 1 : As we know MEX of N elements will be always be between 1 to N+1. I was trying to use this understanding with this tree problem, but then in this case N will keep on changing dynamically as one proceed towards leaf nodes.
Approach 2 : Another thought was to create an array with N+1 empty values and then try to fill them as we go along from root node. But then challenge I faced was on to keep track of first non filled value in this array.
public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int T = Integer.parseInt(br.readLine().trim());
for(int t_i = 0; t_i < T; t_i++)
{
int N = Integer.parseInt(br.readLine().trim());
String[] arr_val = br.readLine().split(" ");
int[] val = new int[N];
for(int i_val = 0; i_val < arr_val.length; i_val++)
{
val[i_val] = Integer.parseInt(arr_val[i_val]);
}
String[] arr_parent = br.readLine().split(" ");
int[] parent = new int[N-1];
for(int i_parent = 0; i_parent < arr_parent.length; i_parent++)
{
parent[i_parent] = Integer.parseInt(arr_parent[i_parent]);
}
int[] out_ = solve(N, val, parent);
System.out.print(out_[0]);
for(int i_out_ = 1; i_out_ < out_.length; i_out_++)
{
System.out.print(" " + out_[i_out_]);
}
System.out.println();
}
wr.close();
br.close();
}
static int[] solve(int N, int[] val, int[] parent){
// Write your code here
int[] result = new int[val.length];
ArrayList<ArrayList<Integer>> temp = new ArrayList<>();
ArrayList<Integer> curr = new ArrayList<>();
if(val[0]==1)
curr.add(2);
else{
curr.add(1);
curr.add(val[0]);
}
result[0]=curr.get(0);
temp.add(new ArrayList<>(curr));
for(int i=1;i<val.length;i++){
int parentIndex = parent[i-1]-1;
curr = new ArrayList<>(temp.get(parentIndex));
int nodeValue = val[i];
boolean enter = false;
while(curr.size()>0 && nodeValue == curr.get(0)){
curr.remove(0);
nodeValue++;
enter=true;
}
if(curr.isEmpty())
curr.add(nodeValue);
else if(!curr.isEmpty() && curr.contains(nodeValue) ==false && (enter|| curr.get(0)<nodeValue))
curr.add(nodeValue);
Collections.sort(curr);
temp.add(new ArrayList<>(curr));
result[i]=curr.get(0);
}
return result;
}
}
This can be done in time O(n log n) using augmented BSTs.
Imagine you have a data structure that supports the following operations:
insert(x), which adds a copy of the number x.
remove(x), which removes a copy of the number x.
mex(), which returns the MEX of the collection.
With something like this available, you can easily solve the problem by doing a recursive tree walk, inserting items when you start visiting a node and removing those items when you leave a node. That will make n calls to each of these functions, so the goal will be to minimize their costs.
We can do this using augmented BSTs. For now, imagine that all the numbers in the original tree are distinct; we’ll address the case when there are duplicates later. Start off with Your BST of Choice and augment it by having each node store the number of nodes in its left subtree. This can be done without changing the asymptotic cost of an insertion or deletion (if you haven’t seen this before, check out the order statistic tree data structure). You can then find the MEX as follows. Starting at the root, look at its value and the number of nodes in its left subtree. One of the following will happen:
The node’s value k is exactly one plus the number of nodes in the left subtree. That means that all the values 1, 2, 3, …, k are in the tree, so the MEX will be the smallest value missing from the right subtree. Recursively find the MEX of the right subtree. As you do, remember that you’ve already seen the values from 1 to k by subtracting k off of all the values you find there as you encounter them.
The node’s value k is at least two more than the number of nodes in the left subtree. That means that the there’s a gap somewhere in the node’s in the left subtree plus the root. Recursively find the MEX of the left subtree.
Once you step off the tree, you can look at the last node where you went right and add one to it to get the MEX. (If you never went right, the MEX is 1).
This is a top-down pass on a balanced tree that does O(1) work per node, so it takes a total of O(log n) work.
The only complication is what happens if a value in the original tree (not the augmented BST) is duplicated on a path. But that’s easy to fix: just add a count field to each BST node tracking how many times it’s there, incrementing it when an insert happens and decrementing it when a remove happens. Then, only remove the node from the BST in the case where the frequency drops to zero.
Overall, each operation on such a tree takes time O(log n), so this gives an O(n log n)-time algorithm for your original problem.
public class PathMex {
static void dfs(int node, int mexVal, int[] res, int[] values, ArrayList<ArrayList<Integer>> adj, HashMap<Integer, Integer> map) {
if (!map.containsKey(values[node])) {
map.put(values[node], 1);
}
else {
map.put(values[node], map.get(values[node]) + 1);
}
while(map.containsKey(mexVal)) mexVal++;
res[node] = mexVal;
ArrayList<Integer> children = adj.get(node);
for (Integer child : children) {
dfs(child, mexVal, res, values, adj, map);
}
if (map.containsKey(values[node])) {
if (map.get(values[node]) == 1) {
map.remove(values[node]);
}
else {
map.put(values[node], map.get(values[node]) - 1);
}
}
}
static int[] findPathMex(int nodes, int[] values, int[] parent) {
ArrayList<ArrayList<Integer>> adj = new ArrayList<>(nodes);
HashMap<Integer, Integer> map = new HashMap<>();
int[] res = new int[nodes];
for (int i = 0; i < nodes; i++) {
adj.add(new ArrayList<Integer>());
}
for (int i = 0; i < nodes - 1; i++) {
adj.get(parent[i] - 1).add(i + 1);
}
dfs(0, 1, res, values, adj, map);
return res;
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int nodes = sc.nextInt();
int[] values = new int[nodes];
int[] parent = new int[nodes - 1];
for (int i = 0; i < nodes; i++) {
values[i] = sc.nextInt();
}
for (int i = 0; i < nodes - 1; i++) {
parent[i] = sc.nextInt();
}
int[] res = findPathMex(nodes, values, parent);
for (int i = 0; i < nodes; i++) {
System.out.print(res[i] + " ");
}
}
}
I'm struggling with this problem on HackerRank.
https://www.hackerrank.com/challenges/friend-circle-queries/problem
I tried solving it using a custom linked list - NodeList. It has three fields - Node first, Node current, int size. 'add' is an overloaded method. It can add a value or another NodeList.
I have put code for NodeList in comments because it doesn't matter much.
Fields :-
static HashMap<Integer, Integer> personToIndex = new HashMap<>();
static int largestCircleSize = 0;
static ArrayList<NodeList> groups = new ArrayList<>();
This is my business logic method.
When only one person is part of a friend circle, I add the other person in the circle. When both the people who are shaking hands are already part of other circles, I merge the circles.
static void updateFriendCircles(int friend1, int friend2) {
int friend1Index, friend2Index;
NodeList toUpdate;
friend1Index = personToIndex.getOrDefault(friend1, -1);
friend2Index = personToIndex.getOrDefault(friend2, -1);
if (friend1Index != -1) {
NodeList list = groups.get(friend1Index);
if (friend2Index != -1) {
NodeList list2 = groups.get(friend2Index);
if (list.first == groups.get(friend2Index).first)
return;
toUpdate = list.add(list2);
groups.set(friend2Index, list);
}
else {
toUpdate = list.add(friend2);
personToIndex.put(friend2, friend1Index);
}
}
else if (friend2Index != -1) {
toUpdate = groups.get(friend2Index).add(friend1);
personToIndex.put(friend1, friend2Index);
}
else {
int index = groups.size();
personToIndex.put(friend1, index);
personToIndex.put(friend2, index);
toUpdate = new NodeList(friend1).add(friend2);
groups.add(toUpdate);
}
if (toUpdate.size > largestCircleSize)
largestCircleSize = toUpdate.size;
}
I have also tried using HashSet but it also has same problem so I think problem is not in data structure.
As it's not clear what is wrong with the solution exactly (it's not specified by the OP) - wrong answers or timeout for some test cases I'll explain how to solve it.
We can use a disjoint set data structure to represent sets of friend circles.
The basic idea is that in each circle we assign a member that is used to represent a given circle. We can call it a root. Finding a number of members in the circle is always delegated to the root that stores its size.
Each non-root member points to his root member or to a member through whom he can get to the root. In the future, the current root may also lose his root status for the community but then it will point to the new root and so it's always possible to get to it through chained calls.
When 2 circles merge then a new root member is chosen among 2 previous ones. The new size can be set into it because previous roots already contain sizes for both circles. But how is the new root chosen? If the size of circle 1 is not smaller than that of circle 2 then it's picked as a new root.
So, for this problem, first we should define placeholders for circles and sizes:
Map<Integer, Integer> people;
Map<Integer, Integer> sizes;
For non-root members in people, key is a person ID and value is a friend he follows (root or parent that can get him to the root). Root members won't have an entry in the map.
Then, we need a method that will get us to the root for any member:
int findCommunityRoot(int x) {
if (people.containsKey(x)) {
return findCommunityRoot(people.get(x));
}
return x;
}
Finally, we need a method to build a community for 2 given friends:
int mergeCommunities(int x, int y) {
//find a root of x
x = findCommunityRoot(x);
//find a root of y
y = findCommunityRoot(y);
// one-man circle has a size of 1
if (!sizes.containsKey(x)) {
sizes.put(x, 1);
}
// one-man circle has a size of 1
if (!sizes.containsKey(y)) {
sizes.put(y, 1);
}
// friends in the same circle so just return its size
if (x == y) {
return sizes.get(x);
}
sizeX = sizes.get(x);
sizeY = sizes.get(y);
if (sizeX >= sizeY) {
people.put(y, x);
sizes.put(x, sizeY + sizeX);
return sizes.get(x);
} else {
people.put(x, y);
sizes.put(y, sizeY + sizeX);
return sizes.get(y);
}
}
So, we have everything we need to save a size of the largest circle at each iteration:
List<Integer> maxCircle(int[][] queries) {
List<Integer> maxCircles = new ArrayList<>();
int maxSize = 1;
for (int i = 0; i < queries.length; i++) {
int size = mergeCommunities(queries[i][0], queries[i][1]);
maxSize = Math.max(maxSize, size);
maxCircles.add(maxSize);
}
return maxCircles;
}
I am trying to find the average of each level in a binary tree. I am doing BFS. I am trying to do it using a null node. Whenever I find a dummy node, that means I am at the last node at that level. The problem I am facing is that I am not able to add average of the last level in a tree using this. Can Someone Help me?
Consider example [3,9,20,15,7]
I am getting the output as [3.00000,14.50000]. Not getting the average of the last level that is 15 and 7
Here's my code
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> list = new ArrayList<Double>();
double sum = 0.0;
Queue<TreeNode> q = new LinkedList<TreeNode>();
TreeNode temp = new TreeNode(0);
q.offer(root);
q.offer(temp);
int count = 0;
while(!q.isEmpty()){
root = q.poll();
sum += root.val;
if(root != temp)
{
count++;
if(root.left != null){
q.offer(root.left);
}
if(root.right != null){
q.offer(root.right);
}
}
else
{
if(!q.isEmpty()){
list.add(sum / count);
sum = 0;
count = 0;
q.add(temp);
}
}
}
return list;
}
}
Take a look at this code, which executes whenever you find the marker for the end of the current level:
if(!q.isEmpty()){
list.add(sum / count);
sum = 0;
count = 0;
q.add(temp);
}
This if statement seems to be designed to check whether you've finished the last row in the tree, which you could detect by noting that there are no more entries in the queue that would correspond to the next level. In that case, you're correct that you don't want to add the dummy node back into the queue (that would cause an infinite loop), but notice that you're also not computing the average in the row you just finished.
To fix this, you'll want to compute the average of the last row independently of reseeding the queue, like this:
if(!q.isEmpty()){
q.add(temp);
}
list.add(sum / count);
sum = 0;
count = 0;
There's a new edge case to watch out for, and that's what happens if the tree is totally empty. I'll let you figure out how to proceed from here. Good luck!
I would use recursive deep scan of the tree. On each node I would push the value into a map with a pair .
I DID NOT test that code but it should be along the lines.
void scan(int level, TreeNode n, Map<Integer, List<Integer> m) {
List l = m.get(level); if (l==null) {
l = new ArrayList();
m.put(level, l);
}
l.add(n.val);
int nextLevel = level + 1;
if (n.left != null) scan(nextLevel, n.left, m);
if (n.right != null) scan(nextLevel, n.right, m);
}
Once the scan is done I can calculate the average for each level.
for (int lvl in m.keyset()) {
List l = m.get(lvl);
// MathUtils.avg() - it is obvious what it should be
double avg = MathUtils.avg(l);
// you code here
}
In Prim's algorithm, it is recommended to maintain the invariant in the following way :
When a vertice v is added to the MST:
For each edge (v,w) in the unexplored tree:
1. Delete w from the min heap.
2. Recompute the key[w] (i.e. it's value from the unexplored tree
to the explored one).
3. Add the value back to the heap.
So, basically this involves deletion from the heap (and heapify which takes O(logn)) and then reinserting (again O(logn))
Instead, if I use the following approach:
For each edge (v,w) in the unexplored tree:
1. Get the position of the node in the heap(array) using HashMap -> O(1)
2. Update the value in place.
3. Bubble up or bubble down accordingly. -> O(logn)
Which gives better constants than the previous one.
The controversial part is the 3rd part where Im supposed to bubble up or down.
My implementation is as follows :
public int heapifyAt(int index){
// Bubble up
if(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
while(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
swap(index, (int)Math.floor(index/2));
index = (int)Math.floor(index/2);
}
}else{
// Bubble down
while(index*2 + 2 < size && (heap[index].edgeCost > heap[index*2 + 1].edgeCost|| heap[index].edgeCost > heap[index*2 + 2].edgeCost)){
if(heap[index*2 + 1].edgeCost < heap[index*2 + 2].edgeCost){
//swap with left child
swap(index, index*2 + 1);
index = index*2 + 1;
}else{
//swap with right child
swap(index, index*2 + 2);
index = index*2 + 2;
}
}
}
return index;
}
And I'am plucking from the heap this way :
public AdjNode pluck(){
AdjNode min = heap[0];
int minNodeNumber = heap[0].nodeNumber;
AdjNode toRet = new AdjNode(min.nodeNumber, min.edgeCost);
heap[0].edgeCost = INF; // set this to infinity, so it'll be at the bottom
// of the heap.
heapifyat(0);
visited.add(minNodeNumber);
updatevertices(minNodeNumber); // Update the adjacent vertices
return toRet;
}
And updating the plucked vertices this way :
public void updatevertices(int pluckedNode){
for(AdjNode adjacentNode : g.list[pluckedNode]){
if(!visited.contains(adjacentNode.nodeNumber)){ // Skip the nodes that are already visited
int positionInHeap = map.get(adjacentNode.nodeNumber); // Retrive the position from HashMap
if(adjacentNode.edgeCost < heap[positionInHeap].edgeCost){
heap[positionInHeap].edgeCost = adjacentNode.edgeCost; // Update if the cost is better
heapifyAt(positionInHeap); // Now this will go bottom or up, depending on the value
}
}
}
}
But when I execute it on large graph, the code fails, There are small values in the bottom of heap and large values at the top. But the heapifyAt() API seems to work fine. So I am unable to figure out is my approach wrong or my code?
Moreover, if I replace the heapifyAt() API by siftDown(), i.e. construct the heap, it works fine, but it doesnt make sense calling siftDown() that takes O(n) time for every updates which can be processed in logarithmic time.
In short : Is it possible to update the values in Heap both way, or the algorithm is wrong, since that's why it is recommended to first remove the element from Heap and reinsert it.
EDIT : Complete code:
public class Graph1{
public static final int INF = 9999999;
public static final int NEGINF = -9999999;
static class AdjNode{
int nodeNumber;
int edgeCost;
AdjNode next;
AdjNode(int nodeNumber, int edgeCost){
this.nodeNumber = nodeNumber;
this.edgeCost = edgeCost;
}
}
static class AdjList implements Iterable<AdjNode>{
AdjNode head;
AdjList(){
}
public void add(int to, int cost){
if(head==null){
head = new AdjNode(to, cost);
}else{
AdjNode temp = head;
while(temp.next!=null){
temp = temp.next;
}
temp.next = new AdjNode(to, cost);
}
}
public Iterator<AdjNode> iterator(){
return new Iterator<AdjNode>(){
AdjNode temp = head;
public boolean hasNext(){
if(head==null){
return false;
}
return temp != null;
}
public AdjNode next(){
AdjNode ttemp = temp;
temp = temp.next;
return ttemp;
}
public void remove(){
throw new UnsupportedOperationException();
}
};
}
public void printList(){
AdjNode temp = head;
if(head==null){
System.out.println("List Empty");
return;
}
while(temp.next!=null){
System.out.print(temp.nodeNumber + "|" + temp.edgeCost + "-> ");
temp = temp.next;
}
System.out.println(temp.nodeNumber + "|" + temp.edgeCost);
}
}
static class Heap{
int size;
AdjNode[] heap;
Graph g;
int pluckSize;
Set<Integer> visited = new HashSet<Integer>();
HashMap<Integer, Integer> map = new HashMap<>();
Heap(){
}
Heap(Graph g){
this.g = g;
this.size = g.numberOfVertices;
this.pluckSize = size - 1;
heap = new AdjNode[size];
copyElements();
constructHeap();
}
public void copyElements(){
AdjList first = g.list[0];
int k = 0;
heap[k++] = new AdjNode(0, NEGINF); //First entry
for(AdjNode nodes : first){
heap[nodes.nodeNumber] = nodes;
}
for(int i=0; i<size; i++){
if(heap[i]==null){
heap[i] = new AdjNode(i, INF);
}
}
}
public void printHashMap(){
System.out.println("Priniting HashMap");
for(int i=0; i<size; i++){
System.out.println(i + " Pos in heap :" + map.get(i));
}
line();
}
public void line(){
System.out.println("*******************************************");
}
public void printHeap(){
System.out.println("Printing Heap");
for(int i=0; i<size; i++){
System.out.println(heap[i].nodeNumber + " | " + heap[i].edgeCost);
}
line();
}
public void initializeMap(){
for(int i=0; i<size; i++){
map.put(heap[i].nodeNumber, i);
}
}
public void swap(int one, int two){
AdjNode first = heap[one];
AdjNode second = heap[two];
map.put(first.nodeNumber, two);
map.put(second.nodeNumber, one);
AdjNode temp = heap[one];
heap[one] = heap[two];
heap[two] = temp;
}
public void constructHeap(){
for(int i=size-1; i>=0; i--){
int temp = i;
while(heap[temp].edgeCost < heap[(int)Math.floor(temp/2)].edgeCost){
swap(temp, (int)Math.floor(temp/2));
temp = (int)Math.floor(temp/2);
}
}
initializeMap();
}
public void updatevertices(int pluckedNode){
for(AdjNode adjacentNode : g.list[pluckedNode]){
if(!visited.contains(adjacentNode.nodeNumber)){
int positionInHeap = map.get(adjacentNode.nodeNumber);
if(adjacentNode.edgeCost < heap[positionInHeap].edgeCost){
// //System.out.println(adjacentNode.nodeNumber + " not visited, Updating vertice " + heap[positionInHeap].nodeNumber + " from " + heap[positionInHeap].edgeCost + " to " + adjacentNode.edgeCost);
// heap[positionInHeap].edgeCost = INF;
// //heap[positionInHeap].edgeCost = adjacentNode.edgeCost;
// int heapifiedIndex = heapifyAt(positionInHeap); // This code follows my logic
// heap[heapifiedIndex].edgeCost = adjacentNode.edgeCost; // (which doesnt work)
// //heapifyAt(size - 1);
heap[positionInHeap].edgeCost = adjacentNode.edgeCost;
//heapifyAt(positionInHeap);
constructHeap(); // When replaced by SiftDown,
} // works as charm
}
}
}
public void printSet(){
Iterator<Integer> it = visited.iterator();
System.out.print("Printing set : [");
while(it.hasNext()){
System.out.print((int)it.next() + ", ");
}
System.out.println("]");
}
public AdjNode pluck(){
AdjNode min = heap[0];
int minNodeNumber = heap[0].nodeNumber;
AdjNode toRet = new AdjNode(min.nodeNumber, min.edgeCost);
heap[0].edgeCost = INF;
constructHeap();
visited.add(minNodeNumber);
updatevertices(minNodeNumber);
return toRet;
}
public int heapifyAt(int index){
if(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
while(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
swap(index, (int)Math.floor(index/2));
index = (int)Math.floor(index/2);
}
}else{
if(index*2 + 2 < size){
while(index*2 + 2 < size && (heap[index].edgeCost > heap[index*2 + 1].edgeCost|| heap[index].edgeCost > heap[index*2 + 2].edgeCost)){
if(heap[index*2 + 1].edgeCost < heap[index*2 + 2].edgeCost){
//swap with left child
swap(index, index*2 + 1);
index = index*2 + 1;
}else{
//swap with right child
swap(index, index*2 + 2);
index = index*2 + 2;
}
}
}
}
return index;
}
}
static class Graph{
int numberOfVertices;
AdjList[] list;
Graph(int numberOfVertices){
list = new AdjList[numberOfVertices];
for(int i=0; i<numberOfVertices; i++){
list[i] = new AdjList();
}
this.numberOfVertices = numberOfVertices;
}
public void addEdge(int from, int to, int cost){
this.list[from].add(to, cost);
this.list[to].add(from, cost);
}
public void printGraph(){
System.out.println("Printing Graph");
for(int i=0; i<numberOfVertices; i++){
System.out.print(i + " = ");
list[i].printList();
}
}
}
public static void prims(Graph graph, Heap heap){
int totalMin = INF;
int tempSize = graph.numberOfVertices;
while(tempSize>0){
AdjNode min = heap.pluck();
totalMin += min.edgeCost;
System.out.println("Added cost : " + min.edgeCost);
tempSize--;
}
System.out.println("Total min : " + totalMin);
}
public static void main(String[] args) throws Throwable {
Scanner in = new Scanner(new File("/home/mayur/Downloads/PrimsInput.txt"));
Graph graph = new Graph(in.nextInt());
in.nextInt();
while(in.hasNext()){
graph.addEdge(in.nextInt() - 1, in.nextInt() - 1, in.nextInt());
}
Heap heap = new Heap(graph);
prims(graph, heap);
}
}
With a proper implementation of heap, you should be able to bubble up and down. Heap preserves a group of elements using an order that applies to both directions and bubbling up and down are essentially the same, apart from the direction in which you move.
As to your implementation, I believe you are correct but one, seemingly minor issue: indexing.
If you look around for array implementations of heap, you will notice that in most cases the root is located at index 1, instead of 0. The reason for that being, in a 1-indexed array you preserve the following relation between parent p and children c1 and c2.
heap[i] = p
heap[2 * i] = c1
heap[2 * i + 1] = c2
It is trivial to draw an array on a piece of paper and see that this relation holds, if you have the root at heap[1]. The children of root, at index 1, are located at indices 2 and 3. Children of the node at index 2 are at indices 4 & 5, while children of the node at index 3 are at indices 6 & 7, and so on.
This relation helps you get to the children or the parent of any node at i, without having to keep track of where they are. (i.e. parent is at floor(i/2) and children are at 2i and 2i+1)
What you seem to have tried is a 0-indexed implementation of heap. Consequently you had to use a slightly different relation given below for parent p and children c1 and c2.
heap[i] = p
heap[2 * i + 1] = c1
heap[2 * i + 2] = c2
This seems to be ok when accessing the children. For example, the children of root, at index 0, are located at indices 1 and 2. Children of the node at index 1 are at indices 3 & 4, while children of the node at index 2 are at indices 5 & 6, and so on. However there is a pickle when accessing the parent of a node. If you consider node 3 and take floor(3/2), you do get index 1, which is the parent of 1. However, if you take the node at index 4, floor(4/2) gives you index 2, which is not the parent of the node at index 4.
Obviously, this adaptation of the index relationship between a parent and its children does not work for both children. Unlike the 1-indexed heap implementation, you can not treat both children the same while accessing their parents. Therefore, the problem lies specifically in your bubbling up part, without necessarily being related to bubbling up operation. As a matter of fact, though I haven't tested your code, the bubbling up portion of heapifyAt function seems to be correct.(i.e. except the indexing, of course)
Now, you may keep using a 0-indexed heap and adapt your code so that whenever you are looking for a node's parent, you implicitly check whether it is the right (i.e. not as in correct but as in the opposite of left) child of that parent and use floor((i-1)/2) if it is. Checking whether a node is the right child is trivial: just look if it is even or not. (i.e. as you index right children with 2i + 2, they will always be even)
However I recommend you take a different approach and instead use a 1-indexed array implementation of heap. The elegance of the array implementation of heap is that you can treat each node the same and you don't have to do anything different based on its index or location, with the root of the heap perhaps being the only possible exception to this.
I have a Graph class with a bunch of nodes, edges, etc. and I'm trying to perform Dijkstra's algorithm. I start off adding all the nodes to a priority queue. Each node has a boolean flag for whether it is already 'known' or not, a reference to the node that comes before it, and an int dist field that stores its length from the source node. After adding all the nodes to the PQ and then flagging the source node appropriately, I've noticed that the wrong node is pulled off the PQ first. It should be that the node with the smallest dist field comes off first (since they are all initialized to a a very high number except for the source, the first node off the PQ should be the source... except it isn't for some reason).
Below is my code for the algorithm followed by my compare method within my Node class.
public void dijkstra() throws IOException {
buildGraph_u();
PriorityQueue<Node> pq = new PriorityQueue<>(200, new Node());
for (int y = 0; y < input.size(); y++) {
Node v = input.get(array.get(y));
v.dist = 99999;
v.known = false;
v.prnode = null;
pq.add(v);
}
source.dist = 0;
source.known = true;
source.prnode = null;
int c=1;
while(c != input.size()) {
Node v = pq.remove();
//System.out.println(v.name);
//^ Prints a node that isn't the source
v.known = true;
c++;
List<Edge> listOfEdges = getAdjacent(v);
for (int x = 0; x < listOfEdges.size(); x++) {
Edge edge = listOfEdges.get(x);
Node w = edge.to;
if (!w.known) {
int cvw = edge.weight;
if (v.dist + cvw < w.dist) {
w.dist = v.dist + cvw;
w.prnode = v;
}
}
}
}
}
public int compare (Node d1, Node d2) {
int dist1 = d1.dist;
int dist2 = d2.dist;
if (dist1 > dist2)
return 1;
else if (dist1 < dist2)
return -1;
else
return 0;
}
Can anyone help me find the issue with my PQ?
The priority queue uses assumption that order doesn't change after you will insert the element.
So instead of inserting all of the elements to priority queue you can:
Start with just one node.
Loop while priority queue is not empty.
Do nothing, if element is "known".
Whenever you find smaller distance add it to priority queue with "right" weight.
So you need to store a sth else in priority queue, a pair: distance at insertion time, node itself.