我正在尝试编写一个程序,该程序将使用Kruskal和Prim的算法找到给定无向加权图的MST。我已经在程序中成功实现了Kruskal的算法,但我遇到了Prim的问题。更确切地说,我无法弄清楚如何实际构建Prim函数,以便它遍历图中的所有顶点。我在程序执行期间遇到一些IndexOutOfBoundsException错误。我不确定其他人需要多少信息来了解到目前为止我所做的事情,但希望不会有太多无用的信息。
这是我到目前为止所做的:
我有Graph
,Edge
和Vertex
类。
Vertex类主要只是一个包含顶点名称(数字)的信息存储。
Edge类可以创建一个获取参数(Vertex start, Vertex end, int edgeWeight)
的新Edge。该类具有返回常用信息的方法,如起始顶点,结束顶点和权重。
Graph类从文本文件中读取数据,并将新边添加到ArrayList。文本文件还告诉我们图表有多少椎骨,也存储了。
在Graph
类中,我有一个Prim()方法,它应该计算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;
}
方法findClosesNeighbour()如下所示:
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
和ArrayList<Edges> graph
。
Visited()-method只是一个布尔检查,用于查看所访问的ArrayList是否包含我们正考虑迁移到的Vertex。我独立测试了findClosestNeighbour()
并且它似乎正在工作但是如果有人发现它有问题,那么反馈也是受欢迎的。
主要是因为我提到我的问题是实际在Prim()方法中构建主循环,如果需要任何其他信息我很乐意提供它。
谢谢。
编辑:用Prim()方法澄清我的思路。我想要做的是首先随机化图表中的起点。在那之后,我将找到与该起点最近的邻居。然后我们将添加将这两个点连接到MST的边,并将顶点添加到访问列表以便稍后检查,这样我们就不会在图中形成任何循环。
这是抛出的错误:
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)
第203行:findClosestNeighbour()
中的return neighbour.get(0);
第179行:Prim()
中的Edge e = findClosestNeighbour(startingVertex);
答案 0 :(得分:0)
Vertex startingVertex = edges.get(rnd.nextInt(G.returnVertexCount())).returnStartingVertex();
这使用顶点计数来索引边缘列表,混合顶点和边缘。
// 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);
}
这不应该每次都将相同的startingVertex传递给findClosestNeighbour。
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.
}
这里s
是什么?这似乎不考虑边缘权重。它正在跳过最后一个边缘,当边缘是非方向性时,它只检查结束顶点。
答案 1 :(得分:0)
// Simple weighted graph representation
// Uses an Adjacency Linked Lists, suitable for sparse graphs /*undirected
9 一个 乙 C d Ë F G H 一世 A B 1 B C 2 C E 7 E G 1 G H 8 F H 3 F D 4 D E 5 我F 9 我3 A D 1 这是我用来保存为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();
}
}