Dijkstra's algorithm java implementation bug - java

So first of all this is HW, so try not to just give me the answer right away, but I'm having trouble programming Dijstra's Algorithm. The lab has us build a priority Queue, which I have made and passes the given JUnit tests so I think it's correct. The second part of the lab had us use the queue in an implementation of dijstra's algorithm. Here is my code for Dijkstra's
/**
* Compute shortest paths in a graph.
*
* Your constructor should compute the actual shortest paths and
* maintain all the information needed to reconstruct them. The
* returnPath() function should use this information to return the
* appropriate path of edge ID's from the start to the given end.
*
* Note that the start and end ID's should be mapped to vertices using
* the graph's get() function.
*/
class ShortestPaths {
Multigraph graph;
final int INF = Integer.MAX_VALUE;
PriorityQueue<Integer> Q;
int n;
int dist[];
Handle handles[];
Edge edge[];
/**
* Constructor
*/
public ShortestPaths(Multigraph G, int startId) {
Q = new PriorityQueue<Integer>();
graph = G;
n = graph.nVertices();
dist = new int [n];
edge = new Edge [n];
handles = new Handle[n];
for (int i = 0; i<n; i++){
dist[i] = INF;
}
dist[startId] = 0;
Handle h = Q.insert(startId, dist[startId]);
handles[startId] = h;
Q = new PriorityQueue<Integer>();
while (!Q.isEmpty()){
Vertex v = graph.get(Q.min());
Q.extractMin();
while (v.adj().hasNext()){
relax(v.adj().next());
}
}
}
private void relax(Edge e) {
Handle h;
int v = e.from().id();
int w = e.to().id();
if (dist[w] > dist[v] + e.weight()) {
dist[w] = dist[v] + e.weight();
edge[w] = e;
if (handles[w].getIndex() != -1){
Q.decreaseKey(handles[w], dist[w]);
}
else{
h = Q.insert(w, dist[w]);
handles[w] = h;
}
}
}
/**
* Calculates the list of edge ID's forming a shortest path from the start
* vertex to the specified end vertex.
*
* #return the array
*/
public int[] returnPath(int endId) {
int c = 0;
int[] path = new int[edge.length];
for (Edge e = edge[endId]; e != null; e = edge[e.from().id()]) {
path[c] = e.id();
c++;
}
return path;
}
}
Just so you know, a handle is simply an object which stores the index of the associated key-value pair, that way we can find it later. The handles update automatically, you can see this in the swap procedure in my priority queue. Anyway, The issue is that my edge[] array is populated with null for some reason, so I can't return any paths. How do I fix my algorithm to update edge[] correctly? Any help would be appreciated. Just tell me if you would like more information. Also I will post the Vertex and Edge classes in case you want to look at those.

