拓扑排序的实现

拓扑排序

1. 概念

  • AOV网

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

    就是用顶点表示活动的网

  • 拓扑序列

    设G = (V, E)是一个具有n个顶点的有向图,V中的顶点序列V1,V2,V3······Vn满足若从顶点Vi到Vj有一条路径,则在顶点序列中顶点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;
    }
}
相关推荐
Promising_GEO2 分钟前
GEE实战02期:从卫星波段开始:利用 Sentinel-2 自己计算 NDVI
java·sentinel·遥感·空间分析
2601_961146205 分钟前
实验室用等离子表面处理设备处理新能源汽车塑料件的一点记录
笔记·汽车·设备
大文说跨境8 分钟前
亚马逊多账号管理浏览器怎么选?云登/紫鸟/AdsPower 对比
java·前端·自动化
知产xiao_xin15 分钟前
专利主体及权利归属
经验分享·笔记·知识产权
CoderYanger23 分钟前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
学电子她就能回来吗24 分钟前
LeetCode Hot 100|普通数组专题学习笔记(零基础版)
笔记·算法·leetcode
2601_9653842626 分钟前
从微生态与流体力学视角看:“口水臭”的系统级成因与清洁边界
经验分享·笔记
用户老李26 分钟前
反向传播计算梯度举例
算法
niyongsheng27 分钟前
多智能体连续时间内路径规划:AA-SIPP(m) 的 Rust 实现与算法
算法·rust·机器人
估值探索者37 分钟前
【Python量化选股流水线 #04】选股器好不好用?「昨日候选→今日表现」回看验收
开发语言·python·股票数据·股票数据api接口