基于贪心的迪杰斯特拉
每次寻找邻点最短路径,不断更新。
下面的两个版本只能用于无孤立顶点的图
邻接矩阵版 O(n^3)
public static int INF=65535;
public static int num=11;
public static int[] P=new int[num];//save the shortpath index
public static int[] D=new int[num];//the weight sum
public static int[][] D1=new int[num][num];
public static int[][] P1=new int[num][num];
public static Stack<Integer> st=new Stack();
public static void dijkstra(MGraph G,int v0)
{
int v,w,k,min;
k=-1;
int[] fin=new int[num];//v0至vw的最短路径
for(v=0;v<G.numVertexes;v++)
{
fin[v]=0;//zero sign the not find
D[v]=G.arc[v0][v];
P[v]=-1;
}
D[v0]=0;
fin[v0]=1;
//find the v0 to any point's shortest path
for(v=1;v<G.numVertexes;v++)
{
min=INF;
for(w=0;w<G.numVertexes;w++)//find the v0 closest point
{
if(fin[w]==0&&D[w]<min)
{
k=w;
min=D[w];
}
}
if(k!=-1)
fin[k]=1;
for(w=0;w<G.numVertexes;w++)
{
if(fin[w]==0&&(min+G.arc[k][w]<D[w]))
{
D[w]=min+G.arc[k][w];
P[w]=k;
}
}
}
}
邻接矩阵在处理贪心算法时读入速度不如邻接表快,下面是邻接表版本
邻接表节点类 分别存储边终点,权重以及下一个的指针
public class ArcNode {
int adjvex;
ArcNode next;
int weight;
}
表类 分别存储边起点索引和表头
public class VNode {
int data;
ArcNode first;
}
堆优化算法
在稀疏图中表现良好,在稳定性上,邻接矩阵的边界似乎更高,相比堆优化的e<<nloogn反而可以达到e<<n^2,目前有点不稳定,还在找原因,并且无法解决负权边的问题。
//发现在edge接近log2^V时 邻接表的的杰斯特拉算法开始不稳定
public static int num=9;
public static int INF=65535;
public static void Dijkstra(AdjGraph G,int v)
{
int ind=0;
Comparator<Node> compar=new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
// TODO Auto-generated method stub
return o1.dist-o2.dist;
}
};
PriorityQueue<Node> pq=new PriorityQueue<Node>(num,compar);
int[] D=new int[100];//distance weight
int[] P=new int[100];//path
for(int i=0;i<num;i++)
{
D[i]=INF;
}
Node e;
ArcNode p=G.adjlist[v].first;
while(p!=null)
{
int w=p.adjvex;//adjvex边的终点编号
D[w]=p.weight;
pq.offer(new Node(w,D[w]));
p=p.next;
}
P[v]=1;
for(ind=0;ind<num;ind++)
{
e=pq.poll();
int u=e.i;
if(P[u]==1)
{
continue;
}
P[u]=1;//move from the queue
p=G.adjlist[u].first;
while(p!=null)
{
int w=p.adjvex;
if(P[w]==0)
{
if(D[u]+p.weight<D[w])//前点加后点权重
{
D[w]=D[u]+p.weight;
pq.offer(new Node(w,D[w]));//change the D
}
}
p=p.next;
}
}
for(int index=0;index<num;index++)
{
if(index!=v)
{
System.out.println(v+"到"+index+"的最短路径长度:"+D[index]);
}
}
}
STFA
结合负权边问题,可以将堆优化问题再度优化,将邻接表存入二维数组当中,进行n^2的松弛操作,每次取最小边<u,v>,对v松弛,改变就入队,直到队列空,外循环控制出队,内循环控制入队。
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) //初始化
{
dist[j]=INFI;
inq[j]=false;
}
dist[i]=0;
node.add(i); //将起点纳入队列中
inq[i]=true;
while(!node.isEmpty())
{
int min_i=node.front(); //得到队列元素并出队
node.poll();
inq[min_i]=false; //元素出队
int len=List[min_i].size();
for(int j=0;j<len;j++) //对该点有影响的邻接点都进行松弛
{
int t=List[min_i][j]->id;
if(dist[t]>dist[min_i]+List[min_i][j]->W)
{
dist[t]=dist[min_i]+List[min_i][j]->W;
if(!inq[t]) //把不在队列里的元素入队
{
node.add(t);
inq[t]=true;
}
}
}
基于动态规划的Floyd
个人觉得这是目前见过最简朴的路径算法,核心思想是利用二维数组把复杂的路线问题转化为起点,终点和中转点之间的问题。时间复杂度在O(n^3)左右,求多源最多路径问题相对方便。
public static void Floyd(MGraph G)
{
int v,w,k;
for(v=0;v<G.numVertexes;v++)
{
for(w=0;w<G.numVertexes;w++)
{
D1[v][w]=G.arc[v][w];
P1[v][w]=w;
}
}
for(k=0;k<G.numVertexes;k++)
{
for(v=0;v<G.numVertexes;v++)
{
for(w=0;w<G.numVertexes;w++)
{
if(D1[v][w]>D1[v][k]+D1[w][k])//如果经过下标为k的路径比原两点间的短
{
D1[v][w]=D1[v][k]+D1[k][w];
P1[v][w]=P1[v][k];
}
}
}
}
}