1.最短路径
有Dijkstra算法和Floyd算法
图 | 算法 |
---|---|
无权图 | BFS |
有权图 单原 | Dijkstra 或者Floyd |
有权图 多原 | Floyd 或者多次Dijkstra |
复杂度:
- Dijkstra:n^2, 查找min distance的时候开业改用堆排序或者PriorityQueue,复杂度降为nlogn
- Floyd:n^3,空间复杂度 N的平方,dist[][] 可以一次性求出所有点之间的最短路径,适合多原最短路径问题
import java.util.Arrays;
import java.util.HashMap;
public class TestMinDistance {
static int MAX = 1000;
//Floyd算法
public int Floyd(int[][] map ,int start,int end) {
int len = map.length;
int[][] dist = new int[len][len];
//init
for(int i =0;i<len;i++) {
for(int j =0;j<len;j++) {
dist[i][j]=map[i][j];
}
}
//duyu K node
for(int k =0;k<len;k++) { //用每个节点,去更新
for(int i=0;i<len;i++) {
for(int j =0;j<len;j++) {
dist[i][j] = Math.min(dist[i][j], dist[i][k]+dist[k][j]);
}
}
}
return dist[start][end];
}
//Dijkstra算法
public int Dijkstra(int[][] map,int start,int end) {
int len = map.length;
int[] distance = new int[len];
Arrays.fill(distance,MAX);
boolean[] isVisited = new boolean[len];
//先通过起点设置distance
isVisited[start] =true;
for(int i = 0;i<len;i++) {
distance[i] = map[start][i];
}
//主循环,每次选择distance中未标记的最小点,用这个点去更新 distance
for(int i =1;i<len;i++) {
//find min
//这里可以用堆排序,或者PriorityQueue,这样复杂度为nlogn
int min = MAX;
int index = -1;
for(int j =0;j<len;j++) {
if(isVisited[j])continue;
//System.out.println(1);
if(min > distance[j]) {
min = distance[j];
index =j;
}
}
isVisited[index] = true;
for(int j =0;j<len;j++) {
int dis = distance[index] +map[index][j];
if(distance[j] > dis ) {
distance[j] = dis;
}
System.out.print(distance[j]+" ");
}
System.out.println();
}
return distance[end];
}
public static void main(String[] args) {
int MAX = TestDijkstra.MAX;
int[][] map = { //基于邻接矩阵的
{0,1,5,10,MAX},
{1,0,2,MAX,8},
{5,2,0,2,3},
{10,MAX,2,0,1},
{MAX,8,3,1,0}
};
TestMinDistancetd = new TestMinDistance();
System.out.println(td.Dijkstra(map, 3, 4));
System.out.println(td.Floyd(map, 0, 3));
}
}
2.最小生成树算法
prim算法和Dijkstra算法很像,只是求distance时候有点差别
这里实现了prim算法
import java.util.Arrays;
public class TestMinProduceTree {
static int MAX = 1000;
//最小生成树算法 prim
//和dijkstra算法的区别就是,每次更新distance的时候,只需要更新这个点到当前集合的值,而不是到原点的值
//distance 不需要加上 前面节点到原点的值
public int Prim(int[][] map, int start) {
int len = map.length;
int[] distance = new int[len]; //更新当前集合到剩下节点的距离
Arrays.fill(distance, MAX);
boolean[] isVisited = new boolean[len];
int[] node = new int[len];//保存节点加入生成树的顺序
int sum =0;//最小生成树的代价
//首次访问的节点加入
node[0] = start;
isVisited[start] = true;
for(int i =0;i<len;i++) {
distance[i] = map[start][i];
}
for(int i =1;i<len;i++) {
//find min
int min = MAX;
int index = -1;
for(int j=0;j<len;j++) {
if(isVisited[j])continue;
if(min > distance[j]) {
min = distance[j];
index = j;
}
}
//mark index node
isVisited[index] = true;
sum += min;
System.out.print(min+" ");
node[i] = index;
//new node update distance
for(int j=0;j<len;j++) {
if(isVisited[j])continue;
if(distance[j] > map[index][j]) { //最小生成树 这里跟新distance 和dijkstra不一样,更简单,其他都一样
distance[j] = map[index][j];
}
}
}
for(int i:node) {
System.out.print(i+" ");
}
return sum;
}
public static void main(String[] args) {
int MAX = TestMinProduceTree.MAX;
int[][] map = {
{0,5,1,5,MAX,MAX},
{5,0,5,MAX,3,MAX},
{1,5,0,5,6,4},
{5,MAX,5,0,MAX,2},
{0,3,6,MAX,0,6},
{MAX,MAX,4,2,6,0}
};
TestMinProduceTree tt = new TestMinProduceTree();
System.out.println(tt.Prim(map, 2));
}
}