SPFA的两种优化方法——SLF和LLL

一、SLF(Small Label First) 优化

优化思路:将原队列改成双端队列,对要加入队列的点 p,如果 dist[p] 小于队头元素 u 的 dist[u],将其插入到队头,否则插入到队尾。

//SLF优化
void spfa_slf(int s,int t,GH *G)//起点s,终点t,图G
{
   
	//节点编号从0开始
	int n=G->vexnum;//节点个数
	int *dist=new int[n];//距离数组
	bool *visit=new bool[n];//访问标记数组
	int *pre=new int[n];;//前驱
	AR *p;

	//初始化
	memset(dist,0x3f,n*sizeof(int));
	memset(visit,0,n*sizeof(bool));
	memset(pre,-1,n*sizeof(int));
	deque<int>Q;//建立双端队列,并将起点入队
	visit[s]=1;
	dist[s]=0;
	Q.push_back(s);
	//进行操作
	while (!Q.empty())
	{
   
		int cur=Q.front();
		Q.pop_front();
		visit[cur]=0;//出队节点取消标记
		p=G->N[cur].next;
		while (p)//遍历出队节点的直接后继
		{
   
			if (dist[p->index] > dist[cur] + (p->weight))//需要进行松弛操作
			{
   
				dist[p->index]=dist[cur] + (p->weight);
				pre[p->index]=cur;
				if (!visit[p->index])
				{
   
					visit[p->index]=1;
					if(!Q.empty() && dist[p->index] < dist[Q.front()])//根据dist[p->index]与dist[Q.front()]的大小关系,决定p->index插入到队头还是队尾
						Q.push_front(p->index);
					else
						Q.push_back(p->index);
				}
			}
			p=p->next;
		}
	}

	if (dist[t] == INF)
		cout<<"两点不连通."<<endl;
	else//输出最短路径
	{
   
		cout<<"存在长度为"<<dist[t]<<"的最短路径:"<<endl;
		int *path=new int[n];//存放路径
		int top=-1;
		int q=t;
		while (q != -1)//将前驱入栈
		{
   
			top++;
			path[top]=q;
			q=pre[q];
		}
		for (; top > 0; top--)
			cout<<G->vexname[path[top]]<<"-->";
		cout<<G->vexname[path[0]]<<endl;
		delete []path;
	}

	delete []dist;
	delete []visit;
	delete []pre;
}

二、LLL(Large Label Last) 优化

优化思路:对每个要出队的队头元素 u,比较 dist[u] 和队列中点的 dist 的平均值,如果 dist[u] 更大,将其弹出放到队尾,然后取队首元素进行相同操作,直到队头元素的 dist 小于等于平均值。

//LLL优化
void spfa_lll(int s,int t,GH *G)//起点s,终点t,图G
{
   
	//节点编号从0开始
	int n=G->vexnum;//节点个数
	int *dist=new int[n];//距离数组
	bool *visit=new bool[n];//访问标记数组
	int *pre=new int[n];//前驱数组
	int num;//队列中点的个数
	int sum;//队列中点的dist之和
	AR *p;

	//初始化
	memset(dist,0x3f,n*sizeof(
  • 21
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值