【数据结构与算法】【算法思想】拓扑排序

一、拓扑排序

拓扑排序是基于依赖关系的节点,根据依赖关系而生成的序列。节点和依赖关系往往要生成有向无环图。类似的问题有:穿衣服裤子的先后关系,生成穿衣序列/专业课程与前置课程形成的课程学习序列/代码编译依赖关系形成的编译顺序序列。

public class Graph {private int v; // 顶点的个数private LinkedList<Integer> adj[]; // 邻接表public Graph(int v) {this.v = v;adj = new LinkedList[v];for (int i=0; i<v; ++i) {adj[i] = new LinkedList<>();}}public void addEdge(int s, int t) { // s先于t,边s->tadj[s].add(t);}
}

二、实现

0x00Kahn 算法

根据邻接表,很容易计算出每个节点的入度。
遍历每个入度,将入度为0的节点,放入队列。
队列不空,循环:
取出队首元素,输出他,然后遍历他的邻接节点,将邻接节点入度-1,如果邻接节点恰好为0,将节点放入队列。
时间复杂度:求入度:O(v+e),循环输出O(v+e)合起来O(v+e)
空间复杂度:入度数组O(v),队列<O(v)


public void topoSortByKahn() {int[] inDegree = new int[v]; // 统计每个顶点的入度for (int i = 0; i < v; ++i) {for (int j = 0; j < adj[i].size(); ++j) {int w = adj[i].get(j); // i->winDegree[w]++;}}LinkedList<Integer> queue = new LinkedList<>();for (int i = 0; i < v; ++i) {if (inDegree[i] == 0) queue.add(i);}while (!queue.isEmpty()) {int i = queue.remove();System.out.print("->" + i);for (int j = 0; j < adj[i].size(); ++j) {int k = adj[i].get(j);inDegree[k]--;if (inDegree[k] == 0) queue.add(k);}}
}
0x01 DFS 深度优先搜索算法
  1. 深度优先搜索是要一通到底的,所以需要将邻接表返过来,改成逆邻接表。方法:遍历邻接表,对i的每个邻接节点j,都将i加到j的逆邻接表中。
  2. 图的深度优先搜索不跟树一样:没有根节点,所以要尝试从每个节点都开始一次,自然需要visited数组防止重复。对某个节点深度遍历完之后,再输出。
  3. 时间复杂度:求入度:O(v+e),顶点两次 边一次
    空间复杂度:入度数组O(v),队列<O(v)

public void topoSortByDFS() {// 先构建逆邻接表,边s->t表示,s依赖于t,t先于sLinkedList<Integer> inverseAdj[] = new LinkedList[v];for (int i = 0; i < v; ++i) { // 申请空间inverseAdj[i] = new LinkedList<>();}for (int i = 0; i < v; ++i) { // 通过邻接表生成逆邻接表for (int j = 0; j < adj[i].size(); ++j) {int w = adj[i].get(j); // i->winverseAdj[w].add(i); // w->i}}boolean[] visited = new boolean[v];for (int i = 0; i < v; ++i) { // 深度优先遍历图if (visited[i] == false) {visited[i] = true;dfs(i, inverseAdj, visited);}}
}private void dfs(int vertex, LinkedList<Integer> inverseAdj[], boolean[] visited) {for (int i = 0; i < inverseAdj[vertex].size(); ++i) {int w = inverseAdj[vertex].get(i);if (visited[w] == true) continue;visited[w] = true;dfs(w, inverseAdj, visited);} // 先把vertex这个顶点可达的所有顶点都打印出来之后,再打印它自己System.out.print("->" + vertex);
}

在这里插入图片描述

显然用于拓扑排序的图是不可以成环的。自然拓扑排序算法可以用于检测图中的环。对于kahn算法,极端化思维:如果所有的节点形成大环,那么没有入度为0的节点,也就不会有任何输出。普通思维:如果存在环,总会到一个位置,没有任何节点入度为0。就会少输出节点。如果输出的节点<总结点,意味着存在环。

三、思考题

[1]在今天的讲解中,我们用图表示依赖关系的时候,如果 a 先于 b 执行,我们就画一条从 a 到 b 的有向边;反过来,如果 a 先于 b,我们画一条从 b 到 a 的有向边,表示 b 依赖 a,那今天讲的 Kahn 算法和 DFS 算法还能否正确工作呢?如果不能,应该如何改造一下呢?

