【问题标题】:Why C++ is slower than Java on topological sort?为什么 C++ 在拓扑排序上比 Java 慢?
【发布时间】: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


【解决方案1】:

int[] res = new int[numCourses];vector&lt;int&gt; outputs; 例如,这个例子中的问题是 Java 事先知道它需要多少空间,来自 C++ 的向量可能需要在运行期间进行调整(代价高昂,它涉及复制、分配和释放内存)。我不是说这是问题,这是问题之一。请务必为 C++ 测试构建版本,而不是调试,同时避免不必要的复制,这是减慢速度的根源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-04
    • 2012-02-24
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多