最短路径(Dijkstra,Floyd,STFA)

基于贪心的迪杰斯特拉

每次寻找邻点最短路径,不断更新。

下面的两个版本只能用于无孤立顶点的图

邻接矩阵版 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];
				}
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值