今天我门来说一下拓扑排序!
1.提出问题:为什么会出现拓扑排序这个玩意?
答:以我当前的知识面来看,拓扑排序的主要应用方向就是解决一些流程问题,就像要生产一种产品,需要从购买原料一直到发货给商家,中间的流程是非常复杂的,在这种复杂的情况下,我们呢需要有较为清晰的流程,所谓流程,就是先做那一步后做那一步
你想想,若果这个工程中包含成百个步骤,有些步骤需要在其他步骤完成的情况下进行,如果我们没有执行步骤的先后顺序那将造成时间和效率上的巨大浪费!这是后拓扑排序就可以帮我们解决这个问题,对流程图进行拓扑排序,拓扑排序后我们将可以清晰的看到执行步骤的先后顺序,按照顺序执行最后就可以完成整个工程!
2.下面我们们说说拓扑排序的应用前提.
对于一个有向,无环的AOV网,我们可以对其应用拓扑排序(所谓AOV就是说每一个顶点代表一个活动)
3.我们通过例题加深对拓扑排序的印象
手工绘图,有点丑,还望见谅!哈哈
首先,我们要用什么来存储这张图呢?我们这里选择使用邻接表来存储这个图(当然用邻接矩阵也可以存储,只不过比较麻烦)
初始化
//邻接表
private node map[]= {null,null,null,null,null,null,null,null};
//记录AOV(有向无环图)网中的所有有向边的始末位置(这里就不输入边了,没啥意义,直接把边全部存到数组里面)
private int[][] side= {{0,2},{0,6},{2,3},{3,4},{6,5},{5,4},{1,6},{1,7},{6,3},{7,5}};
//记录各个顶点的出度
private int[] in_degree= {0,0,0,0,0,0,0,0};
//使用LinkedList模拟队列保存待选取得点
private LinkedList<Integer> queue=new LinkedList<>();
构建链表
public void create_linkedlist() {
//遍历所有包含所有边的数组,建立链表
for(int i=0;i<side.length;i++) {
in_degree[side[i][1]]++;
if(map[side[i][0]]==null) {
map[side[i][0]]=new node(side[i][1],null);
}else {
node temp=map[side[i][0]];
while(temp.getNext()!=null) {
temp=temp.getNext();
}
temp.setNext(new node(side[i][1],null));
}
}
for(int i=0;i<in_degree.length;i++) {
//将入度为0的点推入队列中
if(in_degree[i]==0) {
queue.addLast(i);
}
}
}
进行拓扑排序:
/**
* 进行拓扑排序
*
* 拓扑排序的核心思想
*
* 1.先找到一个入度为0的顶点(如果有多个入度为0的顶点则随便选取即可),访问该点,删除该点和以该点为弧尾的所有弧(相当于将该点踢出这个图)
* 2.寻找下一个入度为0的顶点,然后访问,踢出。。。。。
*
*
* 最后会出现两种情况
* 1.所有点都被访问到了!(说明该网符合无回路的特点)
* 2.有几个点没有被访问到!(说明该网存在回路)
*
*
*/
public void topological_sorting() {
while(!queue.isEmpty()) {
//从栈顶弹出将要访问的定点
int visiting=queue.pop();
//直接将当前访问的节点输出
System.out.println(visiting);
node temp=map[visiting];
while(temp!=null) {
//删去以当前顶点为弧尾的所有弧;
int dg=--in_degree[temp.getDate()];
if(dg==0) {
//如果当入度减去1后弧度变为零则表示该顶点已经可以访问了,将其加入队列
queue.addLast(temp.getDate());
}
temp=temp.getNext();
}
}
}
运行结果:
0
1
2
6
7
3
5
4
结果没有问题(也许你的结果可能和我有差别,这可能是在同时出现多个入度为零的节点时的选取方式不同导致的,我是按照先后顺序选取的)
谢谢观看!