非递归Kosaraju的两遍算法实现需要永远在大型数据集上执行

时间:2015-12-13 22:29:13

标签: c++ algorithm stl graph-algorithm kosaraju-algorithm

  • 我将此编码为已超过截止日期的作业。

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

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

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

  • 如果有人能够指出,这段代码中的内容会使大型数据集以这种方式运行,那将非常有用。

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

(例如):

1 2

2 3

3 1

3 4

5 4

Download link for the Large graph test case zip file

Link to my program file

代码如下:

//宏定义和全局变量

#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
}

// 2通过Kosaraju算法

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";
}

int main()
{
vvi g(N), gr(N);
ifstream file("/home/tauseef/Desktop/DAA/SCC.txt");
int first, second;
string line;

while(getline(file,line,'\n')) //Reading from file
{
    stringstream ss(line);
    ss >> first;
    ss >> second;
    if(first == second) //Eliminating self loops
        continue;

    g[first-1].push_back(second-1); //Creating G & Grev
    gr[second-1].push_back(first-1);
}

cout<<"\nfile read successfully\n";

kosaraju(g, gr);

cout<<"\nFinishing order is: ";
tr(ft, j)
    cout<<*j+1<<" ";
cout<<"\n";

sort(size.rbegin(), size.rend()); //Sorting the SCC sizes in descending order

cout<<"\nThe largest 5 SCCs are: ";
tr(size, j)
    cout<<*j<<" ";
cout<<"\n";

file.close();
}

1 个答案:

答案 0 :(得分:1)

您可以应用以下几项改进:
对于大型输入, 1- cin的速度不是scanf :由于您的输入文件很大,因此最好使用scanf来读取数据。
2-通过值将大数据传递给函数不是一个好主意:您的代码中有两个巨大的图形,您可以按值将它们传递给函数。每次制作数据副本时都需要花费很多时间 3-无需使用iterator来浏览vector :因为您使用的是vector,并且可以通过{{1}随机访问它运算符不需要使用[]来访问数据 4-您的DFS效率不高:这是最重要的一项。每次程序转到iterator的开头并检查while之上的元素的邻接列表,从头开始并检查元素。这使得算法效率非常低,因为您一遍又一遍地检查一些事情。您可以简单地存储已检查的子项数量,当您返回此元素时,您从下一个元素开始,而不是从开始开始。

stack