【问题标题】:Basic DFS space usage基本 DFS 空间使用情况
【发布时间】:2016-08-20 16:42:39
【问题描述】:

我有一个关于空间使用的基本问题,我以 DFS 为例。我不确定这几个实现中的空间使用是否相同,或者是否有几个实际上不同。我对空间使用的解释与函数分配的内容直接相关。 谁能帮我验证我做的这几个例子的空间使用情况?这是关于空间复杂度的问题,而不是时间+功能的问题

示例 1:我们分配一个存储 N 个节点的字典。我很肯定这个分配了 O(N) 空间。

class Node:
    def __init__(self, children):
        self.children = children

    def getChildren(self):
        return self.children

def dfs(start):
    stack = []
    visited = {}
    stack.append(start)
    while(len(stack) > 0):
        node = stack.pop()
        if(node not in visited):
            visited[node] = True
            for child in node.getChildren():
                stack.append(child)

示例 2:我们没有在 dfs 函数中分配任何东西,而是给了我们一个标志来在节点上设置。我们没有在 dfs 函数中分配任何东西,所以它是 O(1) 空间使用量。

class Node:
    def __init__(self, children):
        self.children = children
        self.visited = False

    def getChildren(self):
        return self.children

    def getVisited(self):
        return self.visited

    def setVisited(self, visit):
        self.visited = visit

def dfs(start):
        stack = []
        stack.append(start)
        while(len(stack) > 0):
            node = stack.pop()
            if(!node.getVisited()):
                node.setVisited(True)
                for child in node.getChildren():
                    stack.append(child)

示例 3:我们有一个可以操作的对象 Node,但前面没有标志属性。 DFS 在每个节点上手动创建一个标志,从而分配 O(N) 空间。

class Node:
    def __init__(self, children):
        self.children = children

    def getChildren(self):
        return self.children

def dfs(start):
    stack = []
    stack.append(start)
    while(len(stack) > 0):
        node = stack.pop()
        if(node.visited is not None):
            node.visited = True
            for child in node.getChildren():
                stack.append(child)

【问题讨论】:

  • 好吧,这不是问题的重点。谢谢你至少指出这一点......
  • 我明白了,但是您提供的代码中有许多语法错误,这让我觉得这不是您使用的实际代码...
  • 没有实际代码。这是一个空间使用问题。
  • ...您应该stack.insert(0, x)stack.append(x)stack.pop(0) 更改为stack.pop()。这不会改变您的代码的功能,但将堆栈中插入/弹出的复杂性从 O(N^2) 更改为 O(N)。
  • @Bakuriu 谢谢我会改变它,但这又不是问题的重点。我会在问题中澄清这一点。

标签: python performance memory


【解决方案1】:

Space complexity 不是由 where 分配空间决定的,而是由 多少 需要多少空间(内存)来保存与数字相关的给定数据结构由算法处理的对象。

在您的示例中,所有数据结构都需要 O(N) 空间(N = 节点数)

【讨论】:

  • 好吧,这是有道理的,我忘记了为每个节点附加的堆栈。我知道它可以简化为 O(N),但确切的复杂度是多少?第一个会是唯一一个 O(2N) 的吗?它必须将节点存储在字典和堆栈中。
  • @Taztingo 这取决于您如何准确测量空间复杂度。例如,python 字典是 hashmap,通常 hashmap 必须使用比其元素实际占用的空间更多的空间,以提高查找效率,因此将元素存储在堆栈和 dict 中将消耗超过2N 内存.
  • 按照惯例,Big O 表示法描述了函数的增长率的上限(最坏情况),而不是绝对值。我们还说一个函数是 O(x) “直到常数因子”或 |f(x)| <= c|g(x)|, c > 0 。换句话说,我们假设N >> c,因此 O(2N) 与 O(N) 相同,也就是说,当 N 达到“足够大的数字”时,增长率由 N 决定,而不是由2.
  • 注意,两种实现完全有可能使用非常不同的内存量,但它们的增长率仍然是 O(N)。虽然理论上它在实践中并不重要,但它可能非常好......为了简洁地解释这一点,您可以说您的示例都使用空间复杂度 O(N) 直到常数因子,但是通过仔细观察,您会发现示例 2 是最有效的,因为它具有恒定因子 c = 1,而其他示例至少具有恒定因子 2,因此使用更多空间。
猜你喜欢
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-19
  • 2021-10-07
  • 2015-07-10
  • 2017-08-16
相关资源
最近更新 更多