微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 heapq.heapify 这么快?

如何解决为什么 heapq.heapify 这么快?

我尝试重新实现 heapify 方法,以便使用 _siftup_siftdown 更新或删除堆中的任何节点并保持 O(log(n)) 的时间复杂度。>

我做了一些努力来优化我的代码,但与 heapq.heapify (就所用的总时间而言)相比,它们被证明更糟。所以我决定研究source code。并将复制的代码与模块代码进行比较。

# heap invariant.
def _siftdown(heap,startpos,pos):
    newitem = heap[pos]
    # Follow the path to the root,moving parents down until finding a place
    # newitem fits.
    while pos > startpos:
        parentpos = (pos - 1) >> 1
        parent = heap[parentpos]
        if newitem < parent:
            heap[pos] = parent
            pos = parentpos
            continue
        break
    heap[pos] = newitem

def _siftup(heap,pos):
    endpos = len(heap)
    startpos = pos
    newitem = heap[pos]
    # Bubble up the smaller child until hitting a leaf.
    childpos = 2*pos + 1    # leftmost child position
    while childpos < endpos:
        # Set childpos to index of smaller child.
        rightpos = childpos + 1
        if rightpos < endpos and not heap[childpos] < heap[rightpos]:
            childpos = rightpos
        # Move the smaller child up.
        heap[pos] = heap[childpos]
        pos = childpos
        childpos = 2*pos + 1
    # The leaf at pos is empty Now.  Put newitem there,and bubble it up
    # to its final resting place (by sifting its parents down).
    heap[pos] = newitem
    _siftdown(heap,pos)


def heapify(x):
    """Transform list into a heap,in-place,in O(len(x)) time."""
    n = len(x)
    # Transform bottom-up.  The largest index there's any point to looking at
    # is the largest with a child index in-range,so must have 2*i + 1 < n,# or i < (n-1)/2.  If n is even = 2*j,this is (2*j-1)/2 = j-1/2 so
    # j-1 is the largest,which is n//2 - 1.  If n is odd = 2*j+1,this is
    # (2*j+1-1)/2 = j so j-1 is the largest,and that's again n//2-1.
    for i in reversed(range(n//2)):
        _siftup(x,i)

a = list(reversed(range(1000000)))
b = a.copy()

import heapq

import time

cp1 = time.time()
heapq.heapify(a)
cp2 = time.time()
heapify(b)
cp3 = time.time()

print(a == b)
print(cp3 - cp2,cp2 - cp1)


而且我发现总是 cp3 - cp2 >= cp2 - cp1 并且不一样,heapifyheapq.heaify 花费的时间更长,即使两者相同。 在某些情况下,heapify 用了 3 秒而 heapq.heapify 用了 0.1 秒

heapq.heapfy 模块的执行速度比相同的 heapify 更快,它们仅通过导入有所不同。

请告诉我原因,如果我犯了一些愚蠢的错误,我很抱歉。

解决方法

public class RotateObjects : MonoBehaviour { [SerializeField] Button rotateButton; // Start is called before the first frame update void Start() { rotateButton.onClick.RemoveAllListeners(); rotateButton.onClick.AddListener(RotateClockwise); } void RotateClockwise() { float newRotation = (360 / transform.childCount); transform.Rotate(new Vector3(0,newRotation,0)); } } 模块中的 heapify 实际上是一个内置函数:

heapq

>>> import heapq >>> heapq <module 'heapq' from 'python3.9/heapq.py'> >>> heapq.heapify <built-in function heapify> 说:

关于模块 help(heapq.heapify)... 中内置函数 heapify 的帮助

所以它实际上是导入内置模块 _heapq 并因此运行 C 代码,而不是 Python。

如果进一步滚动 _heapq 代码,您将看到 this

heapq.py

这将使用其 C 实现覆盖 # If available,use C implementation try: from _heapq import * except ImportError: pass 等函数。例如,heapifyhere

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。