I noticed one error:
Q = new PriorityQueue<Integer>();
while (!Q.isEmpty()){ // <-- Q is always empty beсause of previous line

Related

MST - Revert hamiltonian path to cycle

I've got this code to find a minimum spanning tree for given graph. I need to revert this algorithm to get an hamiltonian cycle instead of hamiltonian path. Can u help me to revert this code to get an hamiltonian cycle? I need it to Travelling Salesman Problem. I tried to remove and change this fragment of code responsible to discarding next_edge if edge causes cycle and add additional edge from vertices 1-2, but when i removed it, a program returns arrayIndexOutOfBoundsException, and when I changed if(x != y) to if(x==y) or delete this conditional, output graph were refilled by 0.
I'm very beginner in programming and I can't resolve this problem by myself.
It is the code:
import java.util.*;
import java.lang.*;
import java.io.*;
class Graph {
// A class to represent a graph edge
class Edge implements Comparable<Edge> {
int src, dest, weight;
// Comparator function used for sorting edges
// based on their weight
public int compareTo(Edge compareEdge) {
return this.weight - compareEdge.weight;
}
};
// A class to represent a subset for union-find
class subset {
int parent, rank;
};
int V, E; // V-> no. of vertices & E->no.of edges
Edge edge[]; // collection of all edges
// Creates a graph with V vertices and E edges
Graph(int v, int e) {
V = v;
E = e;
edge = new Edge[E];
for (int i = 0; i < e; ++i) {
edge[i] = new Edge();
}
}
// A utility function to find set of an element i
// (uses path compression technique)
int find(subset subsets[], int i) {
// find root and make root as parent of i (path compression)
if (subsets[i].parent != i) {
subsets[i].parent = find(subsets, subsets[i].parent);
}
return subsets[i].parent;
}
// A function that does union of two sets of x and y
// (uses union by rank)
void Union(subset subsets[], int x, int y) {
int xroot = find(subsets, x);
int yroot = find(subsets, y);
// Attach smaller rank tree under root of high rank tree
// (Union by Rank)
if (subsets[xroot].rank < subsets[yroot].rank) {
subsets[xroot].parent = yroot;
} else if (subsets[xroot].rank > subsets[yroot].rank) {
subsets[yroot].parent = xroot;
}
// If ranks are same, then make one as root and increment
// its rank by one
else {
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}
// The main function to construct MST using Kruskal's algorithm
void KruskalMST() {
Edge result[] = new Edge[V]; // Tnis will store the resultant MST
int e = 0; // An index variable, used for result[]
int i = 0; // An index variable, used for sorted edges
for (i = 0; i < V; ++i) {
result[i] = new Edge();
}
// Step 1: Sort all the edges in non-decreasing order of their
// weight. If we are not allowed to change the given graph, we
// can create a copy of array of edges
Arrays.sort(edge);
// Allocate memory for creating V ssubsets
subset subsets[] = new subset[V];
for (i = 0; i < V; ++i) {
subsets[i] = new subset();
}
// Create V subsets with single elements
for (int v = 0; v < V; ++v) {
subsets[v].parent = v;
subsets[v].rank = 0;
}
i = 0; // Index used to pick next edge
// Number of edges to be taken is equal to V-1
while (e < V - 1) {
// Step 2: Pick the smallest edge. And increment
// the index for next iteration
Edge next_edge = new Edge();
next_edge = edge[i++];
int x = find(subsets, next_edge.src);
int y = find(subsets, next_edge.dest);
// If including this edge does't cause cycle,
// include it in result and increment the index
// of result for next edge
if (x != y) {
result[e++] = next_edge;
Union(subsets, x, y);
}
// Else discard the next_edge
}
// print the contents of result[] to display
// the built MST
System.out.println("Following are the edges in " +
"the constructed MST");
for (i = 0; i < e; ++i)
System.out.println(result[i].src + " -- " +
result[i].dest + " == " + result[i].weight);
}
// Driver Program
public static void main (String[] args) {
/* Let us create following weighted graph
10
0--------1
| \ |
6| 5\ |15
| \ |
2--------3
4 */
int V = 4; // Number of vertices in graph
int E = 5; // Number of edges in graph
Graph graph = new Graph(V, E);
// add edge 0-1
graph.edge[0].src = 0;
graph.edge[0].dest = 1;
graph.edge[0].weight = 10;
// add edge 0-2
graph.edge[1].src = 0;
graph.edge[1].dest = 2;
graph.edge[1].weight = 6;
// add edge 0-3
graph.edge[2].src = 0;
graph.edge[2].dest = 3;
graph.edge[2].weight = 5;
// add edge 1-3
graph.edge[3].src = 1;
graph.edge[3].dest = 3;
graph.edge[3].weight = 15;
// add edge 2-3
graph.edge[4].src = 2;
graph.edge[4].dest = 3;
graph.edge[4].weight = 4;
graph.KruskalMST();
}
}

Algorithm for finding the maximum number of vertices you can visit, given a start point and a maximum distance you can travel

I have an undirected graph with positive edge weights. I am given a start point and the maximum amount of distance I can travel, and in the end, I must return to the start point. What sort of algorithm can do this for me, and give me the path that results?
I understand java well, so if you can, please make code samples look similar to java.
Like I said a DFS should do the trick, this sample code gives the idea. But beware, this sample code don't handle cyclic reference, you will have to do that
public class Answer {
private static final int MAX_WEIGHT = 11;
public static void main(String[] args) {
Node node1 = new Node("node 1");
Node node1_1 = new Node("node 1-1");
Node node1_1_1 = new Node("node 1-1-1");
Node node1_2 = new Node("node 1-2");
Node node1_2_1 = new Node("node 1-2-1");
Node node1_2_1_1 = new Node("node 1-2-1-1");
node1.addNeighbour(node1_1, 1);
node1_1.addNeighbour(node1_1_1, 2);
node1.addNeighbour(node1_2, 1);
node1_2.addNeighbour(node1_2_1, 2);
node1_2_1.addNeighbour(node1_2_1_1, 3);
System.out.println("max of nodes = " + travel(node1, 0));
}
private static int travel(Node node, int totalWeight) {
int maxNodes = 1;
for (Map.Entry<Node, Integer> entry : node.neighbours.entrySet()) {
Integer weight = entry.getValue();
int nodes = 1;
if ((totalWeight + weight) * 2 <= MAX_WEIGHT) {
nodes += travel(entry.getKey(), totalWeight + weight);
}
if (nodes > maxNodes) {
maxNodes = nodes;
}
}
return maxNodes;
}
}
class Node {
String id;
Map<Node, Integer> neighbours;
public Node(String id) {
this.id = id;
neighbours = new HashMap<Node, Integer>();
}
public void addNeighbour(Node node, int weight) {
neighbours.put(node, weight);
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("Node{");
sb.append("id='").append(id).append('\'');
sb.append(", neighbours=").append(neighbours);
sb.append('}');
return sb.toString();
}
}
I now realise this is still NP-hard, even if vertices can be visited more than once: Hamiltonian Path is NP-hard even on unweighted graphs, so we are free to create an instance of your problem using arbitrarily chosen weights. Specifically, given an instance (G = (V, E), k) of Hamiltonian Path, we can create an instance (G' = (V', E'), w, s, d) of your problem in which:
V' = V, plus a new vertex, s
E' = E, plus the edge (s, u) for every vertex u in V
The weight w(e) of every edge e in E' is 1
The starting point is s
The maximum total travel distance is |V|+1.
If the solution to this instance is |V|+1 distinct vertices, then clearly it contains every vertex in G' exactly once, so removing the vertex s from the cycle will leave a path through all the remaining vertices, i.e., a Hamiltonian path in the original graph G. If the solution to this instance is less than |V|+1, then no Hamiltonian path exists in G -- since if one did, we would indeed have gotten a solution of |V|+1.
So, if your problem could be solved in polynomial time, then so could an NP-complete problem. That means that it's very unlikely that your problem can be solved in polynomial time.

Compressing a list of intervals

I need to compress a list of intervals into a smaller list. Let me explain:
For example I have a list containing intervals [1,4],[2,5],[5,7],[10,11],[13,20],[19,21] and i want to join the intersecting intervals and return a list [1,7],[10,11],[13,21] that transforming intersecting intervals into a single longer interval.
For this I wrote this method:
public List compress(List<Interval> intervals) {
for (int j = 0; j < intervals.size(); j++) {
Interval a = intervals.get(j);
int aIndex = j;
for (int i = 1 + aIndex; i < intervals.size(); i++) {
Interval b = intervals.get(i);
if (a.intersects(b)) {
//the union method return a union of two intervals. For example returns [1,7] for [1,4] and [2,5]
intervals.add(j, a.union(b));
intervals.remove(j+1);
intervals.remove(i);
}
}
}
return intervals;
}
This seems to work fine for the first pair of intervals that are checked but it stops there. That is the final output is a list containing [1, 5],[5, 7],[10, 11],[13, 20],[19, 21].
I have found that this may be a problem with illegal removing of elements from a list? https://codereview.stackexchange.com/questions/64011/removing-elements-on-a-list-while-iterating-through-it?newreg=cc3f30e670e24cc2b05cd1fa2492906f
But I have no idea how to get around this.
Please can anyone give me a hint.
Notice: Sorry if I did anything wrong as this is my first post to stackoverflow. And thanks to anyone that will try to help.
UPDATE:
Here is the solution I found after Maraboc proposed to create a copy of the list and manipulate that one.
That seems to work.
public List compress(List<Interval> intervals) {
List<Interval> man = intervals;
for (int j = 0; j < intervals.size(); j++) {
Interval a = intervals.get(j);
int aIndex = j;
for (int i = 1 + aIndex; i < intervals.size(); i++) {
Interval b = intervals.get(i);
if (a.intersects(b)) {
a = a.union(b);
man.add(j,a);
man.remove(j+1);
man.remove(i);
i--;
}
}
}
return intervals;
}
Thank you everyone.
You are actually NOT using iterator, you are using for-cycles and select elements from list based on their position, therefore you do not have to be afraid of "I am not able to remove while iterating" issue.
I posted this question first to stackexchange by mistake. They redirected me to this place and the question was put on hold. But before that happened Maraboc[a link](https://codereview.stackexchange.com/users/87685/maraboc
)
Helped with an idea. He told me to create a new list and modify that one. I did that and it seems to work. The updated solution will be in the updated question.
Just for the fun of it I took an existing Interval Tree and added a minimise method that seems to work nicely.
/**
* Title: IntervlTree
*
* Description: Implements a static Interval Tree. i.e. adding and removal are not possible.
*
* This implementation uses longs to bound the intervals but could just as easily use doubles or any other linear value.
*
* #author OldCurmudgeon
* #version 1.0
* #param <T> - The Intervals to work with.
*/
public class IntervalTree<T extends IntervalTree.Interval> {
// My intervals.
private final List<T> intervals;
// My center value. All my intervals contain this center.
private final long center;
// My interval range.
private final long lBound;
private final long uBound;
// My left tree. All intervals that end below my center.
private final IntervalTree<T> left;
// My right tree. All intervals that start above my center.
private final IntervalTree<T> right;
public IntervalTree(List<T> intervals) {
if (intervals == null) {
throw new NullPointerException();
}
// Initially, my root contains all intervals.
this.intervals = intervals;
// Find my center.
center = findCenter();
/*
* Builds lefts out of all intervals that end below my center.
* Builds rights out of all intervals that start above my center.
* What remains contains all the intervals that contain my center.
*/
// Lefts contains all intervals that end below my center point.
final List<T> lefts = new ArrayList<>();
// Rights contains all intervals that start above my center point.
final List<T> rights = new ArrayList<>();
long uB = Long.MIN_VALUE;
long lB = Long.MAX_VALUE;
for (T i : intervals) {
long start = i.getStart();
long end = i.getEnd();
if (end < center) {
lefts.add(i);
} else if (start > center) {
rights.add(i);
} else {
// One of mine.
lB = Math.min(lB, start);
uB = Math.max(uB, end);
}
}
// Remove all those not mine.
intervals.removeAll(lefts);
intervals.removeAll(rights);
uBound = uB;
lBound = lB;
// Build the subtrees.
left = lefts.size() > 0 ? new IntervalTree<>(lefts) : null;
right = rights.size() > 0 ? new IntervalTree<>(rights) : null;
// Build my ascending and descending arrays.
/**
* #todo Build my ascending and descending arrays.
*/
}
/*
* Returns a list of all intervals containing the point.
*/
List<T> query(long point) {
// Check my range.
if (point >= lBound) {
if (point <= uBound) {
// Gather all intersecting ones.
List<T> found = intervals
.stream()
.filter((i) -> (i.getStart() <= point && point <= i.getEnd()))
.collect(Collectors.toList());
// Gather others.
if (point < center && left != null) {
found.addAll(left.query(point));
}
if (point > center && right != null) {
found.addAll(right.query(point));
}
return found;
} else {
// To right.
return right != null ? right.query(point) : Collections.<T>emptyList();
}
} else {
// To left.
return left != null ? left.query(point) : Collections.<T>emptyList();
}
}
/**
* Blends the two lists together.
*
* If the ends touch then make them one.
*
* #param a
* #param b
* #return
*/
static List<Interval> blend(List<Interval> a, List<Interval> b) {
// Either empty - lreturn the other.
if (a.isEmpty()) {
return b;
}
if (b.isEmpty()) {
return a;
}
Interval aEnd = a.get(a.size() - 1);
Interval bStart = b.get(0);
ArrayList<Interval> blended = new ArrayList<>();
// Do they meet?
if (aEnd.getEnd() >= bStart.getStart() - 1) {
// Yes! merge them.
// Remove the last.
blended.addAll(a.subList(0, a.size() - 1));
// Add a combined one.
blended.add(new SimpleInterval(aEnd.getStart(), bStart.getEnd()));
// Add all but the first.
blended.addAll(b.subList(1, b.size()));
} else {
// Just join them.
blended.addAll(a);
blended.addAll(b);
}
return blended;
}
static List<Interval> blend(List<Interval> a, List<Interval> b, List<Interval>... more) {
List<Interval> blended = blend(a, b);
for (List<Interval> l : more) {
blended = blend(blended, l);
}
return blended;
}
List<Interval> minimise() {
// Calculate min of left and right.
List<Interval> minLeft = left != null ? left.minimise() : Collections.EMPTY_LIST;
List<Interval> minRight = right != null ? right.minimise() : Collections.EMPTY_LIST;
// My contribution.
long meLeft = minLeft.isEmpty() ? lBound : Math.max(lBound, minLeft.get(minLeft.size() - 1).getEnd());
long meRight = minRight.isEmpty() ? uBound : Math.min(uBound, minRight.get(0).getEnd());
return blend(minLeft,
Collections.singletonList(new SimpleInterval(meLeft, meRight)),
minRight);
}
private long findCenter() {
//return average();
return median();
}
protected long median() {
if (intervals.isEmpty()) {
return 0;
}
// Choose the median of all centers. Could choose just ends etc or anything.
long[] points = new long[intervals.size()];
int x = 0;
for (T i : intervals) {
// Take the mid point.
points[x++] = (i.getStart() + i.getEnd()) / 2;
}
Arrays.sort(points);
return points[points.length / 2];
}
/*
* What an interval looks like.
*/
public interface Interval {
public long getStart();
public long getEnd();
}
/*
* A simple implemementation of an interval.
*/
public static class SimpleInterval implements Interval {
private final long start;
private final long end;
public SimpleInterval(long start, long end) {
this.start = start;
this.end = end;
}
#Override
public long getStart() {
return start;
}
#Override
public long getEnd() {
return end;
}
#Override
public String toString() {
return "{" + start + "," + end + "}";
}
}
/**
* Test code.
*
* #param args
*/
public static void main(String[] args) {
/**
* #todo Needs MUCH more rigorous testing.
*/
// Test data.
long[][] data = {
{1, 4}, {2, 5}, {5, 7}, {10, 11}, {13, 20}, {19, 21},};
List<Interval> intervals = new ArrayList<>();
for (long[] pair : data) {
intervals.add(new SimpleInterval(pair[0], pair[1]));
}
// Build it.
IntervalTree<Interval> test = new IntervalTree<>(intervals);
// Check minimise.
List<Interval> min = test.minimise();
System.out.println("Minimise test: ---");
System.out.println(min);
}
}
For your algorithm to work, the intervals must be sorted, say by start.
Then the for-i loop can make a the longest possible interval.
if (a.intersects(b)) {
a = a.union(b);
intervals.remove(i);
--i; // So we remain at old i value.
}
} // for i
intervals.set(j, a);
The reason for these requirements is that intervals A, B, C might form one long interval ABC, whereas C. B, A might.
Indeed the problem is that when you remove an element from the list, then all subsequent elements will be shifted. At around j I'm guessing it doesn't change because you insert then remove an item at the same location. But the removal at position i will shift all elements in the list.
What you could be doing, instead of removing the elements, is to put a null value at that position, so that the indices remain the same. You will then have to perform a final pass to remove null elements from the array (and check for nulls before comparing).
You could also run your inner loop backwards (from max i down to j) so that any element that gets shifted after i has already been processed.

Chromatic Polynomials from a graph

I have an assignment where I have to compute the Chromatic Polynomials of a graph. According to the “Fundamental Reduction Theorem”:
A recursive way of computing the chromatic polynomial is based on edge contraction: for a pair of adjacent vertices u and v the graph Guv is obtained by merging the two vertices and removing the edge between them. Then the chromatic polynomial satisfies the recurrence relation:
P(G, x) = P(G − uv, x) − P(Guv, x)
where u and v are adjacent vertices and G − uv is the graph with the edge uv removed.
Likewise, Chromatic Polynomials can be found when by:
A recursive way of computing the chromatic polynomial is based on edge contraction: for a pair of non-adjacent vertices u and v the graph Guv is obtained by merging the two vertices and adding the edge between them. Then the chromatic polynomial satisfies the recurrence relation
P(G, x) = P(G + uv, x) + P(Guv, x)
where u and v are adjacent vertices and G + uv is the graph with the edge uv added.
It was determined for this assignment that when we want to make null graphs based on the previous formula was when the edges of the graph is <= (the number of vertices) * ((number of vertices-1)/4). This is the “break point” for determining if it is more efficient to go toward null graphs or complete graphs.
Additionally, I have a class for creating Polynomials. So I don’t have to post two classes I’ll the Polynomial class here summarize here:
Constructors:
Polynomial() – creates a constant polynomial P(x) = 1.
Polynomial(int a)- creates a linear polynomial of the form P(x) = x + a.
Polynomial(int a, int b) – creates a polynomial of the form a * x^b.
int degree() – returns the degree of the polynomial.
Polynomial plus(Polynomial b) – returns the sum of this polynomial and b, i.e, c = this + b
Polynomial minus(Polynomial b) – returns the difference of this polynomial and , i.e, c = this–b
Polynomial times(Polynomial b) – returns the product of this polynomial and b, return (this*b)
Polynomial compose(Polynomial b)- returns the composite of this polynomial and b. return this(b(x)) – compute using Horner’s method.
boolean equals(Polynomial b)- returns true whenever this polynomial and b are identical.
int evaluate(int x)- evaluate this polynomial at x. return this(x).
Polynomial differentiate()- return the derivative of the polynomial.
String toString()- return the textual representation of this polynomial.
The following is the Graph class. It uses a Bag data structure array that is implemented using a linked list. So for example, all vertices that are adjacent to vertex 0 will be in the Bag located at Bag[0]. I need help doing the recursive part where it computes a Chromatic Polynomial. I have some comments of questions I have in the chromaticPolynomial method as well as mergeVertices method. I am not sure if what I am thinking in these two methods is correct and would appreciate anyone’s help on it. Thanks in advance.
import java.util.Arrays;
public class Graph {
private final int V;
private int E;
private Bag<Integer>[] adj;
/**
* Create an empty graph with V vertices.
*/
public Graph(int V) {
if (V < 0) throw new RuntimeException("Number of vertices must be nonnegative");
this.V = V;
this.E = 0;
adj = (Bag<Integer>[]) new Bag[V];
for (int v = 0; v < V; v++) {
adj[v] = new Bag<Integer>();
}
}
/**
* Create a random graph with V vertices and E edges.
* Expected running time is proportional to V + E.
*/
public Graph(int V, int E) {
this(V);
if (E < 0) throw new RuntimeException("Number of edges must be nonnegative");
for (int i = 0; i < E; i++) {
int v = (int) (Math.random() * V);
int w = (int) (Math.random() * V);
addEdge(v, w);
}
}
/**
* Create a digraph from input stream.
*/
public Graph(In in) {
this(in.readInt());
int E = in.readInt();
for (int i = 0; i < E; i++) {
int v = in.readInt();
int w = in.readInt();
addEdge(v, w);
}
}
/**
* Copy constructor.
*/
public Graph(Graph G) {
this(G.V());
this.E = G.E();
for (int v = 0; v < G.V(); v++) {
// reverse so that adjacency list is in same order as original
Stack<Integer> reverse = new Stack<Integer>();
for (int w : G.adj[v]) {
reverse.push(w);
}
for (int w : reverse) {
adj[v].add(w);
}
}
}
/**
* Return the number of vertices in the graph.
*/
public int V() { return V; }
/**
* Return the number of edges in the graph.
*/
public int E() { return E; }
/**
* Add the edge v-w to graph.
*/
public void addEdge(int v, int w) {
E++;
adj[v].add(w);
adj[w].add(v);
}
/**
* Remove edge from v-w to graph.
*/
public void removeEdge(int v, int w){
E--;
adj[v].remove(w);
adj[w].remove(v);
}
public Polynomial chromaticPolynomial(Graph G){
// null graph is reached, return a polynomial that is G1.minus(G2)
if(G.V() == 0) return new Polynomial(); // how do I create a Chromatic Polynomial when this condition is reached?
// complete graph is reached, return a polynomial that is G1.plus(G2). If the number of vertices in a complete graph is n, then the number of edges is equal to n(n-1)/2.
if(G.E() == ((G.V() - (G.V() - 1))/2)) return new Polynomial(); // how do I create a Chromatic Polynomial when this condtion is reached?
// head toward a null graph.
if(G.E() <= G.V()*(G.V()-1/4)){
/**
for every vertex (u) and every edge (v) from that vertex, create a graph that has an edge removed (G1)
and a graph with merged vertices (G2), then recurse until a null graph is reached.
*/
for(int u = 0; u < G.V(); u++){
for(int v : adj[u]){
Graph G1 = new Graph(G);
Graph G2 = new Graph(G);
G1.removeEdge(u,v);
G2.mergeVertices(u,v);
chromaticPolynomial(G1);
chromaticPolynomial(G2);
// reutrn a polynomial here?
}
}
}
// head towards a complete graph.
else{
/**
for every vertex (u) and every edge (v) from that vertex, create a graph that has an edge added (G1) and
a graph with merged verticies (G2), then recures unitl all these graphs are a complete graph.
*/
for(int u = 0; u < G.V(); u++){
for(int v : adj[u]){
Graph G1 = new Graph(G);
Graph G2 = new Graph(G);
G1.addEdge(u,v);
G2.mergeVertices(u,v);
chromaticPolynomial(G1);
chromaticPolynomial(G2);
// return a polynomial here?
}
}
}
// return nothing. It didn't work.
return null;
}
public void mergeVertices(int vert1, int vert2){
// edge has already been removed between these two.
// just have to renumber the vertices so one is "removed"
/**
does this look correct?
*/
for(int u = 0; u < this.V(); u++){
for(int w: adj[u]){
if(w > vert1 || w > vert2) w--;
if(u > vert1 || u > vert2) u--;
}
}
}
/**
* Return the list of neighbors of vertex v as in Iterable.
*/
public Iterable<Integer> adj(int v) {
return adj[v];
}
/**
* Return a string representation of the graph.
*/
public String toString() {
StringBuilder s = new StringBuilder();
String NEWLINE = System.getProperty("line.separator");
s.append(V + " vertices, " + E + " edges " + NEWLINE);
for (int v = 0; v < V; v++) {
s.append(v + ": ");
for (int w : adj[v]) {
s.append(w + " ");
}
s.append(NEWLINE);
}
return s.toString();
}

Prim's MST algorithm implementation with Java

I'm trying to write a program that'll find the MST of a given undirected weighted graph with Kruskal's and Prim's algorithms. I've successfully implemented Kruskal's algorithm in the program, but I'm having trouble with Prim's. To be more precise, I can't figure out how to actually build the Prim function so that it'll iterate through all the vertices in the graph. I'm getting some IndexOutOfBoundsException errors during program execution. I'm not sure how much information is needed for others to get the idea of what I have done so far, but hopefully there won't be too much useless information.
This is what I have so far:
I have a Graph, Edge and a Vertex class.
Vertex class mostly just an information storage that contains the name (number) of the vertex.
Edge class can create a new Edge that has gets parameters (Vertex start, Vertex end, int edgeWeight). The class has methods to return the usual info like start vertex, end vertex and the weight.
Graph class reads data from a text file and adds new Edges to an ArrayList. The text file also tells us how many vertecis the graph has, and that gets stored too.
In the Graph class, I have a Prim() -method that's supposed to calculate the MST:
public ArrayList<Edge> Prim(Graph G) {
ArrayList<Edge> edges = G.graph; // Copies the ArrayList with all edges in it.
ArrayList<Edge> MST = new ArrayList<Edge>();
Random rnd = new Random();
Vertex startingVertex = edges.get(rnd.nextInt(G.returnVertexCount())).returnStartingVertex(); // This is just to randomize the starting vertex.
// This is supposed to be the main loop to find the MST, but this is probably horribly wrong..
while (MST.size() < returnVertexCount()) {
Edge e = findClosestNeighbour(startingVertex);
MST.add(e);
visited.add(e.returnStartingVertex());
visited.add(e.returnEndingVertex());
edges.remove(e);
}
return MST;
}
The method findClosesNeighbour() looks like this:
public Edge findClosestNeighbour(Vertex v) {
ArrayList<Edge> neighbours = new ArrayList<Edge>();
ArrayList<Edge> edges = graph;
for (int i = 0; i < edges.size() -1; ++i) {
if (edges.get(i).endPoint() == s.returnVertexID() && !visited(edges.get(i).returnEndingVertex())) {
neighbours.add(edges.get(i));
}
}
return neighbours.get(0); // This is the minimum weight edge in the list.
}
ArrayList<Vertex> visited and ArrayList<Edges> graph get constructed when creating a new graph.
Visited() -method is simply a boolean check to see if ArrayList visited contains the Vertex we're thinking about moving to. I tested the findClosestNeighbour() independantly and it seemed to be working but if someone finds something wrong with it then that feedback is welcome also.
Mainly though as I mentioned my problem is with actually building the main loop in the Prim() -method, and if there's any additional info needed I'm happy to provide it.
Thank you.
Edit: To clarify what my train of thought with the Prim() method is. What I want to do is first randomize the starting point in the graph. After that, I will find the closest neighbor to that starting point. Then we'll add the edge connecting those two points to the MST, and also add the vertices to the visited list for checking later, so that we won't form any loops in the graph.
Here's the error that gets thrown:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at Graph.findClosestNeighbour(graph.java:203)
at Graph.Prim(graph.java:179)
at MST.main(MST.java:49)
Line 203: return neighbour.get(0); in findClosestNeighbour()
Line 179: Edge e = findClosestNeighbour(startingVertex); in Prim()
Vertex startingVertex = edges.get(rnd.nextInt(G.returnVertexCount())).returnStartingVertex();
This uses the vertex count to index an edge list, mixing up vertices and edges.
// This is supposed to be the main loop to find the MST, but this is probably horribly wrong..
while (MST.size() < returnVertexCount()) {
Edge e = findClosestNeighbour(startingVertex);
MST.add(e);
visited.add(e.returnStartingVertex());
visited.add(e.returnEndingVertex());
edges.remove(e);
}
This shouldn't be passing the same startingVertex to findClosestNeighbour each time.
public Edge findClosestNeighbour(Vertex v) {
ArrayList<Edge> neighbours = new ArrayList<Edge>();
ArrayList<Edge> edges = graph;
for (int i = 0; i < edges.size() -1; ++i) {
if (edges.get(i).endPoint() == s.returnVertexID() && !visited(edges.get(i).returnEndingVertex())) {
neighbours.add(edges.get(i));
}
}
return neighbours.get(0); // This is the minimum weight edge in the list.
}
What is s here? This doesn't look like it's taking the edge weights into account. It's skipping the last edge, and it's only checking the ending vertex, when the edges are non-directional.
// Simple weighted graph representation
// Uses an Adjacency Linked Lists, suitable for sparse graphs /*undirected
9
A
B
C
D
E
F
G
H
I
A B 1
B C 2
C E 7
E G 1
G H 8
F H 3
F D 4
D E 5
I F 9
I A 3
A D 1
This is the graph i used saved as graph.txt
*/
import java.io.*;
import java.util.Scanner;
class Heap
{
private int[] h; // heap array
private int[] hPos; // hPos[h[k]] == k
private int[] dist; // dist[v] = priority of v
private int MAX;
private int N; // heap size
// The heap constructor gets passed from the Graph:
// 1. maximum heap size
// 2. reference to the dist[] array
// 3. reference to the hPos[] array
public Heap(int maxSize, int[] _dist, int[] _hPos)
{
N = 0;
MAX = maxSize;
h = new int[maxSize + 1];
dist = _dist;
hPos = _hPos;
}
public boolean isEmpty()
{
return N == 0;
}
public void siftUp( int k)
{
int v = h[k];
h[0] = 0;
dist[0] = Integer.MIN_VALUE;
//vertex using dist moved up heap
while(dist[v] < dist[h[k/2]]){
h[k] = h[k/2]; //parent vertex is assigned pos of child vertex
hPos[h[k]] = k;//hpos modified for siftup
k = k/2;// index of child assigned last parent to continue siftup
}
h[k] = v;//resting pos of vertex assigned to heap
hPos[v] = k;//index of resting pos of vertex updated in hpos
//display hpos array
/* System.out.println("\nThe following is the hpos array after siftup: \n");
for(int i = 0; i < MAX; i ++){
System.out.println("%d", hPos[i]);
}
System.out.println("\n Following is heap array after siftup: \n");
for (int i = 0; i < MAX; i ++ ){
System.out.println("%d" , h[i]);
}*/
}
//removing the vertex at top of heap
//passed the index of the smallest value in heap
//siftdown resizes and resorts heap
public void siftDown( int k)
{
int v, j;
v = h[k];
while(k <= N/2){
j = 2 * k;
if(j < N && dist[h[j]] > dist[h[j + 1]]) ++j; //if node is > left increment j child
if(dist[v] <= dist[h[j]]) break;//if sizeof parent vertex is less than child stop.
h[k] = h[j];//if parent is greater than child then child assigned parent pos
hPos[h[k]] = k;//update new pos of last child
k = j;//assign vertex new pos
}
h[k] = v;//assign rest place of vertex to heap
hPos[v] = k;//update pos of the vertex in hpos array
}
public void insert( int x)
{
h[++N] = x;//assign new vertex to end of heap
siftUp( N);//pass index at end of heap to siftup
}
public int remove()
{
int v = h[1];
hPos[v] = 0; // v is no longer in heap
h[N+1] = 0; // put null node into empty spot
h[1] = h[N--];//last node of heap moved to top
siftDown(1);//pass index at top to siftdown
return v;//return vertex at top of heap
}
}
class Graph {
class Node {
public int vert;
public int wgt;
public Node next;
}
// V = number of vertices
// E = number of edges
// adj[] is the adjacency lists array
private int V, E;
private Node[] adj;
private Node z;
private int[] mst;
// used for traversing graph
private int[] visited;
private int id;
// default constructor
public Graph(String graphFile) throws IOException
{
int u, v;
int e, wgt;
Node t;
FileReader fr = new FileReader(graphFile);
BufferedReader reader = new BufferedReader(fr);
String splits = " +"; // multiple whitespace as delimiter
String line = reader.readLine();
String[] parts = line.split(splits);
System.out.println("Parts[] = " + parts[0] + " " + parts[1]);
V = Integer.parseInt(parts[0]);
E = Integer.parseInt(parts[1]);
// create sentinel node
z = new Node();
z.next = z;
// create adjacency lists, initialised to sentinel node z
adj = new Node[V+1];
for(v = 1; v <= V; ++v)
adj[v] = z;
// read the edges
System.out.println("Reading edges from text file");
for(e = 1; e <= E; ++e)
{
line = reader.readLine();
parts = line.split(splits);
u = Integer.parseInt(parts[0]);
v = Integer.parseInt(parts[1]);
wgt = Integer.parseInt(parts[2]);
System.out.println("Edge " + toChar(u) + "--(" + wgt + ")--" + toChar(v));
// write code to put edge into adjacency matrix
t = new Node(); t.vert = v; t.wgt = wgt; t.next = adj[u]; adj[u] = t;
t = new Node(); t.vert = u; t.wgt = wgt; t.next = adj[v]; adj[v] = t;
}
}
// convert vertex into char for pretty printing
private char toChar(int u)
{
return (char)(u + 64);
}
// method to display the graph representation
public void display() {
int v;
Node n;
for(v=1; v<=V; ++v){
System.out.print("\nadj[" + toChar(v) + "] ->" );
for(n = adj[v]; n != z; n = n.next)
System.out.print(" |" + toChar(n.vert) + " | " + n.wgt + "| ->");
}
System.out.println("");
}
//use the breath first approach to add verts from the adj list to heap
//uses 3 arrays where array = # of verts in graph
//parent array to keep track of parent verts
// a dist matrix to keep track of dist between it and parent
//hpos array to track pos of vert in the heap
public void MST_Prim(int s)
{
int v, u;
int wgt, wgt_sum = 0;
int[] dist, parent, hPos;
Node t;
//declare 3 arrays
dist = new int[V + 1];
parent = new int[V + 1];
hPos = new int[V +1];
//initialise arrays
for(v = 0; v <= V; ++v){
dist[v] = Integer.MAX_VALUE;
parent[v] = 0;
hPos[v] = 0;
}
dist[s] = 0;
//d.dequeue is pq.remove
Heap pq = new Heap(V, dist, hPos);
pq.insert(s);
while (! pq.isEmpty())
{
// most of alg here
v = pq.remove();
wgt_sum += dist[v];//add the dist/wgt of vert removed to mean spanning tree
//System.out.println("\nAdding to MST edge {0} -- ({1}) -- {2}", toChar(parent[v]), dist[v], toChar[v]);
dist[v] = -dist[v];//mark it as done by making it negative
for(t = adj[v]; t != z; t = t.next){
u = t.vert;
wgt = t.wgt;
if(wgt < dist[u]){ //weight less than current value
dist[u] = wgt;
parent[u] = v;
if(hPos[u] == 0)// not in heap insert
pq.insert(u);
else
pq.siftUp(hPos[u]);//if already in heap siftup the modified heap node
}
}
}
System.out.print("\n\nWeight of MST = " + wgt_sum + "\n");
//display hPos array
/*System.out.println("\nhPos array after siftUp: \n");
for(int i = 0; i < V; i ++){
System.out.println("%d", hPos[i]);
}*/
mst = parent;
}
public void showMST()
{
System.out.print("\n\nMinimum Spanning tree parent array is:\n");
for(int v = 1; v <= V; ++v)
System.out.println(toChar(v) + " -> " + toChar(mst[v]));
System.out.println("");
}
}
public class PrimLists {
public static void main(String[] args) throws IOException
{
int s = 2;
String fname = "graph.txt";
Graph g = new Graph(fname);
g.display();
}
}

Categories

Resources