拓扑排序(详解,拓扑排序看这一片就够了)
首先,拓扑排序是利用BFS算法来实现的,要说到BFS算法在图中应用,拓扑排序首屈一指
本篇文章用一道leetcode上经典的题目(207.课程表)来讲解拓扑排序,题目链接:https://leetcode.cn/problems/course-schedule/
第一步,你需要构建出拓扑排序最基础的图表出来,就像要先学A这门课程的话就要先学B的话,那么图的表示就是B->A,以此类推。
第二步,你需要统计出图中所有点的入度,如果学A这么课程要先学B1,B2,B3这三门课那么A的入度就为3,以此类推。
基础工作做好之后就是利用BFS的思想去解题了。
你首先要把入度为0的点全部放在queue容器中(或者其他的容器中),然后让queue中第一个元素的后续节点的入度全部减1,判断入度是否为0,如果减1之后为0,就把这个节点加入进queue容器中,否则继续重复同样的操作,直至queue容器为空。在此期间,你需要统计好一共有多少元素加入了queue这个容器中,以此来和总共的元素作比较。
以上就是拓扑排序的基本流程了,具体怎么利用还要依情况而定。
像上面这道题目,统计好一共有多少元素加入了queue这个容器中之后,你需要判断在这个数是否和总数目相等,如果相等,则返回true,反之则反之。
话不多说,上代码
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
unordered_map<int, vector<int>> pre;//建立图所需的容器
vector<int> in(numCourses);//建入度所需的容器
for (int i = 0; i < prerequisites.size(); i++)
{
pre[prerequisites[i][1]].push_back(prerequisites[i][0]);//建表
in[prerequisites[i][0]]++;//统计入度
}
queue<int>q;
for(int i = 0; i < numCourses; i++)
{
if(in[i] == 0)
{
q.push(i);//初始工作
}
}
int cnt = 0;
while(!q.empty())
{
auto cur = q.front();
q.pop();
cnt++; //统计步数,也就是有多少元素加入过queue中
for(auto x : pre[cur])
{
if(--in[x] == 0)//为0则加入queue中
{
q.push(x);
}
}
}
return cnt == numCourses;
}
};
当然,对于力扣第210题课程表2,https://leetcode.cn/problems/course-schedule-ii/来说,大体的步骤都是一样的,只要设置一个存储最终答案的vector容器即可,并把step那个步骤换成容器的push操作即可,代码如下
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int>result;
unordered_map<int, vector<int>>pre;
vector<int>in(numCourses);
for(int i = 0; i < prerequisites.size(); i++)
{
in[prerequisites[i][0]]++;
pre[prerequisites[i][1]].push_back(prerequisites[i][0]);
}
queue<int>q;
for(int i = 0; i < in.size(); i++)
{
if(in[i] == 0)
{
q.push(i);
}
}
while(!q.empty())
{
int cur = q.front();
q.pop();
result.push_back(cur);
for(int i =0; i < pre[cur].size(); i++)
{
if(--in[pre[cur][i]] == 0)
{
q.push(pre[cur][i]);
}
}
}
if(result.size() < numCourses)
return {};
else
return result;
}
以上是写题过程中的小小记录,希望大家指正。