leetcode(207) Course Schedule即拓扑排序讲解
来源:互联网 发布:短信监控软件 编辑:程序博客网 时间:2024/06/05 23:07
关于拓扑排序的知识点可以参看http://www.cnblogs.com/newpanderking/archive/2012/10/18/2729552.html及http://blog.csdn.net/midgard/article/details/4101025两篇写的很好,这里做一个粗略的讲解
拓扑排序(topological-sort)是指由某个集合上的一个偏序得到该集合上的一个全序的操作。拓扑排序常用来确定一个依赖关系集中,事物发生的顺序。拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。
拓扑排序两个条件:
- 有向无环,图中不能有环路,有环路则不能进行拓扑排序。有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说!!!
- 如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。
图1.拓扑流程图
(1) 在(a)图中v0和v1的入度都为0,不妨选择v0并输出之,接着删去顶点v0及出边<0,2>,得到的结果如(b)图所示。
(2) 在(b)图中只有一个入度为0的顶点v1,输出v1,接着删去v1和它的三条出边<1,2>,<1,3>和<1,4>,得到的结果如(c)图所示。
(3) 在(c)图中v2和v4的入度都为0,不妨选择v2并输出之,接着删去v2及两条出边<2,3>和<2,5>,得到的结果如(d)图所示。
(4) 在(d)图上依次输出顶点v3,v4和v5,并在每个顶点输出后删除该顶点及出边,操作都很简单,不再赘述。
图2.初始状态链表
更详细的流程可见http://www.cnblogs.com/newpanderking/archive/2012/10/18/2729552.html。作者写的真是不错。
拓扑算法C/C++代码(来自博客http://blog.csdn.net/midgard/article/details/4101025):
//http://blog.csdn.net/midgard/article/details/4101025#include <iostream>#include <queue>using namespace std;#define MAX_VERTEX_NUM 20struct adjVertexNode { int adjVertexPosition; adjVertexNode* next; };struct VertexNode{ char data[2]; adjVertexNode* list; int indegree;}; struct Graph{ VertexNode vertexNode[MAX_VERTEX_NUM]; int vertexNum; int edgeNum;};void CreateGraph (Graph& g){ int i, j, edgeStart, edgeEnd; adjVertexNode* adjNode; cout << "Please input vertex and edge num (vnum enum):" <<endl; cin >> g.vertexNum >> g.edgeNum; cout << "Please input vertex information (v1)/n note: every vertex info end with Enter" <<endl; for (i=0;i<g.vertexNum;i++) { cin >> g.vertexNode[i].data; // vertex data info. g.vertexNode[i].list = NULL; g.vertexNode[i].indegree = 0; } cout << "input edge information(start end):" <<endl; for (j=0; j<g.edgeNum; j++) { cin >>edgeStart >>edgeEnd; adjNode = new adjVertexNode; adjNode->adjVertexPosition = edgeEnd; adjNode->next=g.vertexNode[edgeStart].list; g.vertexNode[edgeStart].list=adjNode; //每增加一条边,则边的End顶点的入度加1 g.vertexNode[edgeEnd].indegree++; }}void PrintAdjList(const Graph& g){ cout << "The adjacent list for graph is:" << endl; for (int i=0; i < g.vertexNum; i++) { cout<< g.vertexNode[i].data << "->"; adjVertexNode* head = g.vertexNode[i].list; if (head == NULL) cout << "NULL"; while (head != NULL) { cout << head->adjVertexPosition <<" "; head = head->next; } cout << endl; }}//寻找0入度的点,否则取栈头VertexNode& FindZeroIndegree(Graph& g){ for (int i=0; i<g.vertexNum; i++) { if (g.vertexNode[i].indegree==0) return g.vertexNode[i]; } return g.vertexNode[0];}void TopSort(Graph& g){ cout << "The topsort is:" <<endl; for (int i=0; i<g.vertexNum; i++) { VertexNode& v = FindZeroIndegree(g); if (v.indegree!=NULL) cout << "The graph has cycle, can not do topsort"<<endl; // print graph as topsort. cout<< v.data << " "; // for each vertex w adjacent to v, --indegree adjVertexNode* padjv = v.list; while (padjv!=NULL) {//!!这个算法这里破坏了原图中的入度信息。最后入度均为1 g.vertexNode[padjv->adjVertexPosition].indegree--; padjv = padjv->next; } //避免入度信息均为零FindZeroIndegree找到删除的顶点,将删除的顶点入度置为-1 v.indegree=-1; } cout << endl;}void TopSort2(Graph& g){ queue<VertexNode> q; for (int i=0; i<g.vertexNum; i++) { if (g.vertexNode[i].indegree == 0) q.push(g.vertexNode[i]); } int count = 0; cout << "The topsort is:" <<endl; while (!q.empty()) { VertexNode v = q.front(); q.pop(); cout<< v.data << " "; count++; adjVertexNode* padjv = v.list; while (padjv!=NULL) {//!!这个算法这里破坏了原图中的入度信息。最后入度均为1 if (--(g.vertexNode[padjv->adjVertexPosition].indegree)==0) q.push(g.vertexNode[padjv->adjVertexPosition]); padjv = padjv->next; } } if (count != g.vertexNum) cout << "The graph has cycle, can not do topsort"<<endl;}void DeleteGraph(Graph &g){ for (int i=0; i<g.vertexNum; i++) { adjVertexNode* tmp=NULL; while(g.vertexNode[i].list!=NULL) { tmp = g.vertexNode[i].list; g.vertexNode[i].list = g.vertexNode[i].list->next; delete tmp; tmp = NULL; } }}int main(int argc, const char** argv){ Graph g; CreateGraph(g); PrintAdjList(g); TopSort(g); DeleteGraph(g); return 0;}
package leetcode;import java.util.LinkedList;import java.util.Queue;public class CourseSchedule {/** * 是否可以进行拓扑排序 * * @param numCourses * 元素个数 * @param prerequisites * 关系数组 prerequistes是个二维数组,比如一个元素是{0,1}代表0--->1的路径,即0到1的有向图路径 * @return */public static boolean canFinish(int numCourses, int[][] prerequisites) {int[] map = new int[numCourses]; // 代表元素的入度数组for (int i = 0; i < prerequisites.length; i++) {map[prerequisites[i][1]]++; // 后面元素入度+1}Queue<Integer> que = new LinkedList<Integer>();for (int i = 0; i < map.length; i++) {if (map[i] == 0)que.add(i); // 入度为0的元素加入到队列中}int count = que.size();while (!que.isEmpty()) {int k = que.remove(); // 队列中取出第一个元素并移除for (int i = 0; i < prerequisites.length; i++) { // 遍历此节点是否有指向的节点if (k == prerequisites[i][0]) {int l = prerequisites[i][1];map[l]--; // 指向的节点度数-1if (map[l] == 0) { // 如果度数为0,则加入队列中,计数+1que.add(l);++count;}}}}return count == numCourses; // 如果最后count的数字等于元素个数,说明全部遍历完成没有闭环,返回true,否则返回false}public static void main(String[] args) {// TODO Auto-generated method stubint countNum = 6;int[][] prerequisites = { { 0, 2 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 2, 3 }, { 2, 5 }, { 3, 5 }, { 4, 5 } };System.out.println(canFinish(countNum, prerequisites));}}此外,也可以运用bfs遍历,具体可见博客http://blog.csdn.net/dm_vincent/article/details/7714519
- leetcode(207) Course Schedule即拓扑排序讲解
- 【LeetCode】Course Schedule--拓扑排序
- LeetCode Course Schedule II 拓扑排序
- Leetcode 210 Course Schedule II 拓扑排序
- leetcode 207. Course Schedule(拓扑排序)
- Course Schedule 拓扑排序
- Course Schedule[拓扑排序]
- Course Schedule II 拓扑排序
- 拓扑排序:课程表Course Schedule
- LeetCode OJ 207. Course Schedule 拓扑排序+邻接表
- LeetCode 210. Course Schedule II|图问题.拓扑排序
- leetcode 207. Course Schedule 课程调度 + 拓扑排序
- leetcode 210. Course Schedule II 拓扑排序 + HashSet
- Leetcode解题笔记 207.Course Schedule [Medium] 拓扑排序
- LeetCode 207 - Course Schedule
- leetcode 207: Course Schedule
- LeetCode 207-Course Schedule
- 【Leetcode】Course Schedule #207
- bootstrap起步
- The Java™ Tutorials — Concurrency :Atomic Access 原子访问
- 主成分分析PCA
- 九度oj_题目1489:计算两个矩阵的乘积
- BZOJ 1101: [POI2007]Zap|莫比乌斯反演
- leetcode(207) Course Schedule即拓扑排序讲解
- 指针的运算符
- Markdown基础笔记
- android:fitsSystemWindows的作用
- Android回调Callback的理解(附demo)
- Logcat使用小技巧——多Tag过滤。
- 程序猿必备认知!
- 【 bzoj 2400 】Spoj 839 Optimal Marks - 最小割
- 序列图(sequence)语法