【发布时间】:2023-03-20 08:10:01
【问题描述】:
我正在尝试解决 Leetcode(link here) 上的拓扑排序问题。我惊讶地发现 C++ 比使用相同算法的 Java 慢! C++ 解决方案花费了将近 500ms,而 Java 只有 6~7ms。令人困惑……而且 C++ 也比 python、c# 和 javascript 慢。这是公认的解决方案运行时分布:
这里是 C++ 版本和 Java 版本的代码。两者都使用DSF方法进行拓扑排序。
//Java
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer>[] edges = new ArrayList[numCourses];
int[] visited = new int[numCourses];
int[] res = new int[numCourses];
for (int i = 0; i < edges.length; i++)
edges[i] = new ArrayList<Integer>();
for (int[] edge : prerequisites)
edges[edge[0]].add(edge[1]);
for (int i = 0, j = 0; i < numCourses; i++) {
j = dfs(i, edges, visited, res, j);
if (j == -1) return new int[0]; // cycle, return empty array
}
return res;
}
private int dfs(int v, List<Integer>[] edges, int[] visited, int[] res, int i) {
if (visited[v] == 2) return i; // black node
if (visited[v] == 1) return -1; // gray node -> cycle
visited[v] = 1;
for(int j : edges[v]) {
i = dfs(j, edges, visited, res, i);
if (i == -1) return -1; // if there is a cycle, propagate the error
}
visited[v] = 2;
res[i] = v;
return i+1;
}
--
//C++
vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
vector<int> outputs;
vector<int> nodes(numCourses, 0);
vector<list<int>> edges(numCourses);
for (auto i=prerequisites.begin(); i!=prerequisites.end(); i++) {
edges[i->first].push_back(i->second);
}
for(int i=0; i<numCourses; ++i)
{
if(!dfs(edges, outputs, nodes, i, numCourses))
{
outputs.clear();
return outputs;
}
}
return outputs;
}
bool dfs(vector<list<int>>& edges, vector<int>& outputs, vector<int>& nodes, int cur, int numCourses)
{
if(nodes[cur] == 1) return false;
if(nodes[cur] == 0)
{
nodes[cur]++;
for(auto i=edges[cur].begin(); i!=edges[cur].end(); ++i)
{
if(!dfs(edges, outputs, nodes, *i, numCourses))
return false;
}
nodes[cur]++;
outputs.push_back(cur);
}
return true;
}
【问题讨论】:
-
C++ 版本不是 1:1 端口,它与 Java 版本略有不同。所以你没有进行公平的比较。
-
@Yyao:如果在线评委没有告诉您它使用了哪些编译器选项,那么不幸的是,它作为基准毫无价值。如果它确实告诉了您,请告诉我们!
-
@Yyao “他们使用编译标志 -O0” 那么他们的基准测试完全没用,期间。你不应该看至少没有 -O2 编译的代码的性能
-
编译标志
-O0几乎字面意思的意思是,“让这段代码尽可能慢”;-) 只是因为一些假设的约束,“没有实际添加繁忙循环”和“没有应用可能使其更慢的聪明的代码大小优化”。
标签: java c++ algorithm topological-sort