这个算法是我自己想的最笨最原始的算法,原理跟Prim类似,但不同的是这里不用处理最小优先级队列,当然算法的时间复杂度要高些(该算法针对的是无向连通图,对于有向连通图,算法原理一样,但算法代码需要做一些处理),下面看代码:
1、类和树的定义可参考前面的博文。
2、算法类:
public class PrimAlg
{
public Tree MST_SimpleAlg(Graphic g,Node root)
{
Tree theMST = new Tree();
//最小生成树节点
Dictionary<string, Node> theMstNodes = new Dictionary<string, Node>();
//剩下未纳入最小生成树的节点
Dictionary<string, Node> theRemainNodes = new Dictionary<string, Node>();
//图的边
List<Edge> theEdges = new List<Edge>();
//开始的时候最小生成树节点包含root一个节点.
theMstNodes.Add(root.Symbol, root);
//将图的边复制到临时边集中,目的是没选一个边,就可以删除该边,以减低时间复杂度。
theEdges.AddRange(g.Edges);
//开始的时候剩余点集是图中除根节点之外的所有点.
foreach (var theNode in g.Nodes)
{
if (theNode.Symbol != root.Symbol)
{
theRemainNodes.Add(theNode.Symbol, theNode);
}
}
//将根节点放入结果最小生成树中.
theMST.Nodes.Add(root);
//只要有剩余点就循环处理
while (theRemainNodes.Count() > 0)
{
//记录最小的边,该边一个节点在已生成的最小生成树节点中,
//一个节点在未纳入最小生成树的节点中
Edge theMinEdge = null;
//最小边在最小生成树中的节点
Node theMNode = null;
//最小边在剩余节点中端点.
Node theRNode = null;
foreach (var theEdge in theEdges)
{
if (theMstNodes.ContainsKey(theEdge.Node1.Symbol) &&
theRemainNodes.ContainsKey(theEdge.Node2.Symbol))
{
if (theMinEdge == null)
{
theMinEdge = theEdge;
theMNode = theEdge.Node1;
theRNode = theEdge.Node2;
continue;
}
if (theMinEdge.Weight > theEdge.Weight)
{
theMinEdge = theEdge;
theMNode = theEdge.Node1;
theRNode = theEdge.Node2;
continue;
}
}
if (theMstNodes.ContainsKey(theEdge.Node2.Symbol) &&
theRemainNodes.ContainsKey(theEdge.Node1.Symbol))
{
if (theMinEdge == null)
{
theMinEdge = theEdge;
theMNode = theEdge.Node2;
theRNode = theEdge.Node1;
continue;
}
if (theMinEdge.Weight > theEdge.Weight)
{
theMinEdge = theEdge;
theMNode = theEdge.Node2;
theRNode = theEdge.Node1;
continue;
}
}
}
if (theMinEdge != null)
{
theMST.Nodes.Add(theRNode);
theMST.Edges.Add(theMinEdge);
theMstNodes.Add(theRNode.Symbol,theRNode);
theRemainNodes.Remove(theRNode.Symbol);
theEdges.Remove(theMinEdge);
}
}
return theMST;
}
}
这个算法的复杂度虽然比较高o(E2),但实现非常简单,不需要像Prim算法那样用到二叉堆之类的,容易理解和实现。