拓扑排序主要解决一个工程能否顺序进行的问题。
无环图:图中没有回路
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网(Activity On Vertex Network)。
AOV网中的弧表示活动之间存在的某种制约关系(也可以理解活动要分先后顺序),AOV网中不能有回路。
设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,…vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在顶点vj之前。则我们称这样的顶点序列为一个拓扑序列。
拓扑排序:就是对一个有向图构造拓扑序列的过程。
构造时会有两个结果,如果此网的全部顶点都被输出,则说明它是不存在环(回路)的AOV网;如果输出顶点数少了,哪怕少了一个,也说明这个网存在环(回路),不是AOV网。
一个不存在回路的AOV网,我们可以将它应用在各种各样的工程或项目的流程图中,满足各种应用场景的需要,所以实现拓扑排序的算法就很有价值了。
拓扑排序算法:
对AOV网进行拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
C# 代码:可以只看最后的拓扑排序部分
public class AdjacencyList
{
public class EdgeNode
{
public int adjvex;
public int weight;
public EdgeNode next;
}
public class VertexNode
{
public int inDegree;
public int data;
public EdgeNode firstEdge;
}
public int numVertexes;
public int numEdges;
public VertexNode[] adjacencyArr;
public AdjacencyList(int numVertexes, int numEdges, int[] datas, EdgeNode[] edgeData)
{
this.numEdges = numEdges;
this.numVertexes = numVertexes;
adjacencyArr = new VertexNode[numVertexes];
for (int i = 0; i < this.numVertexes; i++)
{
adjacencyArr[i].data = datas[i];
adjacencyArr[i].firstEdge = edgeData[i];
}
}
private bool[] visited;
public void DFSTraverse(AdjacencyList gl)
{
for (int i = 0; i < gl.numVertexes; i++)
{
visited[i] = false;
}
for (int i = 0; i < gl.numVertexes; i++)
{
if (!visited[i])
{
DFS(gl, i);
}
}
}
private void DFS(AdjacencyList gl, int i)
{
visited[i] = true;
Debug.Log(gl.adjacencyArr[i].data);
EdgeNode temp = gl.adjacencyArr[i].firstEdge;
while (temp != null)
{
if (!visited[temp.adjvex])
DFS(gl, temp.adjvex);
temp = temp.next;
}
}
public void BFSTraverse(AdjacencyList gl)
{
Queue<int> queue = new Queue<int>();
EdgeNode p;
for (int i = 0; i < gl.numVertexes; i++)
{
visited[i] = false;
}
for (int i = 0; i < gl.numVertexes; i++)
{
if (!visited[i])
{
visited[i] = true;
Debug.Log(gl.adjacencyArr[i].data);
queue.Enqueue(i);
while (queue.Count > 0)
{
i = queue.Dequeue();
p = gl.adjacencyArr[i].firstEdge;
while (p != null)
{
if (!visited[p.adjvex])
{
visited[p.adjvex] = true;
Debug.Log(gl.adjacencyArr[p.adjvex].data);
queue.Enqueue(p.adjvex);
}
p = p.next;
}
}
}
}
}
public void MiniSpanTree_Prim(Graph graph)
{
int minCost, i, j, minCostIndex;
int[] adjvex = new int[graph.numVertex];
int[] lowCost = new int[graph.numVertex];
lowCost[0] = 0;
adjvex[0] = 0;
for (i = 1; i < graph.numVertex; i++)
{
lowCost[i] = graph.arcs[0, i];
adjvex[i] = 0;
}
for (i = 1; i < graph.numVertex; i++)
{
minCost = int.MaxValue;
j = 1;
minCostIndex = 0;
while (j < graph.numVertex)
{
if (lowCost[j] != 0 && lowCost[j] < minCost)
{
minCost = lowCost[j];
minCostIndex = j;
}
j++;
}
Debug.Log("打印当前顶点边中权值最小边:" + adjvex[minCostIndex] + "---" + minCostIndex);
lowCost[minCostIndex] = 0;
for (j = 1; j < graph.numVertex; j++)
{
if (lowCost[j] != 0 && graph.arcs[minCostIndex, j] < lowCost[j])
{
lowCost[j] = graph.arcs[minCostIndex, j];
adjvex[j] = minCostIndex;
}
}
}
}
public bool TopologicalSort(AdjacencyList gl)
{
EdgeNode node;
int k, topIndex;
int count = 0;
Stack<int> stack = new Stack<int>(gl.numVertexes);
for (int i = 0; i < gl.numVertexes; i++)
{
if (gl.adjacencyArr[i].inDegree == 0)
{
stack.Push(i);
}
}
while (stack.Count != 0)
{
topIndex = stack.Pop();
Debug.Log("->" + gl.adjacencyArr[topIndex].data);
count++;
for (node = gl.adjacencyArr[topIndex].firstEdge; node != null; node = node.next)
{
k = node.adjvex;
if ((--gl.adjacencyArr[k].inDegree) == 0)
{
stack.Push(k);
}
}
}
if (count < gl.numVertexes) return false;
else return true;
}
}
|