简体   繁体   English

检查堆是否是最小-最大堆

[英]Check if an heap is a min-max heap

I've written a min-max heap , ie an heap where finding the minimum and the maximum are constant operations. 我编写了一个min-max堆 ,即查找最小值和最大值的堆是常量操作。 Now I want to create tests for my class, so I decided to implement a function that checks if a heap is a min-max-heap. 现在,我想为类创建测试,因此我决定实现一个检查堆是否为min-max-heap的函数。 Here it is, but I'm not sure it's 100% correct. 在这里,但我不确定它是否100%正确。

def is_min_max_heap(h):
    if not isinstance(h, MinMaxHeap):
        return False
    if h.heap:
        for item in h.heap:
            if not isinstance(item, HeapNode):
                return False
        for i, item in reversed(list(enumerate(h.heap))):
            g = h.grandparent_index(i)
            if g is not None:
                if h.is_on_even_level(i):
                    if h.heap[g] > item:
                        return False
                else:
                    if h.heap[g] < item:
                        return False            
    return True     

Note that elements of this heap are represented with the class HeapNode , and that's why I am checking if self.heap only contains objects of that class. 请注意,该堆的元素由类HeapNode表示,这就是为什么我要检查self.heap仅包含该类的对象的原因。 Even levels are for example 0, 2, 4, etc. The minimum of this heap is found at self.heap[0] . 偶数级别例如为self.heap[0]等。此堆的最小值位于self.heap[0] The maximum is max(self.heap[1], self.heap[2]) (provided that both exist). 最大值为max(self.heap[1], self.heap[2]) (假设两者都存在)。 h.grandparent_index(i) returns None if the grandparent of the node at i does not exist. 如果i节点的祖父母不存在,则h.grandparent_index(i)返回None

The idea of my algorithm is very simple. 我算法的想法很简单。 I start from the bottom, and I check if I'm on an even of odd level. 我从底部开始,然后检查我是否处于奇数水平。 If on an even level, then I must make sure that the element is greater than its grandparent. 如果是偶数级,那么我必须确保该元素大于其祖父母。 If I'm on a odd level, I must make sure it's smaller than its grandparent. 如果我的水平很奇怪,我必须确保它比其祖父母小。

Is my algorithm correct? 我的算法正确吗? Am I missing some points? 我是否缺少一些要点? If it's correct, suggestions to improve it are well-accepted. 如果是正确的话,就可以接受改进建议。

Eventually my implementation might be useful for someone else. 最终,我的实现可能对其他人有用。

Edit 1 编辑1

I've just noticed that my function checks if the elements in the even (and respectively odd) levels are correctly disposed to each other, but it does not check if the maximum element is found either at self.heap[1] or self.heap[2] and that the minimum element is at self.heap[0] . 我刚刚注意到我的函数检查偶数(和奇数)级中的元素是否正确相互放置,但不检查是否在self.heap[1]self.heap[2]找到最大元素self.heap[2]并且最小元素在self.heap[0]

Edit 2 编辑2

I'm adding the new updated code according to edit 1 and to the answer of @goCards. 我要根据编辑1和@goCards的答案添加新的更新代码。

def is_min_max_heap(h) -> bool:
    """Returns `True` if `h` is a valid `MinMaxHeap` object. `False` otherwise."""
    if not isinstance(h, MinMaxHeap):
        return False

    if h.heap:
        for item in h.heap:
            if not isinstance(item, HeapNode):
                return False

        if h.size() == 1:
            return True

        if h.size() == 2:
            return max(h.heap) == h.heap[1] and min(h.heap) == h.heap[0]

        if h.size() >= 3:
            if (h.heap[0] != min(h.heap) or
                (h.heap[1] != max(h.heap) and
                 h.heap[2] != max(h.heap))):
                return False

        for i, item in reversed(list(enumerate(h.heap))):
            p = h.parent_index(i)

            if p != -1:
                if h.is_on_even_level(i):
                    if h.heap[p] < item:
                        return False
                else:
                    if h.heap[p] > item:
                        return False

            g = h.grandparent_index(i)
            if g != -1:
                if h.is_on_even_level(i):
                    if h.heap[g] > item:
                        return False
                else:
                    if h.heap[g] < item:
                        return False
    return True

A simpler way is to remove elements from the heap. 一种更简单的方法是从堆中删除元素。 The algorithm would be something like this: 该算法将是这样的:

  • pop min-max and store them in an array 弹出最小-最大并将它们存储在数组中
  • repeat until you no longer have elements in the heap 重复直到您在堆中不再有元素
  • check if the array have the characteristics that you expect. 检查数组是否具有您期望的特征。

Checking the array you generate after you pop all elements in the heap, you should have even indices to be strictly increasing and odd indices strictly decreasing. 弹出堆中的所有元素后,检查生成的数组,您应该使偶数索引严格增加而奇数索引严格减少。 If that is not true, your heap implementation is wrong. 如果不正确,则您的堆实现是错误的。

Your algorithm is missing some checks. 您的算法缺少一些检查。 Consider the example below that is not a min-max heap but passes your test. 考虑下面的示例,它不是最小-最大堆,但可以通过测试。 Consider 5 to be the root. 以5为根。 The root has another branch but it is not shown for simplicity. 根有另一个分支,但为简单起见未显示。

Using your algorithm, the heap below is declared as a min-max heap, but it does not satisfy min-max heap properties. 使用您的算法,下面的堆被声明为最小-最大堆,但它不满足最小-最大堆属性。 Your algorithm needs to check the parent node as well. 您的算法也需要检查父节点。

EDIT: A min-max heap is a binary tree that satisfies two properties: 编辑:最小-最大堆是满足两个属性的二叉树:

1) T has the heap-shape 1)T呈堆状

2) T is min-max ordered: values stored at nodes on even (odd) levels are smaller (greater) than or equal to the values stored at their descendants (if any) where the root is at level zero. 2)T是最小-最大有序的:存储在偶数(奇数)级上的节点的值小于(大于)等于或等于存储在其根为零级的后代(如果有)中的值。

例

for i, item in reversed(list(enumerate(h.heap))):
    g = h.grandparent_index(i)
    p = h.parent_index(i)
    if g is not None and p is not None:
        if h.is_on_even_level(i):
            if item > h.heap[g]: pass #grandparent should be smallest in its subtree
            else: return False
            if item < h.heap[p]: pass #parent should be greatest in its subtree
            else: return False
        else: #odd level
            if item < h.heap[g]: pass #grandparent should be greatest in its subtree
            else: return False
            if item > h.heap[p]: pass #parent should be smallest in its subtree
            else: return False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM