C++ 非递归Kosaraju';s的两次通过算法实现需要在大型数据集上永远执行

C++ 非递归Kosaraju';s的两次通过算法实现需要在大型数据集上永远执行,c++,algorithm,stl,graph-algorithm,kosaraju-algorithm,C++,Algorithm,Stl,Graph Algorithm,Kosaraju Algorithm,我为一个已经过了最后期限的作业编写了这个代码 此实现在各种较小的测试用例中完全可以正常工作,并在图中显示5个最大的强连接组件的大小 但当我在大约875714个顶点的赋值数据集上运行它时,它似乎永远执行。(60分钟后第一次通过DFS时甚至没有出现) 我使用了DFS例程的非递归堆栈实现,因为我听说大量顶点导致递归堆栈溢出问题 如果有人能指出,在这段代码中,是什么让它在大数据集上表现出这样的行为,这将非常有帮助 输入文件由图形中的边列表组成。一条边/一条线 (例如): 1 2 2 3 3.1 34

我为一个已经过了最后期限的作业编写了这个代码

  • 此实现在各种较小的测试用例中完全可以正常工作,并在图中显示5个最大的强连接组件的大小

  • 但当我在大约875714个顶点的赋值数据集上运行它时,它似乎永远执行。(60分钟后第一次通过DFS时甚至没有出现)

  • 我使用了DFS例程的非递归堆栈实现,因为我听说大量顶点导致递归堆栈溢出问题

  • 如果有人能指出,在这段代码中,是什么让它在大数据集上表现出这样的行为,这将非常有帮助

  • 输入文件由图形中的边列表组成。一条边/一条线

  • (例如):

    1 2

    2 3

    3.1

    34

    5.4

    代码如下: //宏定义和全局变量

    #define N 875714
    #define all(a) (a).begin(), (a).end()
    #define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
    
    vi v(N), ft, size;
    
    //非递归DFS算法

    void DFS(vvi g, int s, int flag)
    {
    stack<int> stk;
    stk.push(s);
    v[s] = 1;
    
    int jumpOut, count;
    vi::iterator i;
    
    if(flag == 2)
         count = 1;
    
    while(!stk.empty())
    {
    i = g[stk.top()].begin();
    jumpOut = 0;
    
    for(; i != g[stk.top()].end(); i++)
    {
        if(v[*i] != 1)
        {
            stk.push(*i);
            v[*i] = 1;
    
            if(flag == 2) //Count the SCC size
                count++;
    
            jumpOut = 1; //Jump to the while loop's beginning
            break;
        }
     }
    
     if(flag == 1 && jumpOut == 0) //Record the finishing time order of vertices
        ft.push_back(stk.top());
    
     if(jumpOut == 0)
          stk.pop();
    }
    
    if(flag == 2)
        size.push_back(count); //Store the SCC size
    }
    
    void kosaraju(vvi g, vvi gr)
    {
    cout<<"\nInside pass 1\n";
    
    for(int i = N - 1; i >= 0; i--)
        if(v[i] != 1)
            DFS(gr, i, 1);
    
    cout<<"\nPass 1 completed\n";
    
    fill(all(v), 0);
    
    cout<<"\nInside pass 2\n";
    
    for(int i = N - 1; i >= 0; i--)
        if(v[ ft[i] ] != 1)
            DFS(g, ft[i], 2);
    
    cout<<"\nPass 2 completed\n";
    }
    
    void DFS(vvi g、int s、int标志)
    {
    堆栈stk;
    stk.push(s);
    v[s]=1;
    整数跳出,计数;
    迭代器i;
    如果(标志==2)
    计数=1;
    而(!stk.empty())
    {
    i=g[stk.top()].begin();
    跳出=0;
    for(;i!=g[stk.top()].end();i++)
    {
    如果(v[*i]!=1)
    {
    标准推力(*i);
    v[*i]=1;
    if(flag==2)//计算SCC大小
    计数++;
    jumpOut=1;//跳到while循环的开头
    打破
    }
    }
    if(flag==1&&jumpOut==0)//记录顶点的完成时间顺序
    ft.向后推(stk.top());
    如果(跳线==0)
    stk.pop();
    }
    如果(标志==2)
    size.push_back(count);//存储SCC大小
    }
    
    //2路Kosaraju算法

    void DFS(vvi g, int s, int flag)
    {
    stack<int> stk;
    stk.push(s);
    v[s] = 1;
    
    int jumpOut, count;
    vi::iterator i;
    
    if(flag == 2)
         count = 1;
    
    while(!stk.empty())
    {
    i = g[stk.top()].begin();
    jumpOut = 0;
    
    for(; i != g[stk.top()].end(); i++)
    {
        if(v[*i] != 1)
        {
            stk.push(*i);
            v[*i] = 1;
    
            if(flag == 2) //Count the SCC size
                count++;
    
            jumpOut = 1; //Jump to the while loop's beginning
            break;
        }
     }
    
     if(flag == 1 && jumpOut == 0) //Record the finishing time order of vertices
        ft.push_back(stk.top());
    
     if(jumpOut == 0)
          stk.pop();
    }
    
    if(flag == 2)
        size.push_back(count); //Store the SCC size
    }
    
    void kosaraju(vvi g, vvi gr)
    {
    cout<<"\nInside pass 1\n";
    
    for(int i = N - 1; i >= 0; i--)
        if(v[i] != 1)
            DFS(gr, i, 1);
    
    cout<<"\nPass 1 completed\n";
    
    fill(all(v), 0);
    
    cout<<"\nInside pass 2\n";
    
    for(int i = N - 1; i >= 0; i--)
        if(v[ ft[i] ] != 1)
            DFS(g, ft[i], 2);
    
    cout<<"\nPass 2 completed\n";
    }
    
    void kosaraju(vvi g、vvi gr)
    {
    
    cout您可以应用以下几个改进:
    1-
    cin
    对于大输入来说速度不如
    scanf
    :因为您的输入文件很大,所以最好使用
    scanf
    读取数据。
    2-按值将大数据传递给函数不是一个好主意。代码中有两个巨大的图形,可以按值传递给函数。这需要很多时间,因为每次都要复制数据。
    3-无需使用
    迭代器
    遍历
    向量
    :因为您使用的是
    向量
    ,并且您可以通过
    []
    操作符随机访问它,所以无需使用
    迭代器
    访问数据。
    4-您的DFS效率不高:这是最重要的一个。每次程序转到
    的开头,而
    并检查
    堆栈顶部元素的邻接列表
    时,您都从开头开始检查元素。这使得算法效率非常低,因为您正在检查一些精简的元素你可以简单地存储你检查过的子元素的数量,当你返回到这个元素时,你可以从下一个元素开始,而不是从头开始

    #include<iostream>
    #include<vector>
    #include<stack>
    #include<algorithm>
    #include<fstream>
    #include<string>
    #include<sstream>
    using namespace std;
    
    typedef vector<int> vi;
    typedef vector<vi> vvi;
    
    #define N 875714
    #define sz(a) int((a).size())
    #define all(a) (a).begin(), (a).end()
    #define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
    
    vi v(N), ft, size;
    vi childsVisited(N);
    
    void DFS(vvi &g, int s, int flag)
    {
        stack<int> stk;
        stk.push(s);
        v[s] = 1;
    
        int jumpOut, count;
    
        if(flag == 2)
            count = 1;
        int counter = 0;
        while(!stk.empty())
        {
            jumpOut = 0;
            int cur = stk.top();
            for ( ;childsVisited[cur] < g[cur].size(); ++childsVisited[cur] )
            //for ( int i=0; i< g[cur].size(); ++i )
            //for(; i != g[stk.top()].end(); i++)
            {
                int i = childsVisited[cur];
                int next = g[cur][i];
                if(v[next] != 1)
                {
                    stk.push(next);
                    v[next] = 1;
                    if(flag == 2) //Count the SCC size
                        count++;
    
                    jumpOut = 1; //Jump to the while loop's beginning
                    break;
                }
            }
    
            if(flag == 1 && jumpOut == 0) //Record the finishing time order of vertices
                ft.push_back(stk.top());
    
            if(jumpOut == 0)
                stk.pop();
        }
    
        if(flag == 2)
            size.push_back(count); //Store the SCC size
    }
    
    void kosaraju(vvi &g, vvi &gr)
    {
        cout<<"\nInside pass 1\n";
    
        for(int i = N - 1; i >= 0; i--)
            if(v[i] != 1)
                DFS(gr, i, 1);
    
        cout<<"\nPass 1 completed\n";
    
        fill(all(v), 0);
        fill(all(childsVisited), 0);
    
        cout<<"\nInside pass 2\n";
    
        for(int i = N - 1; i >= 0; i--)
            if(v[ ft[i] ] != 1)
                DFS(g, ft[i], 2);
    
        cout<<"\nPass 2 completed\n";
    }
    
    int main()
    {
        freopen("input.txt","r",stdin);
        vvi g(N), gr(N);
        //ifstream file("/home/tauseef/Desktop/DAA/SCC.txt");
        int first, second;
        //string line;
        unsigned long int cnt = 0;
    
        //while(getline(file,line,'\n')) //Reading from file
        //{
            //stringstream ss(line);
            //ss >> first;
            //ss >> second;
            //if(first == second) //Eliminating self loops
                //continue;
        for ( int i = 0; i < 5105043; ++i ){
            int first, second;
            scanf("%d %d",&first,&second);
            g[first-1].push_back(second-1); //Creating G & Grev
            gr[second-1].push_back(first-1);
        }
            //cnt++;
        //}
    
        cout<<"\nfile read successfully\n";
    
    
        kosaraju(g, gr);
    
        cout<<"\nFinishing order is: ";
    
        sort(size.rbegin(), size.rend()); //Sorting the SCC sizes in descending order
    
        cout<<"\nThe largest 5 SCCs are: ";
    
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    使用名称空间std;
    typedef向量vi;
    typedef向量vvi;
    #定义N 875714
    #定义sz(a)int((a).size())
    #定义所有(a)(a).begin(),(a).end()
    #为(typeof((c.begin())i=(c.begin();i!=(c.end();i++)定义tr(c,i)
    vi v(N),英尺,尺寸;
    六儿童受访(N);
    无效DFS(vvi&g、内部s、内部标志)
    {
    堆栈stk;
    stk.push(s);
    v[s]=1;
    整数跳出,计数;
    如果(标志==2)
    计数=1;
    int计数器=0;
    而(!stk.empty())
    {
    跳出=0;
    int cur=stk.top();
    对于(;childsVisited[cur]你的图形有多少条边?大约5105042条边@sudomakeinstall2你能把你的图形上传到某个地方吗?已经在示例输入下附加了Zip文件链接。@sudomakeinstall2IKR FlareCat谢谢:D@sudomakeinstall2请让我知道你是如何修复的。如果能让孩子们访问DFS,那将是非常有帮助的(N)vector做到了这一点。不过代码中仍然存在一个小错误。让我们将childsVisited(N)作为CV(N)调用。由于CV是全局声明的,第二个DFS调用会产生不正确的值,因为第一个DFS调用的CV中存在值。当我尝试在DFS()中本地声明CV时执行再次返回到在大型图上永远运行,并且没有终止。相反,当我在第一次DFS调用后将CV重新初始化为全零时,代码工作正常。在DFS()中本地声明CV时出现此异常的原因可能是什么?澄清一下,你的意思是通过引用来传递吗?只是好奇。你是在问他回答中的“传递值”还是“声明孩子在本地访问”在我的评论中?@FlareCatapprove编辑,这样我就可以将其标记为答案@sudomakeinstall2:)Ok@sudomakeinstall2。但是数组在声明正确时需要大小?当我不确定容器的长度时该怎么办?