【问题标题】:Median Maintenance using heaps使用堆的中值维护
【发布时间】:2017-04-10 15:58:28
【问题描述】:

我正在尝试在 python3 中实现这个问题。从 1 到 10,000 的整数流的答案应该是 1213,我没有得到。我怀疑我的堆实现存在问题,而不是 main() 函数中的实际解决方案。

问题陈述:这个问题的目标是实现“中值维护”算法。文本文件包含从 1 到 10000 的整数列表,未排序;您应该将其视为一串数字,一个接一个到达。设 xi 表示文件的第 i 个编号,第 k 个中值 mk 定义为数字 x1,…,xk 的中值。 (所以,如果 k 是奇数,那么 mk 是 x1,…,xk 中的第 ((k+1)/2) 个最小的数;如果 k 是偶数,那么 mk 是 x1 中的第 (k/2) 个最小的数, …,xk。)

求 10000 个中位数之和,以 10000 为模。

#A = [4, 1, 3, 2, 16, 9, 10, 14, 8 , 7]
max_heap, min_heap = [], []
M, max_size, min_size, data_count, heap = 0, 0, 0, 0, True #True: MAX, False: MIN

def main():
    global M
    data = list(map(int, open('Median.txt').read().splitlines()))
    #data = [2, 1, 3, 4, 5, 6, 7, 8, 9, 10]
    insert(min_heap, data[0], not heap)
    M += data[0]
    insert(max_heap, data[1], heap)
    M += data[1]
    del data[:2]

    for x in data:
        if x < max_heap[0]:
            insert(max_heap, x, heap)
        else:
            insert(min_heap, x, not heap)

        if abs(max_size - min_size) > 1:
            if max_size > min_size:
                y = extract(max_heap, heap)
                insert(min_heap, y, not heap)
            else:
                y = extract(min_heap, not heap)
                insert(max_heap, y, heap)

        if (min_size + max_size)%2 == 0:
            M += max_heap[0]
        else:
            if max_size > min_size:
                M += max_heap[0]
            else:
                M += min_heap[0]
        print(max_heap, min_heap)
    print(len(max_heap), len(min_heap))
    print(M%10000)

def parent(i):
    return i//2

def left(i):
    return 2*i

def right(i):
    return (2*i) + 1

def heapify(A, i, heap):
    l, r = left(i), right(i)
    if heap:
        largest = None
        if l < max_size and A[l] > A[i]:
            largest = l
        else:
            largest = i
        if r < max_size and A[r] > A[largest]:
            largest = r

        if largest != i:
            A[i], A[largest] = A[largest], A[i]
            heapify(A, largest, heap)
    else:
        smallest = None
        if l < min_size and A[l] < A[i]:
            smallest = l
        else:
            smallest = i
        if r < min_size and A[r] < A[smallest]:
            smallest = r

        if smallest != i:
            A[i], A[smallest] = A[smallest], A[i]
            heapify(A, smallest, heap)

def buildHeap(A, heap):
    global max_size, min_size

    if heap:
        max_size = len(A)
    else:
        min_size = len(A)

    for i in reversed(range(len(A)//2)):
        heapify(A, i, heap)

def insert(A, key, heap):
    global max_size, min_size

    if heap:
        if max_size == len(A):
            A.append(key)
        else:
            A[max_size] = key
        max_size += 1
        insertUtils(A, parent(max_size), heap)
    else:
        if min_size == len(A):
            A.append(key)
        else:
            A[min_size] = key
        min_size += 1
        insertUtils(A, parent(min_size), heap)

def insertUtils(A, i, heap):
    heapify(A, i, heap)
    if parent(i) != 0:
        insertUtils(A, parent(i), heap)
    heapify(A, parent(i), heap)

def extract(A, heap): #THE PROBLEM IS HERE I BELIEVE!
    global max_size, min_size

    if heap:
        if max_size < 1:
            raise Exception('Heap underflow!')

        max = A[0]
        A[0] = A[max_size - 1]
        max_size -= 1
        heapify(A, 0, heap)
        return max
    else:
        if min_size < 1:
            raise Exception('Heap underflow!')

        min = A[0]
        A[0] = A[min_size - 1]
        min_size -= 1
        heapify(A, 0, not heap)
        return min

main()
'''
buildHeap(A, heap)
insert(A, 17, heap)
for i in range(11):
    print(A)
    print(extract(A, heap))
insert(A, 18, heap)
print(A)
print(extract(A, heap))
'''

我知道,我问了很多,这是一个很长的代码。但我真的很感激一些帮助!谢谢! :)

【问题讨论】:

  • 你写了什么代码来测试这个?在我看来,维护一个列表,在每个数字之后对其进行排序,并提取第 k/2 或 k/2+1 个数字对我来说似乎很明显将是对小值的有效检查(在这种情况下,10000 是一个小值。
  • @AustinHastings 确实是,但使用堆会提供更好的性能。如果我们使用快速排序之类的方法,我们将获得 O(logn) 时间的堆和 O(nlogn) 时间的排序方法。计数排序可能为 O(n),但堆仍然更好。我的疑问在于我对堆的实现!至于测试,我确实用非常小的数字进行了测试,比如 10,它似乎在那里工作。但它不适用于 10000。:/ 测试代码都在那里,它被注释了!
  • 如果您怀疑代码在extract 中,为什么不只拿您的那部分代码并测试它是否正常工作?如果测试失败,您可以用heapq.heapify 替换您自己对heapify 的定义,以查看是否修复了您的测试,依此类推。 ericlippert.com/2014/03/05/how-to-debug-small-programs 可能会有所帮助。
  • @PaulHankin 哇!为此非常感谢!实际上,我一直在努力提出正确的问题。我尝试过,但有时我的日程安排迫使我在这里在线转储代码以希望得到答案,这太耗时了。我会尝试自己调试它,并研究'heapq'!再次感谢!

标签: python algorithm data-structures heap


【解决方案1】:

启动

一开始似乎就有一个问题:

insert(min_heap, data[0], not heap)
M += data[0]
insert(max_heap, data[1], heap)
M += data[1]

此代码假定前两项以降序出现。

如果前两项按升序排列,那么您的堆将被从前初始化,并且第二个计算的中位数也不正确。

索引

主要问题似乎是从零开始的索引(在数组查找中使用)和从一开始的索引(在父/左/右函数中使用)之间的混淆。

将所有内容更改为从零开始的索引应该会有所帮助。 堆函数变为:

def parent(i):
    return (i+1)//2-1

def left(i):
    return 2*(i+1)-1

def right(i):
    return (2*(i+1))

def insertUtils(A, i, heap):
    heapify(A, i, heap)
    if parent(i) >= 0:
        insertUtils(A, parent(i), heap)

def insert(A, key, heap):
    global max_size, min_size

    if heap:
        if max_size == len(A):
            A.append(key)
        else:
            A[max_size] = key
        max_size += 1
        insertUtils(A, parent(max_size-1), heap)
    else:
        if min_size == len(A):
            A.append(key)
        else:
            A[min_size] = key
        min_size += 1
        insertUtils(A, parent(min_size-1), heap)

【讨论】:

  • 哦,对不起,我应该提到的。确实如此,已知前两个整数是按降序排列的。代码运行后,我将对其进行更改以适应更一般的情况。
  • 我添加了一个额外问题的描述
猜你喜欢
  • 2018-05-19
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 2011-12-02
  • 2016-11-28
相关资源
最近更新 更多