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

时间:2016-02-18 23:18:55

标签: python python-3.x heap correctness minmax-heap

我写了min-max heap,即找到最小值和最大值的常量操作堆。现在我想为我的类创建测试,所以我决定实现一个函数来检查堆是否是最小 - 最大堆。在这里,但我不确定它是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     

请注意,此堆的元素使用类HeapNode表示,这就是我检查self.heap是否仅包含该类对象的原因。甚至级别例如是0,2,4等。此堆的最小值位于self.heap[0]。最大值为max(self.heap[1], self.heap[2])(前提是两者都存在)。如果h.grandparent_index(i)处的节点的祖父母不存在,则None会返回i

我的算法的想法非常简单。我从底部开始,然后检查我是否处于奇怪的水平。如果在一个均匀的水平上,那么我必须确保该元素大于其祖父母。如果我处于奇怪的水平,我必须确保它比祖父母小。

我的算法是否正确?我错过了一些观点吗?如果它是正确的,那么改进它的建议是被广泛接受的。

最终我的实施可能对其他人有用。

修改1

我刚刚注意到我的函数检查偶数(和奇数)级别的元素是否正确相互配置,但是它不会检查是否在self.heap[1]或者self.heap[2]处找到了最大元素self.heap[0]并且最小元素位于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

修改2

我正在根据编辑1和@goCards的答案添加新的更新代码。

public class YourClass
{
    public DateTimeOffset StartDate { get; set; }
    public DateTimeOffset EndDate { get; set; }
}

2 个答案:

答案 0 :(得分:1)

更简单的方法是从堆中删除元素。算法将是这样的:

  • pop min-max并将它们存储在数组中
  • 重复,直到您不再拥有堆中的元素
  • 检查数组是否具有您期望的特征。

在弹出堆中的所有元素后检查生成的数组,应该使得偶数索引严格增加,奇数索引严格减少。如果不是这样,那么堆实现是错误的。

答案 1 :(得分:0)

您的算法缺少一些检查。考虑下面的示例,它不是最小 - 最大堆,而是通过您的测试。考虑5是根。根有另一个分支但是为了简单起见没有显示。

使用您的算法,下面的堆被声明为最小 - 最大堆,但它不满足最小 - 最大堆属性。您的算法也需要检查父节点。

编辑:最小 - 最大堆是一个满足两个属性的二叉树:

1)T具有堆形

2)T是min-max ordered:存储在节点上的值 偶数(奇数)水平小于(大于)或等于 存储在其后代的值(如果有的话) 根位于零级别。

Example

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