1.如果有向边反向,代表依赖关系,则Kahn算法无法工作,改造方法是:1.1把对入度的计算改为对出度的计算,即首先输出出度为0的节点,然后依次把与该节点相邻的节点的出度都减1,重复此过程直到输出所有节点;1.2 改成逆连接表,计算入度;而DFS算法中,则会输出相反的结果,由于邻接表和逆邻接表正好是相反的,因此改造方法是:在DFS中,把对逆邻接表的的访问改为对邻接表的访问即可。

[2]我们今天讲了两种拓扑排序算法的实现思路,Kahn 算法和 DFS 深度优先搜索算法,如果换做 BFS 广度优先搜索算法,还可以实现吗?
2.采用BFS算法,无法保证在某个结点输出之前,先输出其所有依赖的节点,因为有可能该节点和其所依赖的某个节点,可能在BFS算法中处于同一个层次,因为这两个节点可能都和某个节点相邻,因此,采用BFS算法,有可能会输出不正确的拓扑次序。

笔记整理来源: 王争 数据结构与算法之美

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424761.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java面试题5 牛客:下列关于JavaBean的说法正确的是:

下列关于JavaBean的说法正确的是&#xff1a; A:Java文件与Bean所定义的类名可以不同&#xff0c;但一定要注意区分字母的大小写 B:在JSP文件中引用Bean&#xff0c;其实就是用语句 C&#xff1a;被引用的Bean文件的文件名后缀为.java D:Bean文件放在任何目录下都可以被引用…

Depth-first Search深度优先搜索专题3

473. Matchsticks to Square 思路&#xff1a;有n根长度不一的火柴&#xff0c;这些火柴可以拼接在一起&#xff0c;但不能被折断。这些火柴能够围城一个正方形吗&#xff1f;每个火柴可以并且必须使用一次。分析得到每个边的长度应该是所有火柴长度和的1/4。接下来就是将火柴…

java面试题6 牛客:哪个关键字可以对对象加互斥锁?

哪个关键字可以对对象加互斥锁&#xff1f;&#xff08;&#xff09; A synchronized B volatile C serialize D static synchronized的4种用法 1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进…

[Leetcode][第347题][JAVA][前K个高频元素][优先队列][堆][遍历set/map]

