拓扑排序的DFS和BFS

博主以前有一个疑问,DFS和BFS各自的适用范围是?我想你今天看了这篇文章之后会有一个判断!


BFS

数据结构与算法分析:c语言描述(p217)
已经存在一个Indgree入度数组(indgree[v]={(u,v)的数目})
以及一个邻接矩阵,求一个拓扑排序
提示:图中出现环就会拓扑失败
代码风格被我改为了C++

void TopSort(vector<vector<int>> G){    
//图中所有的点都要被遍历到,每次取出一个点,共执行NumVertex次
    for(int counter=0;counter<G.size();counter++){
        int v=findVertexIndgreeZero(G);//寻找入度为0的点
        if(!v){
                cout<<"有环,失败!"<<endl;
                return;
            }
        TopNum[v]=counter;//第counter+1个被遍历到的
        for(int i;i<G[v].size();i++){
            if(G[v][i])
                indgree[i]--;
        }
    }
}

用一句话来概括这个算法就是依次寻找出入度为0的点,然后将其所通的所有点入度都减1。循环直至结束或者报错(有环)。

上面这个算法存在优化的余地,findVertexIndgreeZero()的复杂度为O(n),执行n次为O(N2)次,用一个队列会大大缩减复杂度

void TopSort(vector<vector<int>> G){
    int counter=0;
    queue<int> q;
    for(int i=0;i<G.size();i++){
        if(indgree[i]==0);
        q.push(i);
    }
    while(!q.empty()){
        int u=q.top();q.pop();
        TopNum[u]=counter++;
        for(int i=0;i<G[u].size();i++){
            if(G[u][i]){
                if(--indgree[i]==0)
                    q.push(i);
                }
            }
        }
    if(counter!=G.size())
        cout<<"有环"<<endl;
}

这个结果很有趣,我们可以不严谨地总结一下“拓扑排序就是在找入度0点+更新入度”。
题外话
另外TopNum[i]保存了遍历的顺序。那么能不能TopNum[counter]=i,这样呢。。也可以。因为i和counter肯定是一一映射的关系。如果学习过数据库,那么你就可以说:谁来做主键都可以。

DFS

刘汝佳 算法竞赛入门经典第二版
P167
假设有n个变量,m个二元组(u,v),分别表示u< v。那么寻找一个不等式,包含所有的变量。类似于a< b,b< c ,则输出a< b< c;

我们可以把二元组小于关系看作边关系。这一转换其实很自然
然后,寻找一个不等式,其实就是在寻找一个拓扑顺序。那么,这个问题其实就是一个拓扑排序,完全可以用BFS完成

但是还有另外一种比较有趣的解法,就是使用dfs

我们首先定义一个函数

bool dfs(int u);//u代表当前点,返回点u之后是否存在一个拓扑路线

有了这个定义就不难继续做下去了,我们再想到:当前点u若是想能够返回true,那么它所能到达(u->v)的所有点也应该都能。
那么,失败的具体条件是什么?就是成环

只要之后遍历到的点和之前的点u有关系(v->u),那么就说明成环!返回false。
那么,代码应该是:

int vector<vector<int>> G 
int c[maxn];
int TopNum[maxn];
int t;
bool dfs(int u){
    c[u]=-1;
    for(int i=0;i<G.size();i++)
        if(G[u][i]){
            if(c[i]==-1){//大水冲了龙王庙,这个i点在之前已经被遍历到了,成环!
                return false;       
            }
            if(!c[i]&&!dfs(i)) return false;
        }
        //经过了检验
        c[u]=1;
        TopNum[--t]=u;
        return true;
}
bool topsort(){
    int t=n;
    memset(c,0.sizeof(c));
    for(int i=0;i<G.size();i++)
        if(!c[u])
            if(!dfs(u))
                return false;
    return true;            
}

版权声明:本文为博主原创文章,转载请标明出处。

posted @ 2015-09-12 15:02  Fridge  阅读(536)  评论(0编辑  收藏