非递归 Kosaraju 的两次传递算法实现需要很长时间才能在大型数据集上执行
Non recursive Kosaraju's two pass algorithm implementation taking forever to execute on a large data set
-
我为一项已经过了最后期限的作业编写了这个代码。
-
这个实现可以很好地处理各种较小的测试用例,并在图中显示5个最大的强连接组件的大小。
-
但是当我在大约875714个顶点的赋值数据集上运行它时,它似乎永远执行。(60分钟后第一次DFS通行证都没有出来)
-
我使用了DFS例程的非递归堆栈实现,因为我听说大量的顶点会导致递归堆栈溢出问题。
-
如果有人能指出,这段代码中的内容使它在大型数据集中表现出这种行为,那将非常有帮助。
-
输入文件由图形中的边列表组成。一条边/一条线。
(例如):
12
2 3
3 1
3 4
5 4
大型图形测试用例zip文件的下载链接
链接到我的程序文件
代码如下:
//宏观定义和全局变量
#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 1n";
for(int i = N - 1; i >= 0; i--)
if(v[i] != 1)
DFS(gr, i, 1);
cout<<"nPass 1 completedn";
fill(all(v), 0);
cout<<"nInside pass 2n";
for(int i = N - 1; i >= 0; i--)
if(v[ ft[i] ] != 1)
DFS(g, ft[i], 2);
cout<<"nPass 2 completedn";
}
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 successfullyn";
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-对于大型输入,cin
不如scanf
快:因为输入文件很大,所以最好使用scanf
读取数据
2-按值将大数据传递给函数不是一个好主意:您的代码中有两个巨大的图,您可以按值将它们传递给函数。这需要很多时间,因为每次你都在复制数据
3-不需要使用iterator
来遍历vector
:因为您使用的是vector
,并且您可以通过[]
运算符随机访问它,所以不需要使用iterator
来访问数据
4-您的DFS效率低下:这是最重要的一个。每次程序转到while
的开头并检查stack
顶部元素的邻接列表时,都要从头开始并检查元素。这使得算法效率非常低,因为你要一遍又一遍地检查一些东西。您可以简单地存储已检查的子元素的数量,当您返回到此元素时,您可以从下一个元素开始,而不是从头开始。
#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 1n";
for(int i = N - 1; i >= 0; i--)
if(v[i] != 1)
DFS(gr, i, 1);
cout<<"nPass 1 completedn";
fill(all(v), 0);
fill(all(childsVisited), 0);
cout<<"nInside pass 2n";
for(int i = N - 1; i >= 0; i--)
if(v[ ft[i] ] != 1)
DFS(g, ft[i], 2);
cout<<"nPass 2 completedn";
}
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 successfullyn";
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: ";
}
相关文章:
- 使用Boost Interprocess创建托管共享内存需要很长时间
- SFML RenderWindow打开窗口需要很长时间
- Kafka C++客户端需要很长时间才能收到消息
- 给定使用 C++ 或 C,我如何测量在 linux 下进行线程切换需要多长时间?可能吗?
- asio::read() 需要很长时间,使用 asio::write 没有问题
- 将线程锁定很长时间
- 正在等待在非阻塞文件描述符上长时间运行ioctl
- 即使长时间等待,C++线程也不会加入
- 连接() 在连接被拒绝时长时间挂起
- 为什么这段代码需要这么长时间才能用 g++ 编译?
- 如何在长时间运行的方法中等待信号?
- mbed 套接字连接需要很长时间
- Lambda 捕获此函数和长时间运行的函数
- C程序的示例长时间执行时间
- 长时间运行的脚本的 symfony 执行
- 可执行文件在无限大小写(任何时间限制)下将运行多长时间
- 非递归 Kosaraju 的两次传递算法实现需要很长时间才能在大型数据集上执行
- 如何为长时间运行的程序执行文件输出
- 哪些函数需要很长时间才能执行?
- 为什么与 C 和 C++ 相比,C# 代码需要很长时间才能执行