prim最小生成树算法
1.任意选取一个起始顶点,并将它添加到最小生成树中。
2.将所有含起始顶点的边按照权重次序添加到minheap(最小堆)中。
3.从最小堆中取出最小边,并将这条边和那个新顶点添加到最小生成树中。
4.我们往minheap中添加所有含新顶点且另一顶点不在最小生成树中的边。
5.重复这一过程直到最小生成树含有原始图中的所有顶点时结束。
public Network mstNetwork()
{
int x, y;
int index;
double weight;
int[] edge = new int[2];
Heap<Double> minHeap = new Heap<Double>();
Network<T> resultGraph = new Network<T>();
if (isEmpty() || !isConnected())
return resultGraph;
resultGraph.adjMatrix = new double[numVertices][numVertices];
for (int i = 0; i < numVertices; i++)
for (int j = 0; j < numVertices; j++)
resultGraph.adjMatrix[i][j] = Double.POSITIVE_INFINITY;
resultGraph.vertices = (T[])(new Object[numVertices]);
boolean[] visited = new boolean[numVertices];
for (int i = 0; i < numVertices; i++)
visited[i] = false;
edge[0] = 0;
resultGraph.vertices[0] = this.vertices[0];
resultGraph.numVertices++;
visited[0] = true;
/** Add all edges, which are adjacent to the starting vertex,
to the heap */
for (int i = 0; i < numVertices; i++)
minHeap.addElement(new Double(adjMatrix[0][i]));
while ((resultGraph.size() < this.size()) && !minHeap.isEmpty())
{
/** Get the edge with the smallest weight that has exactly
one vertex already in the resultGraph */
do
{
weight = (minHeap.removeMin()).doubleValue();
edge = getEdgeWithWeightOf(weight, visited);
} while (!indexIsValid(edge[0]) || !indexIsValid(edge[1]));
x = edge[0];
y = edge[1];
if (!visited[x])
index = x;
else
index = y;
/** Add the new edge and vertex to the resultGraph */
resultGraph.vertices[index] = this.vertices[index];
visited[index] = true;
resultGraph.numVertices++;
resultGraph.adjMatrix[x][y] = this.adjMatrix[x][y];
resultGraph.adjMatrix[y][x] = this.adjMatrix[y][x];
/** Add all edges, that are adjacent to the newly added vertex,
to the heap */
for (int i = 0; i < numVertices; i++)
{
if (!visited[i] && (this.adjMatrix[i][index] <
Double.POSITIVE_INFINITY))
{
edge[0] = index;
edge[1] = i;
minHeap.addElement(new Double(adjMatrix[index][i]));
}
}
}
return resultGraph;
}
最短路径:
A:两个顶点之间的最小边数
将广度优先遍历算法转变成寻找最短路径的算法
在遍历期间为每个顶点多存储两个信息
1. 从起始点到本顶点的路径长度,以及本顶点的前驱顶点
2. 起始顶点到本顶点的长度。
接着修改循环,使得当抵达目标顶点时循环终止,最短路径数就是从起始顶点到目标顶点前驱的路径长度再加1;如果要输出最短路径上的顶点,只需沿着前驱链回溯即可。
protected Iterator<Integer> iteratorShortestPathIndices
(int startIndex, int targetIndex)
{
int index = startIndex;
int[] pathLength = new int[numVertices];
int[] predecessor = new int[numVertices];
LinkedQueue<Integer> traversalQueue = new LinkedQueue<Integer>();
ArrayUnorderedList<Integer> resultList =
new ArrayUnorderedList<Integer>();
if (!indexIsValid(startIndex) || !indexIsValid(targetIndex) ||
(startIndex == targetIndex))
return resultList.iterator();
boolean[] visited = new boolean[numVertices];
for (int i = 0; i < numVertices; i++)
visited[i] = false;
traversalQueue.enqueue(new Integer(startIndex));
visited[startIndex] = true;
pathLength[startIndex] = 0;
predecessor[startIndex] = -1;
while (!traversalQueue.isEmpty() && (index != targetIndex))
{
index = (traversalQueue.dequeue()).intValue();
/** Update the pathLength for each unvisited vertex adjacent
to the vertex at the current index. */
for (int i = 0; i < numVertices; i++)
{
if (adjMatrix[index][i] && !visited[i])
{
pathLength[i] = pathLength[index] + 1;
predecessor[i] = index;
traversalQueue.enqueue(new Integer(i));
visited[i] = true;
}
}
}
if (index != targetIndex) // no path must have been found
return resultList.iterator();
LinkedStack<Integer> stack = new LinkedStack<Integer>();
index = targetIndex;
stack.push(new Integer(index));
do
{
index = predecessor[index];
stack.push(new Integer(index));
} while (index != startIndex);
while (!stack.isEmpty())
resultList.addToRear(((Integer)stack.pop()));
return resultList.iterator();
}
B:加权图的最小路径
使用一个minheap或优先队列来存储顶点,基于总权重(从起始顶点到本顶点的权重和)来衡量顶点对。这样我们总是能优先沿着最便宜的路径来游历图。
对每个顶点,都必须存储该顶点的标签,从起始顶点到本顶点的最便宜的路径的权重,路径上本顶点的前驱。在minheap中将存储顶点,对每条已经遇到但尚未游历的候选路径来权衡顶点对。从minheap取出顶点的时候,会权衡取自minheap的顶点对;如果遇到一个顶点的权重小于目前顶点中已存储的权重,则更新路径的代价。
protected Iterator<Integer> iteratorShortestPathIndices
(int startIndex, int targetIndex)
{
int index;
double weight;
int[] predecessor = new int[numVertices];
Heap<Double> traversalMinHeap = new Heap<Double>();
ArrayUnorderedList<Integer> resultList =
new ArrayUnorderedList<Integer>();
LinkedStack<Integer> stack = new LinkedStack<Integer>();
int[] pathIndex = new int[numVertices];
double[] pathWeight = new double[numVertices];
for (int i = 0; i < numVertices; i++)
pathWeight[i] = Double.POSITIVE_INFINITY;
boolean[] visited = new boolean[numVertices];
for (int i = 0; i < numVertices; i++)
visited[i] = false;
if (!indexIsValid(startIndex) || !indexIsValid(targetIndex) ||
(startIndex == targetIndex) || isEmpty())
return resultList.iterator();
pathWeight[startIndex] = 0;
predecessor[startIndex] = -1;
visited[startIndex] = true;
weight = 0;
/** Update the pathWeight for each vertex except the
startVertex. Notice that all vertices not adjacent
to the startVertex will have a pathWeight of
infinity for now. */
for (int i = 0; i < numVertices; i++)
{
if (!visited[i])
{
pathWeight[i] = pathWeight[startIndex] +
adjMatrix[startIndex][i];
predecessor[i] = startIndex;
traversalMinHeap.addElement(new Double(pathWeight[i]));
}
}
do
{
weight = (traversalMinHeap.removeMin()).doubleValue();
traversalMinHeap = new Heap<Double>();
if (weight == Double.POSITIVE_INFINITY) // no possible path
return resultList.iterator();
else
{
index = getIndexOfAdjVertexWithWeightOf(visited, pathWeight,
weight);
visited[index] = true;
}
/** Update the pathWeight for each vertex that has has not been
visited and is adjacent to the last vertex that was visited.
Also, add each unvisited vertex to the heap. */
for (int i = 0; i < numVertices; i++)
{
if (!visited[i])
{
if((adjMatrix[index][i] < Double.POSITIVE_INFINITY) &&
(pathWeight[index] + adjMatrix[index][i]) < pathWeight[i])
{
pathWeight[i] = pathWeight[index] + adjMatrix[index][i];
predecessor[i] = index;
}
traversalMinHeap.addElement(new Double(pathWeight[i]));
}
}
} while (!traversalMinHeap.isEmpty() && !visited[targetIndex]);
index = targetIndex;
stack.push(new Integer(index));
do
{
index = predecessor[index];
stack.push(new Integer(index));
} while (index != startIndex);
while (!stack.isEmpty())
resultList.addToRear((stack.pop()));
return resultList.iterator();
}