拓扑排序 dfs
2015-06-01 16:36
295 查看
拓扑排序简单来说就是把一个图的所有节点排序,使得每一条有向边(u,v)对应的u都排在v的前面。
拓扑排序最大的用途就是判断一个有向图是否有环,当然判断还有一种方法就是Floyd算法。
如果用邻接表的话拓扑排序的时间复杂度是O(N*E),邻接矩阵是O(N^2),N表示顶点数,E表示边数,Floyd时间复杂度是O(N^3)。
性质
1、 拓扑排序在有向无环图中才能排出有效的序列,否则能判断该有向图有环。
2、如果输入的有向图中的点,不存在入度为0的点,则该有向图存在回路
3、如果存在的入度为0的点大于一个,则该有向图肯定不存在一个可以确定的拓扑序列但并不妨碍拓扑排序
下面给出核心程序:
[cpp] view
plaincopyprint?
vector<int>g
;//邻接表存储
int vis
,topo
,cnt;
bool dfs(int u)
{
vis[u] = -1;//-1用来表示顶点u正在访问
for(int i = 0 ; i < g[u].size() ; i ++)
{
if(vis[g[u][i]] == -1)//表示这个点进入了两次,肯定出现了环
return false;
else if(vis[g[u][i]] == 0)
{
dfs(g[u][i]);
}
}
vis[u] = 1;
topo[cnt++] = u;//放到结果数组里,输出的时候记得倒序输出,(回溯的原因)
return true;
}
bool toposort(int n)
{
memset(vis,0,sizeof(vis));
for(int i = 1 ; i <= n ; i ++)
{
if(!vis[i])
{
if(!dfs(i)) return false;//huan
}
}
return true;
}
非递归代码,这段代码无法判断是否有环
[cpp] view
plaincopyprint?
for(i=1;i<=n;i++)//外层循环n次,in[]数组用来记录每个点的入度
{
j=1;
while(in[j]!=0) j++;//从第一个节点开始找到一个节点入度为0的节点
ans[i]=j;//存储答案
in[j]=-1;//将该节点的入度更新为-1
for( k=1;k<=n;k++)//将所有与节点j相连的节点的入度值全部减1
if(vis[j][k]==1) in[k]--;
}
晚上做题的时候想起来,拓扑排序还有一个重要的功能就是判断节点是一条链,还是在某个节点出现了分叉,这个很好理解,就用上面的非递归代码就可以判断,每次找入度为0的节点数目只能有1个,如果出现了两个则说明在该节点的父亲节点出现了分叉。
转:http://blog.csdn.net/acceptedxukai/article/details/6959882
拓扑排序最大的用途就是判断一个有向图是否有环,当然判断还有一种方法就是Floyd算法。
如果用邻接表的话拓扑排序的时间复杂度是O(N*E),邻接矩阵是O(N^2),N表示顶点数,E表示边数,Floyd时间复杂度是O(N^3)。
性质
1、 拓扑排序在有向无环图中才能排出有效的序列,否则能判断该有向图有环。
2、如果输入的有向图中的点,不存在入度为0的点,则该有向图存在回路
3、如果存在的入度为0的点大于一个,则该有向图肯定不存在一个可以确定的拓扑序列但并不妨碍拓扑排序
下面给出核心程序:
[cpp] view
plaincopyprint?
vector<int>g
;//邻接表存储
int vis
,topo
,cnt;
bool dfs(int u)
{
vis[u] = -1;//-1用来表示顶点u正在访问
for(int i = 0 ; i < g[u].size() ; i ++)
{
if(vis[g[u][i]] == -1)//表示这个点进入了两次,肯定出现了环
return false;
else if(vis[g[u][i]] == 0)
{
dfs(g[u][i]);
}
}
vis[u] = 1;
topo[cnt++] = u;//放到结果数组里,输出的时候记得倒序输出,(回溯的原因)
return true;
}
bool toposort(int n)
{
memset(vis,0,sizeof(vis));
for(int i = 1 ; i <= n ; i ++)
{
if(!vis[i])
{
if(!dfs(i)) return false;//huan
}
}
return true;
}
非递归代码,这段代码无法判断是否有环
[cpp] view
plaincopyprint?
for(i=1;i<=n;i++)//外层循环n次,in[]数组用来记录每个点的入度
{
j=1;
while(in[j]!=0) j++;//从第一个节点开始找到一个节点入度为0的节点
ans[i]=j;//存储答案
in[j]=-1;//将该节点的入度更新为-1
for( k=1;k<=n;k++)//将所有与节点j相连的节点的入度值全部减1
if(vis[j][k]==1) in[k]--;
}
晚上做题的时候想起来,拓扑排序还有一个重要的功能就是判断节点是一条链,还是在某个节点出现了分叉,这个很好理解,就用上面的非递归代码就可以判断,每次找入度为0的节点数目只能有1个,如果出现了两个则说明在该节点的父亲节点出现了分叉。
转:http://blog.csdn.net/acceptedxukai/article/details/6959882
相关文章推荐
- qaxwidget去掉网页上的边框
- 函数指针与指针函数
- STUN/TURN/ICE协议在P2P SIP中的应用(二)
- JetBRAINS 系列注册机
- 23_css清除浮动.html
- 黑马程序员——IO流(二)
- 22_css浮动布局示例.html
- 用两个栈实现一个队列的问题
- 学习latex排版的感受
- 无需投入成本,教你配置服务器,防止用户数据被人为泄漏
- iphone使用开源代码Asyncsocket进行socket编程
- Linux下ln链接命令详解
- 如何将密切好友的微信聊天记录恢复到自己的微信中
- webapp调试工具weinre的使用
- 21_css布局3_定位布局.html
- CAN错误计数值变动条件
- STUN/TURN/ICE协议在P2P SIP中的应用(一)
- JavaScript prototype 属性
- 21_css布局2_浮动布局.html
- 21_css布局1_默认布局.html