数据结构与算法(15)

图的运用

1.最小生成树

最小生成树其实是最小权重生成树的简称。一个有n个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有n个结点,并且有保持图连通的最少的边。最小生成树可以用克鲁斯卡尔算法或普里姆算法求出。

最小生成树性质:设G=(V,E)是一个连通网络,U是顶点集V的一个非空真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。

普里姆算法

算法步骤:

1)首先将初始顶点u加入U中,对其余的每一顶点,将closedge[j]均初始化到u的边信息。

2)循环n-1次,做出以下处理:

        从各边closedge中选出最小边closedge[k],输出此边;

        将k加入u中

        更新剩余每组最小边信息closedge[j],对于U-V中的边,新增加了一条从k到j的边,如果新边的权值比closedge[j].lowcost小,则将closedge[j].lowcost更新为新边的权值。

算法:

struct {
	VerTexType adjvex;//最小边在U中的顶点 
	ArcType lowcast;//最小边上的权值 
} closedge[MVNum];

void MiniSpanTree_Prim(AMGraph G,VerTexType u) {
	k=Locatevex(G,u);//k为U顶点的下标 
	for(j=0; j<G.vexnum; ++j) {//进行初始化 
		if(j!=k)
			closedge[j]={u,G.zrc[k][j]};
		}
	closedge[k].lowcast=0;//初始U=u 
	for(i=1;i<G.vexnum;++i){
		//选择n-1个顶点,生成n-1条边 
		k=Min(closedge);
		//求出T的下一节点:第k个顶点,closedge[k]中存有当前最小边 
		u0=closedge[k].adjvex;
		v0=G.vex[k];
		cout<<u0<<v0;//输出当前最小边 
		closedge[k].lowcast=0;//第k个结点并入U 
		for(j=0;j<G.vexnum;++j){
			if(G.arcs[k][j]<closedge[j].lowcast)//新顶点并入后重新选择最小边 
				closedge[j]={G.vexs[k],G.arcs[k][j]};
		}
	}
}

2.最短路径

用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。迪杰斯特拉算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。

迪杰斯特拉算法基本思想:

创建两个表,OPEN, CLOSE。
OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
1. 访问路网中距离起始点最近且没有被检查过的点,把这个点放入OPEN组中等待检查。
2. 从OPEN表中找出距起始点最近的点,找出这个点的所有子节点,把这个点放到CLOSE表中。
3. 遍历考察这个点的子节点。求出这些子节点距起始点的距离值,放子节点到OPEN表中。
4. 重复第2和第3步,直到OPEN表为空,或找到目标点。

void ShortestPath_DIJ(int n) {
	int count = 0;          //count是已求出最短路径的顶点数目
	visit[0] = 1;
	prevetrix[0] = 0;
	count++;
	for (int i = 1; i < n; i++) {  //初始化
		dis[i] = graph[0][i];
		prevetrix[i] = 0;
	}
	while (count < n) {
		int min = INF, target_index;
		for (int i = 1; i < n; i++) {
			if (visit[i] == 0 && min > dis[i]) {       //找到距离源点最短的顶点target_index
				min = dis[i];
				target_index = i;
			}
		}
		visit[target_index] = 1;
		count++;
		for (int i = 1; i < n; i++) {
			if (visit[i] == 0 && dis[target_index] +
			        graph[target_index][i] < dis[i]) {          //更新
				dis[i] = dis[target_index] + graph[target_index][i];
				prevetrix[i] = target_index;
			}
		}
	}
}

求每一对顶点之间的最短距离(弗洛伊德算法)

1.在主函数中创建一个矩阵,存储输入的两点间的距离。
2.在Floyd函数中,初始化记录最短距离的矩阵和记录中介点的矩阵。初始化之后将主函数的矩阵复制给记录最短距离的矩阵。
3.用三层循环不断更新最短距离。

void ShortestPath_Floyd(AMGraph G) {
	for(i=0; i<G.vexnum; ++i) {//各对顶点之间初始已知路径及距离 
		for(j=0; j<G.vexnum; ++j) {
			D[i][j]=G.arcs[i][j];
			if(D[i][j]<MaxInt && i!=j)
				Path[i][j]=i;
			else
				Path[i][j]=-1;
		}

	}
	for(k=0; k<G.vexnum; ++k) {
		for(i=0; i<G.vexnum; ++i) {
			for(j=0; j<G.vexnum; ++j) {
				if(D[i][k]+D[k][j]<D[i][j]) {//从i经k到j的一条路径更短 
					D[i][j]=D[i][k]+D[k][j];//更新D[i][j] 
					Path[i][j]=Path[k][j];//更改j的前驱为k 
				}
			}
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值