【问题标题】:how is the time complexity of dict.clear() is O(1) in python?python中dict.clear()的时间复杂度是O(1)如何?
【发布时间】:2018-11-22 20:44:04
【问题描述】:

根据https://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt,dict.clear()的时间复杂度是O(1)。

据我所知,dict.clear() 与分配 dict = {} 不同,因为 dict.clear() 对同一个 dict 进行更改,而 dict = {} 创建一个新的 dict。

现在如果 dict.clear() 正在清除同一个 dict 对象,那么它如何在 O(1) 中完成它。

【问题讨论】:

  • 也许通过破坏内部数据结构并让垃圾收集器完成肮脏的非 O(1) 工作。它不是循环遍历元素并一一删除。
  • PyDict_Clear 的实现可以在here 找到。
  • for (i = 0; i < n; i++) Py_CLEAR(oldvalues[i]); 在我看来不像O(1)...看来我错了
  • 有趣的是,这里没有讨论 clear 的复杂性wiki.python.org/moin/TimeComplexity

标签: python dictionary time-complexity python-internals


【解决方案1】:

为什么它被称为 O(1) 的一些理由:

clear() 方法实际上只是将内部字典结构分配给新的空值(如 source 所示)。看似 O(n) 的部分是递减引用计数和其他 GC 相关内容的结果。但这纯粹是 CPython 使用的 GC 方法的一个功能(即引用计数);您可以设想不同的方法,这些方法不需要像这样显式清理,或者清理将在更晚发生(甚至被摊销)。由于理想情况下clear() 的时间复杂度不应该依赖于底层的 GC 方法,因此所有与 GC 相关的部分都被省略,使其成为“O(1)”。 IMO 这主要是一个定义性论点,而不是其他任何东西,但这至少是一些理由。

【讨论】:

    【解决方案2】:

    我首先认为dict.clear 只是执行了一些引用减少以让垃圾收集器完成肮脏的非 O(1) 工作,但查看source code(感谢 timgeb 提供链接)它没有好像是这样的:

       oldvalues = mp->ma_values;
        if (oldvalues == empty_values)
            return;
        /* Empty the dict... */
        dictkeys_incref(Py_EMPTY_KEYS);
        mp->ma_keys = Py_EMPTY_KEYS;
        mp->ma_values = empty_values;
        mp->ma_used = 0;
        mp->ma_version_tag = DICT_NEXT_VERSION();
        /* ...then clear the keys and values */
        if (oldvalues != NULL) {
            n = oldkeys->dk_nentries;
            for (i = 0; i < n; i++)
                Py_CLEAR(oldvalues[i]);
    

    我看到的是,如果字典有值,则执行循环以减少对这些值的引用并将指针设置为 NULL。所以似乎是O(n) 而不是O(1),因为它取决于值的数量。

    当你分配给一个像d = {} 这样的新字典时,这是O(1),但是当不再引用时,垃圾收集器必须删除旧对象。分配时可能不正确,但这会发生,除非 python 突然退出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-09
      • 2017-09-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 2020-08-18
      • 2016-04-21
      • 1970-01-01
      相关资源
      最近更新 更多