拓扑排序(Topological Sorting):Kahn 算法和 DFS 算法

拓扑排序(Topological Sorting):Kahn 算法和 DFS 算法

拓扑排序(TopoSort)有相当广泛的应用,比如依赖关系分析、图是否有环的检测、编译优化中的数据流分析等。

拓扑排序,就是任意一条边 u->v,节点 u 都先于节点 v 。

显然,有向图中有环的话,就不存在拓扑排序,所以我们讲的拓扑排序是针对有向无环图(DAG)的。拓扑排序可能不是唯一的,如下图,ABDCEF 、ABDECF 和 ABCDEF 都是这个 DAG 的拓扑排序。
在这里插入图片描述
上文 图的邻接矩阵、邻接表存储和图的广度优先搜索(BFS)、深度优先搜索(DFS)介绍 BFS 和 DFS 算法时,使用的是图的邻接表存储方式,这次我使用邻接矩阵存储方式来介绍拓扑排序。完整的代码放到文章最后,方便大家验证。

#define MaxVertexNum 10
typedef char VertexType;
typedef int EdgeType;

typedef struct
{
    VertexType vertex[MaxVertexNum];
    EdgeType edge[MaxVertexNum][MaxVertexNum];
    int vexnum, edgenum;
} AdjMatGraph;

Kahn 算法

首先介绍的是 Kahn 算法,Kahn 算法非常简单,根据拓扑序很容易理解。DAG 中有一条边 u->v,则 u 要排在 v 前面,那么 ADG 中入度为 0 的顶点,则不会依赖任何其他顶点,可以排在前面。算法基本思想:首先找到入度为 0 的顶点,将其输出到序列中,并将该顶点删除,则该顶点指向的顶点入度相应减 1。重复上述过程,直到完成所有顶点的排序,最后得到的序列就是拓扑排序。算法实现如下:

 void kahnTopoSort(const AdjMatGraph& g) {
     int* indegree =  new int[g.vexnum];
     memset(indegree, 0, g.vexnum * sizeof(int));
     for (int i = 0; i < g.vexnum; i++) {
         for (int j = 0; j < g.vexnum; j++) {
             if (g.edge[i][j] == 1) {
                 indegree[j] += 1;
             }
         }
     }   
     std::queue<int> q;
     for (int i = 0; i < g.vexnum; i++) {
         if (indegree[i] == 0) {
             q.push(i);
         }
     }   
     while (!q.empty()) {
         int u = q.front();
         q.pop();
         // visit
         std::cout << g.vertex[u];
         for (int j = 0; j < g.vexnum; j++) {
             if (g.edge[u][j] == 1) {
                 indegree[j] -= 1;
                 if (indegree[j] == 0) {
                     q.push(j);
                 }
             }
         }
     }   
     delete [] indegree;
 }

DFS 算法

第二种算法是使用 DFS 算法遍历图,并且在回溯的时候将遍历的顶点入栈,那么先入栈的顶点必定入度不为 0,而入度为 0 的顶点必定是最后入栈。算法实现如下:

void dfs(const AdjMatGraph& g, const int u, bool visited[], std::stack<int>& s) {
     visited[u] = true;
     for (int j = 0; j < g.vexnum; j++) {
         if (g.edge[u][j] == 1 && !visited[j]) {
             dfs(g, j, visited, s); 
         }
     }   
     s.push(u);
 }
 
 void dfsTopoSort(const AdjMatGraph& g) {
     std::stack<int> s;
     bool *visited = new bool[g.vexnum];
     for (int i = 0; i < g.vexnum; i++) {
         if (!visited[i]) {
             dfs(g, i, visited, s); 
         }
     }   
     // visit
     while (!s.empty()) {
         int v = s.top();
         std::cout << g.vertex[v];
         s.pop();
     }   
     std::cout << std::endl;
     delete [] visited;
 }

最后附上完整代码方便测试:

#include<iostream>
#include<cstring>
#include<queue>
#include<stack>

#define MaxVertexNum 50
typedef char VertexType;
typedef int EdgeType;

typedef struct
{
    VertexType vertex[MaxVertexNum];
    EdgeType edge[MaxVertexNum][MaxVertexNum];
    int vexnum, edgenum;
} AdjMatGraph;

// lookup index of vertex u in the graph
int LocateVex(const AdjMatGraph& g, VertexType u)
{
    int i;
    for(i = 0; i < g.vexnum; ++i) {
        if(u == g.vertex[i])
        {
            return i;
        }
    }

    return -1;
}

void printAdjMatGraph(const AdjMatGraph& g) {
    for (int i = 0; i < g.edgenum; i++) {
        for (int j = 0; j < g.edgenum; j++) {
            if (g.edge[i][j] == 1) {
                std::cout << g.vertex[i] << " -> " << g.vertex[j] << std::endl;
            }
        }
    }
}

void createAdjMatGraph(AdjMatGraph& g) {
    std::cout << "Enter vertex num: ";
    std::cin >> g.vexnum;
    std::cout << "Enter edge num: ";
    std::cin >> g.edgenum;

    std::cout << "Enter " << g.vexnum << " vertex value: ";
    for (int i = 0; i < g.vexnum; i++) {
        std::cin >> g.vertex[i];
    }

    memset(g.edge, 0, g.vexnum * g.vexnum * sizeof(EdgeType));

    std::cout << "Enter " << g.edgenum << " edge info:" << std::endl;
    for (int e = 0; e < g.edgenum; e++) {
        VertexType v1, v2;
        std::cin >> v1 >> v2;
        int i = LocateVex(g, v1);
        int j = LocateVex(g, v2);
        g.edge[i][j] = 1;
    }
}

void kahnTopoSort(const AdjMatGraph& g) {
    int* indegree =  new int[g.vexnum];
    memset(indegree, 0, g.vexnum * sizeof(int));
    for (int i = 0; i < g.vexnum; i++) {
        for (int j = 0; j < g.vexnum; j++) {
            if (g.edge[i][j] == 1) {
                indegree[j] += 1;
            }
        }
    }
    std::queue<int> q;
    for (int i = 0; i < g.vexnum; i++) {
        if (indegree[i] == 0) {
            q.push(i);
        }
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        // visit
        std::cout << g.vertex[u];
        for (int j = 0; j < g.vexnum; j++) {
            if (g.edge[u][j] == 1) {
                indegree[j] -= 1;
                if (indegree[j] == 0) {
                    q.push(j);
                }
            }
        }
    }
    std::cout << std::endl;
    delete [] indegree;
}

void dfs(const AdjMatGraph& g, const int u, bool visited[], std::stack<int>& s) {
    visited[u] = true;
    for (int j = 0; j < g.vexnum; j++) {
        if (g.edge[u][j] == 1 && !visited[j]) {
            dfs(g, j, visited, s);
        }
    }
    s.push(u);
}

void dfsTopoSort(const AdjMatGraph& g) {
    std::stack<int> s;
    bool *visited = new bool[g.vexnum];
    for (int i = 0; i < g.vexnum; i++) {
        if (!visited[i]) {
            dfs(g, i, visited, s);
        }
    }
    // visit
    while (!s.empty()) {
        int v = s.top();
        std::cout << g.vertex[v];
        s.pop();
    }
    std::cout << std::endl;
    delete [] visited;
}

int main() {
    AdjMatGraph g;
    createAdjMatGraph(g);
    printAdjMatGraph(g);
    kahnTopoSort(g);
    dfsTopoSort(g);
    return 0;
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值