【问题描述】[中等] 【解答思路】 1. 堆 复杂度 class Solution {public int[] topKFrequent(int[] nums, int k) {Map<Integer, Integer> occurrences new HashMap<Integer, Integer>();for (int num : nums) {occurrences.put(num, occurrences.getOrDefault…

Depth-first Search深度优先搜索专题4

576. Out of Boundary Paths 思路&#xff1a;这道题目难倒了我。最直接的思路是暴力搜索。要注意的问题1是需要仔细观察Example2&#xff0c;轨迹不同意思是可以从A点到B点&#xff0c;再从B点到A点也可以&#xff0c;只要step够用。所以暴力搜索&#xff0c;在(i,j)点在步骤…

java面试题7 牛客:关于AWT和Swing说法正确的是?

关于AWT和Swing说法正确的是&#xff1f; A Swing是AWT的子类 B AWT在不同操作系统中显示相同的风格 C AWT不支持事件类型&#xff0c;Swing支持事件模型 D Swing在不同的操作系统中显示相同的风格 AWT和Swing都是java中的包。 AWT(Abstract Window Toolkit)&#xff1a;…

bwa比对软件的使用以及其结果文件(sam)格式说明

一、bwa比对软件的使用 1、对参考基因组构建索引 bwa index -a bwtsw hg19.fa # -a 参数&#xff1a;is[默认] or bwtsw&#xff0c;即bwa构建索引的两种算法&#xff0c;两种算法都是基于BWT的&#xff08;BWT search while the CIGAR string by Smith-Waterman alignment.…

java面试题8 牛客:在Web应用程序中,( )负责将HTTP请求转换为HttpServletRequest对象

在Web应用程序中&#xff0c;( )负责将HTTP请求转换为HttpServletRequest对象 A Servlet对象 B HTTP服务器 C Web容器 D JSP网页 首先我们来看看web程序的整个过程 web的基本工作流程 首先&#xff0c;我们先来思考一下我们平常在上网浏览网页时候的场景&#xff0c;…

2018-2019-2-20175225 实验四《Android开发基础》实验报告

一、实验报告封面 课程&#xff1a;Java程序设计 班级&#xff1a;1752班 姓名&#xff1a;张元瑞 学号&#xff1a;20175225 指导教师&#xff1a;娄嘉鹏 实验日期&#xff1a;2019年5月14日 实验时间&#xff1a;13:45 - 21:00 实验序号&#xff1a;实验四 实验名称&#xff…

【小技巧】【Java】 创建指定数目m的Set数组

1. Set[] 并初始化 Set[] sets new Set[m]; //均会指向同一对象 // Arrays.fill(sets,new HashSet()); for(int i 0;i<m;i){sets[i] new HashSet<Integer>();}2. Stream 流 Set[] sets Stream.generate(HashSet::new).limit(m).toArray(Set[]::new); for循环初始…

第七十六期:3000台服务器不宕机,微博广告系统全景运维大法

微博现在日活达到了 2 亿&#xff0c;微博广告是微博最重要且稳定的收入来源&#xff0c;没有之一&#xff0c;所以微博广告系统的稳定性是我们广告运维所有工作中的重中之重。 作者&#xff1a;孙燕来源 微博现在日活达到了 2 亿&#xff0c;微博广告是微博最重要且稳定的收入…

第六章小结

本章&#xff0c;我们学习了图。 首先是图(GRAPH)的定义 一种非线性数据结构&#xff0c;由有穷、非空的点集V(G)和边集E(G)组成。当G中的每条边有方向时&#xff0c;称G为有向图&#xff0c;有向边&#xff08;用一对尖括号<a,b>&#xff09;又称为弧&#xff0c;起始顶…

753 Cracking the Safe

方法一 Hierholzer’s Algorithm 相关概念&#xff1a; 1 欧拉路径&#xff1a;在无向图中&#xff0c;每个边只经过一次&#xff0c;形成的路径。在有向图中&#xff0c;是指每条有向边只使用一次&#xff0c;形成的路径。 2 欧拉回路&#xff1a;欧拉路径是一个环。 3 在…

java面试题9 牛客:不同的服务器之间,哪种通信方式是不可行的

在一个基于分布式的游戏服务器系统中&#xff0c;不同的服务器之间&#xff0c;哪种通信方式是不可行的&#xff08;&#xff09;&#xff1f; A管道 B消息队列 C高速缓存数据库 D套接字 首先看到这道题我是懵逼的&#xff0c;我们分别介绍一下各个的概念 管道为运行在同…

[Leetcode][第77题][JAVA][组合][回溯]

【问题描述】[中等] 【解答思路】 1. 回溯 class Solution {List<List<Integer>> lists new ArrayList<>();public List<List<Integer>> combine(int n, int k) {List<Integer> list new ArrayList<>();backTrace(list, n, k, 0)…

Depth-first Search深度优先搜索专题6

472 Concatenated Words 思路&#xff1a;将词典使用Trie树表示。对于输入的词word&#xff0c;在Trie树上找&#xff0c;当遇到一个isWordtrue的节点&#xff0c;查看剩下部分的词是否在词典中。 例如输入 [“cat”,”cats”,”catsdogcats”,”dog”,”dogcatsdog”,”hipp…

目标检测近5年发展历程概述(转)

目标检测近5年发展历程概述&#xff0c;从R-CNN到RFBNet&#xff08;2013--2018&#xff09;&#xff08;转&#xff09; 2018年09月24日 12:32:02 C小C 【时间】2018.09.24 【题目】目标检测近5年发展历程概述&#xff0c;从R-CNN到RFBNet&#xff08;2013--2018&#xff09; …

[Leetcode][第39题][JAVA][组合总和][回溯][dfs][剪枝]

【问题描述】[中等] 【解答思路】 1. 回溯 import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List;public class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {int …

Depth-first Search深度优先搜索专题7

834 Sum of Distances in Tree 思路&#xff1a;一颗无向的树有N个节点&#xff0c;分别标记为0,1,2,…N-1&#xff0c;有若干条边。结果返回每个节点到其他节点的路径和。 以上面这棵树为例。从节点0到其他点的路径查找过程是&#xff1a;节点0有两条边分别到达子节点1和子节…

[Leetcode][第216题][JAVA][数组之和3][回溯]

【问题描述】[中等] 【解答思路】 回溯 剪树枝 当和超过n 或 个数超过k 1. 正向求和 优化前 class Solution {public List<List<Integer>> ans new LinkedList();public List<List<Integer>> combinationSum3(int k, int n) {dfs(0,k,0,n,1,new L…