《Data Structures and Algorithm Analysis in C》(数据结构与算法分析 C语言描述)

拓扑排序

条件:无圈。顶点v的入度定义为边(u, v)的条数。步骤:

  1. 找出任意没有入边(入度为零)的顶点,显示该点,删除它和它的边。
  2. 重复步骤1直到图为空。

复杂度O(|E| + |V|)。

void topo_sort(unordered_map<string, vector<string>> graph, 
                unordered_map<string, int> indegree, 
                unordered_map<string, int> &topo_num)
{
    queue<string> head;  // 入度为0的点
    for(auto node : indegree)
    {
        if(node.second == 0)
            head.push(node.first);
    }
    int cnt = 0;  
    while(!head.empty())
    {
        string h = head.front();
        head.pop();
        topo_num[h] = ++cnt;  // 顺序
        for(auto adj : graph[h])
        {
            indegree[adj]--;
            if(indegree[adj] == 0)
                head.push(adj);
        }
    }
}

int main(int argc, const char** argv) {
    unordered_map<string, vector<string>> graph;  // 邻接表  O(|E| + |V|)
    vector<string> v1 = {"v2", "v3", "v4"};
    vector<string> v2 = {"v4", "v5"};
    vector<string> v3 = {"v6"};
    vector<string> v4 = {"v3", "v6", "v7"};
    vector<string> v5 = {"v4", "v7"};
    vector<string> v7 = {"v6"};
    graph["v1"] = v1;
    graph["v2"] = v2;
    graph["v3"] = v3;
    graph["v4"] = v4;
    graph["v5"] = v5;
    graph["v6"] = vector<string>();
    graph["v7"] = v7;

    unordered_map<string, int> indegree;
    for(auto node : graph)
    {
        indegree[node.first] = 0;
    }
    
    for(auto node : graph)
    {
        for(auto adj : node.second)
        {
            indegree[adj]++;
        }   
    }   
    // for(auto node : indegree)
    // {
    //     cout << node.first << ":" << node.second << endl;
    // }   
    unordered_map<string, int> topo_num;
    topo_sort(graph, indegree, topo_num);
    for(auto node : topo_num)
    {
        cout << node.first << "'s order: " << node.second << endl;
    }
    return 0;
}

Tarjan算法求割点割边

在这里插入图片描述

删除割点,图不再连通。
在这里插入图片描述
割点:C、D;割边:CG。

vector<vector<int>> Graph;  // 邻接表
int times = 1;              // 时间戳
vector<int> num;            // 节点遍历顺序号(时间戳)
vector<int> low;            // 节点不经过其父亲能到达最小时间戳
vector<int> parent;

void dfs(int v)
{
    num[v] = low[v] = times++;  // rule1:初始值
    int children = 0;
    for(int w: Graph[v])
    {
        children++;
        if(!num[w])  // w未访问
        {
            parent[w] = v;
            dfs(w);
            if(parent[v] != -1 && low[w] >= num[v])    // case1:非root且有child
            {
                cout << v << "是割点" << endl;
            }
            else if(parent[v] == -1 && children >= 2)  // case2:root且child>=2
            {
                cout << v << "是割点" << endl;
            }
            if(low[w] > num[v])
            {
                cout << v << "->" << w << "是割边" << endl;
            }
            low[v] = min(low[v], low[w]);  // rule3:所有边(v,w)中最小的low[w]
        }
        else if(w != parent[v])  // 背向边
        {
            low[v] = min(low[v], num[w]);  // rule2:所有背向边(v,w)中最小的num[w]
        }
    }
}
int main(int argc, const char** argv) {
    vector<int> v0 = {};
    vector<int> v1 = {2, 4};
    vector<int> v2 = {1, 3};
    vector<int> v3 = {2, 4, 7};
    vector<int> v4 = {1, 3, 5, 6};
    vector<int> v5 = {4, 6};
    vector<int> v6 = {4, 5};
    vector<int> v7 = {3};
    Graph.push_back(v0);
    Graph.push_back(v1);
    Graph.push_back(v2);
    Graph.push_back(v3);
    Graph.push_back(v4);
    Graph.push_back(v5);
    Graph.push_back(v6);
    Graph.push_back(v7);
    
    num = vector<int>(Graph.size(), 0);
    low = vector<int>(Graph.size(), 0);
    parent = vector<int>(Graph.size(), -1);

    dfs(1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值