`
ql213
  • 浏览: 11465 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

贪心策略之求解稀疏边的最小生成树-Kruskal算法

阅读更多

最小生成树问题是贪心策略的经典应用,其中Kruskal算法用来求解边数不是特别多的(例如完全图)图的最小生成树。这里我们以无向连通图为例。

 

Kruskal算法的核心思想是按照边的从小到大的顺序依次加入到点集中,直到加入n-1条边,设无向连通图有n个顶点。

 

Kruskal算法一般包含如下重要步骤:

 

1. 边集按照权值由小到大的顺序排序--时间复杂度是 O(e*log(e) ) (e为边数)

 

2. 检查待加入的边是否和当前求得的点集构成回路--时间复杂度是 O(n) (n为当前求得点集的顶点数)

 

3. 点集的合并-如果用数组形式,时间复杂度是 O(n) (待加入的点所在点集合的顶点数)

 

由此看出,Kruskal算法总的时间复杂度主要由排序决定,所以为 O(e*log(e) ) (e为边数)。

显然,对于稀疏边的图,Kruskal算法是很适合的。

 

在实现算法的时候,数据结构的设计是十分重要的,特别是对于检查回路和点集的合并。合理的设计数据结构并充分利用Java的集合类将大大简化实现的难度。

 

主体类:

 

import greedyProgramming.SimpleGraphics.Edge;
import java.util.List;

/**
 * 稀疏边图的最小生成树的Kruskal算法实现
 * @author ql_math
 *
 */
public class KruskalForMinimumSpanningTree implements MinimumSpanningTreeGeneration{
	
	public double generateMinimumSpanningTree(double[][] graphicArray)
	{
		SimpleGraphics graph=new SimpleGraphics(graphicArray);
		List<Edge> sortedEdges = graph.sortGraphicEdges();//按照边的长度排序(短的在前)
		
		int n=graph.getPSize();//顶点数目
		int i=0,j=0;
		double shortestLength=0;
		
		while(i<sortedEdges.size())//贪心思想加入当前权值最小的边并检查是否含有回路
		{
			Edge e=sortedEdges.get(i++);
			
			Point stP=e.startPoint;
			Point edP=e.endPoint;
			
			if(stP.getBelongToList().contains(edP))//当前待加入的边加入后形成回路
				continue;
			
			stP.getBelongToList().addAll(edP.getBelongToList());//合并两个不同的点集
			edP.setBelongToList(stP.getBelongToList());//保持所属集合一致性

			j++;//合服要求的边数+1
			shortestLength+=e.length;
			
			if(j==n-1)
				break;

		}
	
		return shortestLength;
		
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		MinimumSpanningTreeGeneration st=new KruskalForMinimumSpanningTree();
		double[][] graphicArray={{0,0,300,80,50},{0,0,70,75,200},
				{300,70,0,60,0},{80,75,60,0,90},{50,200,0,90,0}};
		System.out.println("最小生成树的权值和是:"+st.generateMinimumSpanningTree(graphicArray));
	}

}

 

 

 数据结构类:

SimpleGraphics类

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class SimpleGraphics {
	
	public final static double ERROR=1e-3;
	
	/**无向图的邻接矩阵表示*/
	private int[][] adjArray;
	
	/**无向图的数组表示*/
	private double[][] graphArray;
	
	/**点集合*/
	private Point[] points;

	/**点个数*/
	private int pSize;
	
	static class Edge implements Comparable<Edge>
	{
		Point startPoint;
		Point endPoint;
		
		double length;
		
		Edge(Point point1,Point point2, double value)
		{
			startPoint=point1;
			endPoint=point2;
			length=value;
		}

		@Override
		public int compareTo(Edge o) {
			if(length-o.length>ERROR)
				return 1;
			if(o.length>ERROR)
				return -1;
			
			return 0;
		}
	}

	
	/**
	 * 无向图的二维数组表示
	 * @param graphArray
	 */
	public SimpleGraphics(double[][] graphArray)
	{
		this.graphArray=graphArray;
		pSize=graphArray.length;
		points=new Point[pSize];
		for(int i=0; i<pSize;i++)
			points[i]=new Point(i);
	}
	
	/**
	 * 
	 * @return
	 */
	public List<Edge> sortGraphicEdges()
	{
		
		List<Edge> eList=new LinkedList<Edge>();
		
		for(int i=0;i<pSize;i++)
		{
			for(int j=0;j<i;j++)
			{
				if(graphArray[i][j]>0)
				{
					eList.add(new Edge(points[i],points[j],graphArray[i][j]));
				}
			}
		}
		
		Collections.sort(eList);
		
		return new ArrayList<Edge>(eList);
	}
	
	public Point[] getPoints()
	{
		return points;
	}
	
	public void setPoints(Point[] points) {
		this.points = points;
	}

	
	
	public void updateGraphicArray(int i, int j, double value)
	{
		graphArray[i][j]=value;
	}
	
	public void updateAdjacencyArray(int i, int j, int status)
	{
		adjArray[i][j]=status;
	}
	
	public void setGraphicArray(double[][] graphArray)
	{
		this.graphArray=graphArray;
	}
	
	public double[][] getGraphicArray()
	{
		return graphArray;
	}
	
	public int getConnectionStatus(int i, int j)
	{
		return adjArray[i][j];
	}
	
	public void setAdjacencyArray(int[][] adjArray)
	{
		this.adjArray=adjArray;
	}
	
	public int[][] getAdjacencyArray()
	{
		return adjArray;
	}
	
	public int getPSize() {
		return pSize;
	}

	public void setPSize(int size) {
		pSize = size;
	}

	/**
	 * 获得与当前点连接的点集合
	 * @param start_point
	 * @return
	 */
	public double[] getAdjacencyPoints(int start_point) {
		return graphArray[start_point];
	}


}

 

 

Point类

import java.util.ArrayList;
import java.util.List;

public class Point {
	
	private int index;
	
	/**和该点相连的点集*/
	private List<Point> connectedToList;
	
	/**该点属于的点集*/
	private List<Point> belongToList=new ArrayList<Point>();
	

	public Point(int index)
	{
		this.index=index;
		belongToList.add(this);	
	}

	
	public int getIndex() {
		return index;
	}


	public void setIndex(int index) {
		this.index = index;
	}


	public List<Point> getBelongToList() {
		return belongToList;
	}


	public void setBelongToList(List<Point> belongToList) {
		this.belongToList = belongToList;
	}
	

	public void setConnectedToList(List<Point> connectedToList) {
		this.connectedToList = connectedToList;
	}


	public List<Point> getConnectedToList() {
		return connectedToList;
	}

}

 

1
1
分享到:
评论

相关推荐

    cpp-图论算法最小生成树Prim算法和Kruskal算法C实现

    Kruskal算法同样基于贪心策略,但它的核心是按照边的权重对所有边进行排序,然后依次选择未造成环路的边加入到最小生成树中。具体步骤如下: 1. 将所有边按权重升序排序。 2. 初始化一个并查集(Disjoint Set)数据...

    用Prim和Kruskal算法构造最小生成树

    ### 使用Prim和Kruskal算法构建最小生成树 在图论中,最小生成树(Minimum Spanning Tree, ...这两种算法都是通过贪心策略来构建最小生成树,最终得到的最小生成树将覆盖图中的所有顶点,并且其所有边的权重之和最小。

    Prim算法与Kruskal算法求最小生成树

    最小生成树是图论中的一个重要概念,用于寻找一个无向加权图的边集合,使得这些边连接了图中的所有顶点,同时整个边集合的总权重尽可能小。在这个问题中,Prim算法和Kruskal算法是两种常用的方法。 1. Prim算法: ...

    数据课程设计_最小生成树

    首先,我们要了解两种常见的求解最小生成树的算法:Prim算法和Kruskal算法。 1. **Prim算法**: Prim算法是从一个初始顶点开始,逐步扩展生成树,每次添加一条与当前生成树连接且权值最小的边。这个过程持续到所有...

    数据结构-图-最小生成树-最短路径

    在实际应用中,比如网络设计和优化问题中,Prim算法和Kruskal算法是最常用的两种求解最小生成树的策略。Prim算法从顶点开始构建最小生成树,逐步增加边直到包括所有顶点,且每次增加的边会使得树的总权重最小;...

    求解最小生成树问题的论文

    最小生成树是图论中的一个核心概念,主要应用于网络设计、资源分配等领域,它寻找一个树形子图,连接图中的所有顶点,并且使得这个子图的所有边的权重之和最小。这个问题在计算机科学中有着广泛的应用,比如在设计...

    最小生成树算法Prim & Kruskal

    Prim算法和Kruskal算法是两种常用求解最小生成树的算法。 1. **Prim算法**: Prim算法是从一个顶点开始,逐步扩展生成树,每次添加一条与当前生成树相连且权值最小的边。它以贪心策略为基础,确保每一步都选择...

    最小生成树(Prim、Kruskal算法)整理版.docx

    总之,最小生成树问题的求解对许多实际问题的解决至关重要,而Prim和Kruskal算法为这类问题提供了有效的算法工具。通过深刻理解每种算法的原理和特点,以及它们的适用场景,我们可以更好地解决实际问题,并优化解决...

    Prim算法是一种常用的求解最小生成树的贪心算法.pdf

    prim算法求最小生成树这个代码假设图使用邻接矩阵表示,图的节点数为`num_nodes`,`graph`是一个二维数组,`graph[i][j]`表示节点i和节点j之间的边的权重。返回值是一个列表,列表中的每个元素是一条边,表示最小...

    最小生成树 (3).docx

    因此,Kruskal算法适合求解稀疏图的最小生成树。 3. 破圈法 破圈法是一种从图G出发,逐步去边破圈得到最小生成树的方法。该算法的思想是,先找到图中的一个圈,然后删除其中的权最大的边,依次操作,直到图中无圈...

    求解最小生成树

    Kruskal算法也是贪心算法,但它的策略是按边的权重从小到大排序,然后依次考虑每条边,只要这条边不形成环路,就将其加入到最小生成树中。以下是Kruskal算法的步骤: - 对图中的所有边按权重进行升序排序。 - 初始...

    最小生成树

    标题"最小生成树"所涉及的算法主要是Kruskal算法和Prim算法,这两种都是经典求解最小生成树的方法。 1. **Kruskal算法**: Kruskal算法主要基于贪心策略。它的基本步骤如下: - 将图中的所有边按权重从小到大排序...

    最小生成树算法

    Prim算法是一种贪心策略,从一个初始顶点开始,逐步添加边,每次选择与当前生成树连接的边中权值最小的一条,直到包含所有顶点。该算法需要维护一个优先队列来高效地找到最小边。Prim算法的时间复杂度可以达到O(E ...

    最小生成树 数据结构

    在数据结构中,求解最小生成树的方法主要有两种:Prim算法和Kruskal算法。 **Prim算法** 是一种贪心策略,它从一个初始顶点开始,逐步将相邻的最小权重边加入到生成树中,直到所有顶点都被包含。Prim算法通常使用...

    kruskal和prim算法程序实现

    Kruskal算法和Prim算法是两种经典的求解最小生成树的方法。 #### 二、Kruskal算法原理 Kruskal算法是一种贪心算法,其核心思想是按照边的权重从小到大依次考虑每条边是否加入结果中。如果这条边连接的两个顶点还...

    贪心法求最小生成树算法.pdf

    在给定的文件中提到了两种经典的贪心算法来求解最小生成树问题: 1. **普里姆算法(Prim's Algorithm)**:该算法基于“最近顶点策略”。从任意一个顶点开始,每次选择一条与当前生成树中顶点相连的、权重最小的边,...

    用Kruska和Prim算法求最小生成树完整代码

    最小生成树是图论中的一个重要概念,用于寻找连接所有顶点的边的集合,使得这些边的总权重尽可能小。在计算机科学中,这个概念在优化网络、设计高效的通信网络和解决其他类似问题时非常有用。本文将详细介绍两种常用...

    数据结构的实现——最小生成树算法.pdf

    因此,Kruskal算法的整体效率非常高,非常适合用于求解最小生成树问题,特别是在边数远大于顶点数的稀疏图中。 总结来说,最小生成树在数据结构中扮演了重要角色,对于求解网络设计、电路布线、城市交通规划等实际...

Global site tag (gtag.js) - Google Analytics