拓扑排序的实现

拓扑排序

1. 概念

  • AOV

    在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先级关系的有向图称为顶点表示活动的网(Activity On Vertex NetWork),简称AOV网。

    就是用顶点表示活动的网

  • 拓扑序列

    G = (V, E)是一个具有n个顶点的有向图,V中的顶点序列V1,V2,V3······Vn满足若从顶点ViVj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前。则我们称这样的序列为一个拓扑序列。

  • 拓扑排序

    所谓的拓扑排序,其实就是对一个有向无环图构造拓扑序列的过程。

2. 拓扑排序

  1. 从又向图中选择一个没有前驱(入度为0)的顶点,输出
  2. 删除第一步入度中入度为0的点,相关的弧进行顺序调整
  3. 重复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;
    }
}
相关推荐
2301_776508722 小时前
分布式系统监控工具
开发语言·c++·算法
splage2 小时前
Spring Framework 中文官方文档
java·后端·spring
Irissgwe2 小时前
Linux进程信号
linux·服务器·开发语言·c++·linux进程信号
暮冬-  Gentle°2 小时前
C++与区块链智能合约
开发语言·c++·算法
JobDocLS2 小时前
Bash调试方法
开发语言·bash
愣头不青2 小时前
78.子集
数据结构·算法
Oueii2 小时前
C++中的代理模式实现
开发语言·c++·算法
艾莉丝努力练剑2 小时前
【Linux:文件 + 进程】理解IPC通信
linux·运维·服务器·开发语言·网络·c++·ide
3DVisionary2 小时前
从微观损伤到宏观断裂:DIC非接触测量在复合材料可靠性验证中的前沿实践
人工智能·数码相机·算法·机器学习·3d·复合材料·dic技术