16 - 12 - 09 拓扑排序 (C++)

拓扑
不存在回路,就像流程图一样向下延伸。称AOV网图。
拓扑排序就是按照箭头顺序往后排的,是为了解决一个工程能否顺利进行的。拓扑排序还有一个重要的功能就是判断节点是一条链,还是在某个节点出现了分叉。

排序的基本思路:

…………方法一
现在我们可以得到这个算法的基本步骤:
1.构造空列表 L和S;
2.把所有没有依赖节点(入度为0)的节点放入L;
3.当L还有节点的时候,执行下面步骤:
3.1 L中拿出一个节点n(从L中remove掉),并放入S
3.2 对每一个邻近n的节点m,
3.2.1 去掉边(n,m);(表示加入最终结果集S)
3.2.2 如果m没有依赖节点(入度为零),把m放入L;
核心就是:每次都选取入度为0的节点,再更新其相邻的节点的入度 。
这个是直观也是常见的一种算法。我们用一个数组degree[ ]记录所有顶点的入度。删除点时更新该数组。
参考下面代码函数:topologicalSort_1( )

…………方法二
另外一种方法是参考DFS,对图的深度优先遍历做些修改。我们确信在有向图中如果存在一条边(u,v),那么顶点u会先于顶点v进入列表中。因此在深度遍历时,用栈来存储遍历的顺序。参考下面代码的函数:topologicalSort_2( )

// C++实现的拓扑排序算法
#include<iostream>
#include <list>
#include <stack>
using namespace std;

// 图类
class Graph
{
    int V;    //顶点个数

    // 邻接表
    list<int> *adj;
    // 拓扑排序方法 2的辅助函数
    void topologicalSortRecall(int v, bool visited[], stack<int> &Stack);

public:
    Graph(int V);

     // 添加边
    void addEdge(int v, int w);

    //拓扑排序普通方法
    void topologicalSort1();

    // 拓扑排序方法二
    void topologicalSort2();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w); //
}

//类似深度优先遍历,将和V相邻的顶点(且为访问过的)放入栈中
void Graph::topologicalSortRecall(int v, bool visited[], stack<int> &stk)
{
    //标记v为访问过的
    visited[v] = true;

    // 对每个顶点进行递归调用
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            topologicalSortRecall(*i, visited, stk);

    // 保存顶点
    stk.push(v);
}

// 方法二,使用递归调用实现拓扑排序
void Graph::topologicalSort2()
{
    stack<int> stk;
    bool *visited = new bool[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;

    //每个顶点都调用一次
    for (int i = 0; i < V; i++)
      if (visited[i] == false)
        topologicalSortRecall(i, visited, stk);

    // 打印
    while (stk.empty() == false)
    {
        cout << stk.top() << " ";
        stk.pop();
    }
}

// 方法一
void Graph::topologicalSort1()
{
    list<int>::iterator j;
    int degree[V];
    //遍历所有的边,计算入度
    for(int i=0; i<V; i++){
        degree[i] = 0;
        for (j = adj[i].begin(); j != adj[i].end(); ++j){
            degree[*j]++;
        }
    }
    list<int> zeroNodes;//所有入度为0的点
    list<int> result;//所有入度为0的点
    for(int i=0; i<V; i++){
        if(degree[i] == 0){
            zeroNodes.push_back(i);
        }
    }
    while(zeroNodes.size() > 0){
        int top = zeroNodes.back();
        zeroNodes.pop_back();
        result.push_back(top);
        for (j = adj[top].begin(); j != adj[top].end(); ++j){
            degree[*j]--;//删除和top相邻的边,并更新其它顶点的入度
            if(degree[*j] == 0) zeroNodes.push_back(*j);
        }
    }

    //打印结果
    for(j= result.begin(); j != result.end(); j++)
        cout << (*j) << " ";
}

int main()
{
    // 创建文中所以的图
    Graph g(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);

    cout << "Following is a Topological Sort of the given graph using  topologicalSort1\n";
    g.topologicalSort1();
    cout << endl;
    cout << "Following is a Topological Sort of the given graph using  topologicalSort2\n";
    g.topologicalSort2();
    return 0;
}

鸣谢
htp://www.acmerblog.com/topological-sorting-5896.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值