• 【数据结构】DFS求有向图的强连通分量


    用十字链表结构写的,根据数据结构书上的描述和自己的理解实现。但理解的不透彻,所以不知道有没有错误。但实验了几个都ok.

    #include <iostream>
    #include <vector>
    using namespace std;
    
    //有向图十字链表表示
    #define MAX_VERTEX_NUM 20
    
    typedef struct ArcBox{
        int tailvex, headvex; //该弧尾和头顶点的位置
        struct ArcBox *hlink, *tlink; //分别指向弧头相同和弧尾相同的弧的链域
    }ArcBox;
    
    typedef struct VexNode{
        int data;
        ArcBox *firstin, *firstout;//分别指向该顶点的第一条入弧和出弧
    }VexNode;
    
    typedef struct{
        VexNode xlist[MAX_VERTEX_NUM]; //表头向量
        int vexnum, arcnum; //有向图的顶点数和弧数
    }OLGraph;
    
    //定位顶点在xlist中的位置
    int LocateVex(OLGraph G, int data)
    {
        for(int i = 0; i < G.vexnum; i++)
        {
            if(G.xlist[i].data == data)
            {
                return i;
            }
        }
        cout << "error the vertex "<< data << " is not in the list"<<endl;
        return -1;
    }
    
    //有向图十字链表创建
    void CreateDG(OLGraph &G)
    {
        cout << "please input the number of vertex, the number of arc:";
        cin >> G.vexnum >> G.arcnum;
    
        for(int i = 0; i < G.vexnum; i++)
        {
            cout << "please input vertex data:";
            cin >> G.xlist[i].data;
    
            G.xlist[i].firstin = NULL;  //初始化指针
            G.xlist[i].firstout = NULL;
        }
    
        for(int k = 0; k < G.arcnum; k++)
        {
            int v1, v2; //弧的尾和头
            cout << "please input the tail and head vertex of each tail:";
            cin >> v1 >> v2;
    
            int i = LocateVex(G, v1);
            int j = LocateVex(G, v2);
            ArcBox * p = new ArcBox;
            p->headvex = j;
            p->tailvex = i;
            p->hlink = G.xlist[j].firstin;
            p->tlink = G.xlist[i].firstout;
    
            G.xlist[j].firstin = p;
            G.xlist[i].firstout = p;
        }
    }
    
    //单向深度优先搜索
    //输入: 图G, 开始遍历点v, 遍历标志visited, 遍历方向dir 0 表示从尾向头遍历 1表示从头到尾遍历, vecor存放跳出遍历的顺序
    void DFS(OLGraph G, int v, int * visited, int dir, vector<int> * vec)
    {
        visited[v] = 1;
        (*vec).push_back(v);
        if(dir == 0) //从尾向头遍历
        {
            ArcBox * w = G.xlist[v].firstout;
            while(w != NULL ) //注意 这里的while 
            {
                if(visited[w->headvex] == 1)
                {
                    w = w->tlink;
                }
                else//未访问过该点 递归遍历该点
                {
                    DFS(G, w->headvex, visited, dir, vec);
                    w = w->tlink;
                }
            }
        }
        else //从头向尾遍历
        {
            ArcBox * w = G.xlist[v].firstin;
            while(w != NULL)//查找下一个遍历点
            {
                if((visited[w->tailvex]) == 1)
                {
                    w = w->hlink;
                }
                else//未访问过该点 递归遍历该点
                {
                    DFS(G, w->tailvex, visited, dir, vec);
                    w = w->hlink;
                }
            }                
        }
    }
    
    //查找有向图强连通分量
    vector<vector<int>> FindConnectedPart(OLGraph G)
    {
        vector<vector<int>> ConnectedPart;
        vector<vector<int>> finished;
        int* visited = new int[G.vexnum];
        memset(visited, 0, G.vexnum * sizeof(int)); //初始化为全部没有访问过
    
        //从尾向头遍历
        for(int v = 0; v < G.vexnum; v++)
        {
            if(visited[v] == 0) //没有被访问过
            {
                vector<int> vec;
                DFS(G, v, visited, 0, &vec);
                finished.push_back(vec);
            }
        }
    
        //从头向尾遍历
        memset(visited, 0, G.vexnum * sizeof(int)); 
        vector<int>::iterator it;
        vector<vector<int>>::iterator it2;
        int* find = new int[G.vexnum]; //find标识顶点实际上是否被查找过
        for(int i = 0; i < G.vexnum; i++) 
        {
            find[i] = 0;
            visited[i] = 1;
        }
        for(it2 = finished.begin(); it2 < finished.end(); it2++)
        {
            //已经遍历过的部分visited不变,即都是1; find[i]= 0的表示本次遍历时不遍历结点i,为了跳过i,设它们的visited[i]=1; 但实际上,它们还没有被访问到
            //比如从尾到头遍历时得到两个分量 (1,2,3,4)(5)
            //那么为了找到重连通分量,从头到尾遍历4,3,2,1时不应该经过5 即可能从头到尾遍历时的分量是(1 2 3 5)(4)
            // 但实际上重连通分量为(1,2,3)(4)(5)三个
            for(it = it2->begin(); it < it2->end(); it++)
            {
                visited[*it] = 0; //只把本次遍历考虑到的顶点的visited设为0,其他为1,就不会加人遍历了
                find[*it] = 1;
            }
    
            for(it = it2->begin(); it < it2->end(); it++)
            {
                if(visited[*it] == 0) //没有被访问过
                {
                    vector<int> vec;
                    DFS(G, *it, visited, 1, &vec);
                    ConnectedPart.push_back(vec);
                }
            }
        }
    
        //输出重连通分量
        int n = 0;
        cout << "重连通分量有:" << endl;
        for(it2 = ConnectedPart.begin(); it2 < ConnectedPart.end(); it2++)
        {
            cout << ++n << ":";
            for(it = it2->begin(); it < it2->end(); it++)
            {
                cout << G.xlist[*it].data << " ";
            }
            cout<< endl;
        }
    
        delete [] visited;
        delete [] find;
        return ConnectedPart;
    }
    
    int main()
    {
        OLGraph G;
        CreateDG(G);
        FindConnectedPart(G);
    
        return 0;
    }

    http://blog.csdn.net/wsniyufang/article/details/6604458里面有将更好的算法。我还没看。

  • 相关阅读:
    还在纠结注册.com域名还是.cn域名?
    网站域名被墙的检测查询和解决办法
    阿里云服务器无法远程其他的mysql服务器
    如何维护一个产品
    使用bootstrap+asp.net mvc4+IBatis.Net实现的小程序
    bootstrap IE兼容
    mongodb命令使用
    聊天工具实现winform端实现
    二级域名设置
    org
  • 原文地址:https://www.cnblogs.com/dplearning/p/3992697.html
Copyright © 2020-2023  润新知