【问题标题】:Graph In-degree Calculation from Adjacency-list邻接表中的图形入度计算
【发布时间】:2014-04-08 07:28:05
【问题描述】:

我遇到了这个问题,它需要根据邻接表表示来计算图的每个节点的入度。

for each u
   for each Adj[i] where i!=u
     if (i,u) ∈ E
         in-degree[u]+=1

现在根据我的说法,它的时间复杂度应该是O(|V||E|+|V|^2),但我提到的解决方案将其描述为等于O(|V||E|)

请帮忙告诉我哪一个是正确的。

【问题讨论】:

    标签: algorithm graph asymptotic-complexity


    【解决方案1】:

    计算入度的复杂度不是 O(|V||E|),而是 O(|E|)。让我们考虑以下用于计算每个节点的入度的伪代码:

    for each u
      indegree[u] = 0;
    
    for each u
      for each v \in Adj[u]
        indegree[v]++;
    

    第一个循环的线性复杂度为 O(|V|)。对于第二部分:对于每个 v,最里面的循环最多执行 |E|次,而最外层循环执行 |V|次。因此,第二部分似乎具有复杂性 O(|V||E|)。实际上,代码对每条边执行一次操作,因此更准确的复杂度是 O(|E|)。

    【讨论】:

    • 我不太清楚。第二部分的外循环必须执行|V|次,我们不能避免它对吗?我可以知道怎么做 O|VE|变成 O|E| ?
    • 是的,外循环一定要执行|V|次,但内部循环的执行取决于与该顶点相邻的边数。这将小于 |E| (不包括完整的图表案例)。为了可视化这一点,请将查找入度视为查看所有边缘。所以复杂度是成正比的,图中边的数量是 O(|E|)
    • 嗨,它应该是 O(|E|) 的推理似乎很好。但正如你所说,外循环确实运行 |V|次。那么,在进行复杂度计算时,我们是否没有考虑到没有发生任何事情的循环?像for i in (0,n): do nothing 的复杂性为n1
    • 另外,复杂度应该是O(|E|)还是O(|E| + |V|),因为我们需要至少访问Adj(G)中的所有顶点行一次?
    【解决方案2】:

    根据http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Graphs.html,第 4.2 节,使用邻接表表示,

    查找节点 u 的前任非常昂贵,需要在 O(n+m) 时间内查看每个节点的每个列表,其中 m 是边的总数。

    因此,在此处使用的符号中,计算节点入度的时间复杂度为O(|V| + |E|)

    但是,这可以通过使用额外空间来减少额外空间。 Wiki 还指出

    添加具有反向边的图的第二个副本可以让我们在 O(d-(u)) 时间内找到 u 的所有前任,其中 d-(u) 是 u 的入度。

    实现此方法的包的一个示例是 Python 包Networkx。从有向图的DiGraph 对象的constructor 可以看出,networkx 跟踪self._succself._pred,它们是表示继承者 的前身的字典每个节点,分别。这允许它有效地计算每个节点的in_degree

    【讨论】:

      【解决方案3】:

      O(|V|+|E|) 是正确答案,因为您访问了 O(|V|) 中的每个顶点,并且每次访问边的一部分,所以总共 O(|E|),通常也是 |E|>>|V|,所以 O(|E|) 也是正确的

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-12
        • 1970-01-01
        • 2022-11-21
        • 1970-01-01
        相关资源
        最近更新 更多