拓扑排序
1. 概念
-
AOV网在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先级关系的有向图称为顶点表示活动的网(
Activity On Vertex NetWork),简称AOV网。就是用顶点表示活动的网
-
拓扑序列
设
G = (V, E)是一个具有n个顶点的有向图,V中的顶点序列V1,V2,V3······Vn满足若从顶点Vi到Vj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前。则我们称这样的序列为一个拓扑序列。
-
拓扑排序
所谓的拓扑排序,其实就是对一个有向无环图构造拓扑序列的过程。
2. 拓扑排序
- 从又向图中选择一个没有前驱(入度为0)的顶点,输出
- 删除第一步入度中入度为0的点,相关的弧进行顺序调整
- 重复1,2步骤
C 实现:
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "topological.h"
static void visitNode(ArcNode* node) {
if (node == NULL) return;
printf("%s\t", node->show);
}
int TopologicalSort(AGraph* graph) {
// 申请入度数组
int* inDegree = malloc(sizeof(int) * graph->nodeNum);
if (inDegree == NULL) return -1;
memset(inDegree, 0, sizeof(int) * graph->nodeNum);
// 将入度加入数组
for (int i = 0; i < graph->nodeNum; i++) {
if (graph->nodes[i].firstEdge) {
ArcEdge* edge = graph->nodes[i].firstEdge;
while (edge) {
inDegree[edge->number]++;
edge = edge->next;
}
}
}
// 申请栈
int top = -1;
int* stack = malloc(sizeof(int) * graph->nodeNum);
if (stack == NULL) {
free(inDegree);
return -1;
}
// 将入度为0的值都加入栈中
for (int i = 0; i < graph->nodeNum; i++) {
if (inDegree[i] == 0) {
stack[++top] = i;
}
}
int count = 0;
while (top != -1) {
int index = stack[top--];
count++;
visitNode(&graph->nodes[index]);
ArcEdge* edge = graph->nodes[index].firstEdge;
while (edge) {
inDegree[edge->number]--;
if (inDegree[edge->number] == 0) {
stack[++top] = edge->number;
}
edge = edge->next;
}
}
free(stack);
free(inDegree);
if (count == graph->nodeNum) {
return 1;
}
else {
return 0;
}
}
Java 实现:
java
package com.sonnet.topological_sort;
import com.Sonnet.adjacency_list.AdjacencyList;
import java.util.ArrayDeque;
import java.util.Deque;
public class Topological<T> {
public boolean topologicalSort(final AdjacencyList<T> graph) {
// 申请入度数组
int[] inDegree = new int[graph.getNodeNum()];
AdjacencyList.ArcNode<T>[] nodes = graph.getNodes();
// 将入度加入到数组中
for (int i = 0; i < graph.getNodeNum(); i++) {
// 如果有入度
if (nodes[i].getFirstEdge() != null) {
AdjacencyList.ArcEdge edge = nodes[i].getFirstEdge();
while (edge != null) {
inDegree[edge.getNumber()]++;
edge = edge.getNext();
}
}
}
// 申请栈
Deque<Integer> stack = new ArrayDeque<>();
for (int i : inDegree) {
// 如果度为0 就压入栈
if (i == 0) {
stack.push(i);
}
}
int count = 0;
// 出栈,直到栈为空
while(!stack.isEmpty()) {
int index = stack.pop();
count++;
visitNode(nodes[index]);
AdjacencyList.ArcEdge edge = nodes[index].getFirstEdge();
while (edge != null) {
inDegree[edge.getNumber()]--;
if (inDegree[edge.getNumber()] == 0) {
stack.push(edge.getNumber());
}
edge = edge.getNext();
}
}
return count == graph.getNodeNum();
}
private void visitNode(AdjacencyList.ArcNode<T> node) {
System.out.print(node.getShow() + "\t");
}
}
3. 完整实现
C 实现:
topologicalSort.h
c
#pragma once
#include "Adjacency.h"
int TopologicalSort(AGraph* graph);
topologicalSort.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "topologicalSort.h"
static void vistiedAGraphNode(ArcNode* node) {
printf("%s\t", node->show);
}
/*
1. 从又向图中选择一个没有前驱(入度为0)的顶点,输出
2. 删除第一步入度中入度为0的点,相关的弧进行顺序调整
3. 重复1,2步骤
*/
int TopologicalSort(AGraph* graph) {
int* inDegree = malloc(sizeof(int) * graph->nodeNum); // 入度记录表
if (inDegree == NULL) return -1;
memset(inDegree, 0, sizeof(int) * graph->nodeNum);
// 1. 将有向图的所有入度边更新到入度记录表
for (int i = 0; i < graph->nodeNum; i++) {
if (graph->nodes[i].firstEdge) {
ArcEdge* edge = graph->nodes[i].firstEdge;
while (edge) {
inDegree[edge->number]++;
edge = edge->next;
}
}
}
// 2. 发现度为0,入栈
// 查找入度记录表,度为0的顶点,入栈
int* stack = malloc(sizeof(int) * graph->nodeNum);
if (stack == NULL) {
free(inDegree);
return -1;
}
int top = -1;
for (int i = 0; i < graph->nodeNum; i++) {
if (inDegree[i] == 0) {
stack[++top] = i;
}
}
// 3. 根据任务栈里的数据,弹出当前第一个任务
int count = 0;
while (top != -1) {
int index = stack[top--];
count++;
vistiedAGraphNode(&graph->nodes[index]);
// 更新入度信息表,如果发现0,直接入缓存区
ArcEdge* edge = graph->nodes[index].firstEdge;
while (edge) {
inDegree[edge->number]--;
if (inDegree[edge->number] == 0) {
stack[++top] = graph->nodes[edge->number].number;
}
edge = edge->next;
}
}
free(stack);
free(inDegree);
if (count == graph->nodeNum) {
return 0;
}
else {
return 1;
}
}
main.c
c
#include <stdio.h>
#include <stdlib.h>
#include "topologicalSort.h"
AGraph* setupAGraph() {
const char* names[] = { "0", "1", "2", "3", "4", "5", "6" };
int n = sizeof(names) / sizeof(names[0]);
AGraph* graph = createAGraph(n);
if (graph == NULL) {
return NULL;
}
initAGraph(graph, names, n, 1);
addAGraph(graph, 0, 1, 1);
addAGraph(graph, 0, 2, 1);
addAGraph(graph, 0, 3, 1);
addAGraph(graph, 1, 2, 1);
addAGraph(graph, 1, 4, 1);
addAGraph(graph, 2, 4, 1);
addAGraph(graph, 2, 5, 1);
addAGraph(graph, 3, 5, 1);
addAGraph(graph, 4, 6, 1);
addAGraph(graph, 5, 4, 1);
addAGraph(graph, 5, 6, 1);
return graph;
}
int main() {
AGraph* graph = setupAGraph();
int result = TopologicalSort(graph);
printf("\nresult = %d\n", result);
}
Java 实现:
Topological
java
package com.sonnet.topological_sort;
import com.Sonnet.adjacency_list.AdjacencyList;
import java.util.ArrayDeque;
import java.util.Deque;
public class Topological<T> {
public boolean topologicalSort(final AdjacencyList<T> graph) {
// 申请入度数组
int[] inDegree = new int[graph.getNodeNum()];
AdjacencyList.ArcNode<T>[] nodes = graph.getNodes();
// 将入度加入到数组中
for (int i = 0; i < graph.getNodeNum(); i++) {
// 如果有入度
if (nodes[i].getFirstEdge() != null) {
AdjacencyList.ArcEdge edge = nodes[i].getFirstEdge();
while (edge != null) {
inDegree[edge.getNumber()]++;
edge = edge.getNext();
}
}
}
// 申请栈
Deque<Integer> stack = new ArrayDeque<>();
for (int i : inDegree) {
// 如果度为0 就压入栈
if (i == 0) {
stack.push(i);
}
}
int count = 0;
// 出栈,直到栈为空
while(!stack.isEmpty()) {
int index = stack.pop();
count++;
visitNode(nodes[index]);
AdjacencyList.ArcEdge edge = nodes[index].getFirstEdge();
while (edge != null) {
inDegree[edge.getNumber()]--;
if (inDegree[edge.getNumber()] == 0) {
stack.push(edge.getNumber());
}
edge = edge.getNext();
}
}
return count == graph.getNodeNum();
}
private void visitNode(AdjacencyList.ArcNode<T> node) {
System.out.print(node.getShow() + "\t");
}
}
TopologicalSortTest
java
package com.sonnet.topological_sort;
import com.Sonnet.adjacency_list.AdjacencyList;
public class TopologicalSortTest {
public static void main(String[] args) {
AdjacencyList<String> AGraph = createAGraph();
Topological<String> graph = new Topological<>();
boolean result = graph.topologicalSort(AGraph);
System.out.println();
System.out.println("result: " + result);
}
public static AdjacencyList<String> createAGraph() {
String[] shows = {"0", "1", "2", "3", "4", "5", "6"};
AdjacencyList<String> graph = new AdjacencyList<>(shows.length);
graph.initAGraph(shows, true);
graph.addAGraphEdge(0, 1, 1);
graph.addAGraphEdge(0, 2, 1);
graph.addAGraphEdge(0, 3, 1);
graph.addAGraphEdge(1, 2, 1);
graph.addAGraphEdge(1, 4, 1);
graph.addAGraphEdge(2, 4, 1);
graph.addAGraphEdge(2, 5, 1);
graph.addAGraphEdge(3, 5, 1);
graph.addAGraphEdge(4, 6, 1);
graph.addAGraphEdge(5, 4, 1);
graph.addAGraphEdge(5, 6, 1);
return graph;
}
}