迪杰斯特拉
步骤:
package algorithm.dijkstra;
import java.util.Arrays;
public class DijkstraDemo {
public static final int INF = 65535;
public static void main(String[] args) {
char[] village = {'A','B','C','D','E','F','G'};
int[][] distance = {
{0, 5, 7, INF, INF, INF, 2},
{5, 0, INF, 9, INF, INF, 3},
{7, INF, 0, INF, 8, INF, INF},
{INF, 9, INF, 0, INF, 4, INF},
{INF, INF, 8, INF, 0, 5, 4},
{INF, INF, INF, 4, 5, 0, 6},
{2, 3, INF, INF, 4, 6, 0},
};
Graph graph = createCountrySide(village, distance);
graph.traverse();
int startIndex = 6; // 出发顶点的下标
VertexCollection vc = new VertexCollection(graph.vertexNum, startIndex);
System.out.println("\n处理前~");
print(vc,graph);
dijkstra(graph, vc, startIndex);
System.out.println("\n处理后~");
print(vc,graph);
}
private static void dijkstra(Graph graph, VertexCollection vc, int index) {
updateDisAndPre(graph, vc, index); // 更新出发顶点与相邻顶点的距离
for (int i = 0; i < graph.vertexNum - 1; i++) { // 已处理完一个顶点(出发顶点)
index = selectNewIndex(graph, vc); // 选择并返回新的访问顶点
updateDisAndPre(graph, vc, index); // 更新当前顶点的周围顶点到出发顶点的距离(当前顶点可能作为一个中间顶点) 和 周围顶点的前驱顶点
}
}
// 挑选新的访问顶点(从visited数组中挑选未被访问的)
private static int selectNewIndex(Graph graph, VertexCollection vc) {
int minIndex = -1;
int minDistance = 65535;
for (int i = 0; i < vc.visited.length; i++) { // 选出 [没有被访问过] 且跟[出发顶点距离最短的边]
if (vc.visited[i] != 1 && vc.dis[i] < minDistance) {
minIndex = i;
minDistance = vc.dis[i];
}
}
// 选出后,标记选中顶点为已访问顶点
vc.visited[minIndex] = 1;
return minIndex;
}
// 更新当前顶点的周围顶点到出发顶点的距离(当前顶点可能作为一个中间顶点) 和 周围顶点的前驱顶点
private static void updateDisAndPre(Graph graph, VertexCollection vc, int index) {
for (int i = 0; i < graph.edges[index].length; i++) { // 遍历当前顶点所包含的边
int distance = vc.dis[index] + graph.edges[index][i]; // distance = (出发顶点-当前顶点的距离) + (当前顶点-周围顶点的距离)
if (vc.visited[i] != 1 && distance < vc.dis[i]) { // 判断 distance 和 出发顶点直接到周围顶点的距离(周围顶点要未被访问)
vc.pre[i] = index; // 条件成立,则当前顶点为中间顶点,它是周围顶点的前趋顶点
vc.dis[i] = distance; // 将周围顶点到出发顶点的距离设置为distance
}
}
}
private static Graph createCountrySide(char[] village, int[][] distance) {
Graph graph = new Graph(village.length);
for (int i = 0; i < village.length; i++) {
graph.vertexs[i] = village[i];
for (int j = 0; j < village.length; j++) {
graph.edges[i][j] = distance[i][j];
}
}
return graph;
}
private static void print(VertexCollection vc, Graph graph) {
System.out.print("visited:");
for (int i = 0; i < vc.visited.length; i++) {
System.out.print(vc.visited[i] + " ");
}
System.out.println();
System.out.print("pre:");
for (int i = 0; i < vc.pre.length; i++) {
System.out.print(vc.pre[i] + " ");
}
System.out.println();
System.out.print("dis:");
for (int i = 0; i < vc.dis.length; i++) {
if (vc.dis[i] != 65535)
System.out.print("("+ graph.vertexs[i] + ")"+vc.dis[i] + " ");
else {
System.out.print(vc.dis[i] + " ");
}
}
System.out.println();
}
}
class Graph{
public int vertexNum;
public int edgeNum;
public char[] vertexs;
public int[][] edges;
public Graph(int vertexsNum) {
this.vertexNum = vertexsNum;
this.edgeNum = 0;
this.vertexs = new char[vertexsNum];
edges = new int[vertexsNum][vertexsNum];
}
public void traverse() {
System.out.println("村庄分布如下:");
for (int[] edge : this.edges) {
System.out.println(Arrays.toString(edge));
}
}
}
// 辅助顶点集合
class VertexCollection{
public int[] visited; // 标记已访问的顶点
public int[] dis; // 记录出发顶点到各顶点的距离
public int[] pre; // 记录顶点对应的前趋顶点(中间顶点)
public VertexCollection(int vertexNum, int startIndex) {
this.visited = new int[vertexNum];
this.dis = new int[vertexNum];
this.pre = new int[vertexNum];
this.visited[startIndex] = 1;
Arrays.fill(dis, 65535);
this.dis[startIndex] = 0;
}
}
弗洛伊德算法
步骤:
package algorithm.floyd;
import java.util.Arrays;
public class FloydDemo {
public static final int INF = 65535;
public static void main(String[] args) {
char[] village = {'A','B','C','D','E','F','G'};
int[][] distance = {
{0, 5, 7, INF, INF, INF, 2},
{5, 0, INF, 9, INF, INF, 3},
{7, INF, 0, INF, 8, INF, INF},
{INF, 9, INF, 0, INF, 4, INF},
{INF, INF, 8, INF, 0, 5, 4},
{INF, INF, INF, 4, 5, 0, 6},
{2, 3, INF, INF, 4, 6, 0},
};
Graph graph = createCountrySide(village, distance);
graph.traverse();
int[][] pre = getPre(graph); // 获取前驱关系表
int[][] dis = getDis(graph); // 获取距离表
System.out.println("处理前两表如下:");
print(graph, pre, dis);
System.out.println("处理前de最短路径:");
printRes(graph, pre, dis);
System.out.println("\n处理后de最短路径:");
floyd(pre, dis);
printRes(graph, pre, dis);
System.out.println("处理后两表如下:");
print(graph, pre, dis);
}
private static void floyd(int[][] pre, int[][] dis) {
for (int k = 0; k < pre.length; k++) { // 遍历中间顶点(就是前驱顶点数组)-[A,B,C,D,E,F,G]
for (int i = 0; i < dis.length; i++) { // 寻找中间顶点关联的两条边(遍历距离表)
for (int j = 0; j < dis.length; j++) {
int distance = dis[i][k] + dis[k][j]; // 获取中间顶点关联的两条边总距离
if (distance < dis[i][j]) {
dis[i][j] = distance;
pre[i][j] = pre[k][j];
}
}
}
}
}
private static int[][] getDis(Graph graph) {
int[][] dis = new int[graph.vertexNum][graph.vertexNum];
for (int i = 0; i < graph.vertexNum; i++) {
for (int j = 0; j < graph.vertexNum; j++) {
dis[i][j] = graph.edges[i][j];
}
}
return dis;
}
private static int[][] getPre(Graph graph) {
int[][] pre = new int[graph.vertexNum][graph.vertexNum];
for (int i = 0; i < pre.length; i++) {
Arrays.fill(pre[i], i);
}
return pre;
}
private static Graph createCountrySide(char[] village, int[][] distance) {
Graph graph = new Graph(village.length);
for (int i = 0; i < village.length; i++) {
graph.vertexs[i] = village[i];
for (int j = 0; j < village.length; j++) {
graph.edges[i][j] = distance[i][j];
}
}
return graph;
}
private static void print(Graph graph, int[][] pre, int[][] dis) {
System.out.println("前驱关系表:");
for (int i = 0; i < pre.length; i++) {
for (int j = 0; j < pre.length; j++) {
System.out.print(graph.vertexs[pre[i][j]] + " ");
}
System.out.println();
}
System.out.println("\n距离表:");
for (int i = 0; i < dis.length; i++) {
for (int j = 0; j < dis.length; j++) {
if (dis[i][j] != 65535) {
System.out.print(dis[i][j] + " ");
} else {
System.out.print("N ");
}
}
System.out.println();
}
System.out.print("-----------------------------------------------------");
System.out.println("--------------------------------------------------");
}
private static void printRes(Graph graph, int[][] pre, int[][] dis) {
for (int k = 0; k < pre.length; k++) { // 遍历所有的中间顶点
for (int i = 0; i < pre.length; i++) {
System.out.print(graph.vertexs[pre[k][i]] + " "); // 输出前驱顶点(即中间顶点)
}
System.out.println();
for (int j = 0; j < dis.length; j++) {
System.out.print("[" + graph.vertexs[k] + "->" + graph.vertexs[j] + " = " + dis[k][j] + "],");
}
System.out.println("\n");
}
System.out.print("-----------------------------------------------------");
System.out.println("--------------------------------------------------");
}
}
class Graph{
public int vertexNum;
public int edgeNum;
public char[] vertexs;
public int[][] edges;
public Graph(int vertexNum) {
this.vertexNum = vertexNum;
this.edgeNum = 0;
this.vertexs = new char[vertexNum];
edges = new int[vertexNum][vertexNum];
}
public void traverse() {
System.out.println("村庄分布如下:");
for (int[] edge : this.edges) {
System.out.println(Arrays.toString(edge));
}
System.out.println();
}
}