博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
拓扑排序
阅读量:3947 次
发布时间:2019-05-24

本文共 4703 字,大约阅读时间需要 15 分钟。

拓扑排序

定义:

对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

注意:

只有当一幅有向图是无环图时才能进行拓扑排序。

应用:

任务调度、课程安排、继承

题目描述:

共有n门课程你必须参加,标签从0到n-1。

有些课程可能有先决条件,例如,要参加课程0,您必须首先参加课程1,这表示为一对:[0,1]

考虑到课程总数和先决条件对列表,您是否可以完成所有课程?可以返回true,不可以返回false

Input: 2, [[1,0]] Output: trueInput: 2, [[1,0],[0,1]]Output: false
解决:

这道不需要使用拓扑排序,只需要检测有向图是否存在环即可,在这里采用DFS,递归来实现

/***采用深度优先遍历解决有无环*如果采用BFS会更快**/class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
List
[] graphic = new List[numCourses]; boolean [] marked = new boolean[numCourses]; //判断那个数是否被标记 for (int i = 0;i < numCourses;i++){
graphic[i] = new ArrayList(); //对每个数字生成一个链表 } for (int [] pre : prerequisites){
graphic[pre[0]].add(pre[1]); } for (int i = 0;i < numCourses;i++){
if(hasCycle(graphic,marked,i)){
return false; } } return true; } //判断是否含环 private boolean hasCycle(List
[] graphic,boolean [] marked,int cur){
if (marked[cur]){
return true; //如果被标记,则直接返回true } marked[cur] = true; for (int next : graphic[cur]){
if (hasCycle(graphic,marked,next)){
return true; } } marked[cur] = false; return false; }}

题目描述:

总共有n门课程你必须参加,标签从0到n-1。

有些课程可能有先决条件,例如,要参加课程0,您必须首先参加课程1,这表示为一对:[0,1]

给定课程总数和先决条件对列表,返回完成所有课程所需的课程顺序。

可能有多个正确的订单,您只需返回其中一个。如果无法完成所有课程,则返回空数组。

Input: 2, [[1,0]] Output: [0,1] Input: 4, [[1,0],[2,0],[3,1],[3,2]]Output: [0,1,2,3] or [0,2,1,3]
解题:

这道属于典型拓扑排序,可以考虑用DFS或者BFS来完成,在LeetCode上显示第一种这种解法比第二种更快点。

DFS:使用一个栈存储后序遍历结果,这个栈的逆序结果就是拓扑排序结果,这里有一个globalMarked全局判断,可以减少判断次数。

class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
List
[] graphic = new List[numCourses]; for (int i = 0;i < numCourses;i++){
graphic[i] = new ArrayList<>(); } for(int [] a : prerequisites){
graphic[a[0]].add(a[1]); } boolean [] globalMarked = new boolean[numCourses]; //增加一个全局判断,可以减少时间 boolean [] localMarked = new boolean[numCourses]; Stack
postOrder = new Stack<>(); //使用栈存储后序遍历结果 for(int i = 0;i < numCourses;i++){
if(hasCycle(globalMarked,localMarked,postOrder,graphic,i)){
return new int[0]; } } int [] order = new int[numCourses]; for(int i = numCourses - 1;i >= 0;i--){
order[i] = postOrder.pop(); //逆序输出 } return order; } //DFS,判断是否有环 private boolean hasCycle(boolean [] globalMarked,boolean [] localMarked,Stack
postOrder, List
[] graphic,int i ){
if(localMarked[i]){
return true; } if(globalMarked[i]){
return false; //减少判断 } localMarked[i] = true; globalMarked[i] = true; for(int next : graphic[i]){
if(hasCycle(globalMarked,localMarked,postOrder,graphic,next)){
return true; } } localMarked[i] = false; postOrder.add(i); return false; }}

BFS:首先遍历图中所有的顶点,将入度为0的顶点入队列,然后将入度为0的顶点出队列,并更新与之邻接的顶点的入度,若邻接顶点的入度降为0,则入队列,最后判断index与numCourses得大小,如果有环,index的值 一定小numCourses。

public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses == 0) return null; // 将图形表示从边转换为相邻列表 int indegree[] = new int[numCourses], order[] = new int[numCourses], index = 0; //判断哪些有先决条件得课程 for (int i = 0; i < prerequisites.length; i++) indegree[prerequisites[i][0]]++; Queue
queue = new LinkedList
(); for (int i = 0; i < numCourses; i++) if (indegree[i] == 0) {
// 将课程添加到订单中,因为它没有先决条件,即将入度为0的顶点入队列 order[index++] = i; queue.offer(i); } while (!queue.isEmpty()) {
int prerequisite = queue.poll(); //更新与之邻接的顶点的入度 for (int i = 0; i < prerequisites.length; i++) {
if (prerequisites[i][1] == prerequisite) {
indegree[prerequisites[i][0]]--; if (indegree[prerequisites[i][0]] == 0) {
//如果Indegree为零,则将课程添加到order中 order[index++] = prerequisites[i][0]; queue.offer(prerequisites[i][0]); } } } } //如果有环,index的值 一定小于numCourses return (index == numCourses) ? order : new int[0];}

转载地址:http://ierwi.baihongyu.com/

你可能感兴趣的文章
调试打包jar方法
查看>>
MVC RPC SOA 和微服务架构的区别
查看>>
HTTP与TCP的区别和联系
查看>>
解决Cannot resolve method 'onMethod_'
查看>>
VMware 虚拟机NAT模式如何设置网络连接
查看>>
cloud2020
查看>>
@bean和@component的理解
查看>>
spring注解@Primary与@Qualifier
查看>>
annotation之@Autowired、@Inject、@Resource三者区别
查看>>
idea启动微服务找不到配置文件
查看>>
Java通过反射机制调用某个类的方法
查看>>
字节跳到面试题
查看>>
Linux查看物理CPU个数
查看>>
Linux学习之网络IO,磁盘io
查看>>
ES7.6.2安装
查看>>
查看jar依赖树
查看>>
idea运行gradle项目
查看>>
es安装ltr插件
查看>>
es插件使用之ltr插件demo体验
查看>>
开源ltr-es-7.6.2代码到本地idea打开出现各种错误总结
查看>>