【问题标题】:Building MIN-HEAP in Python在 Python 中构建 MIN-HEAP
【发布时间】:2016-01-23 14:31:51
【问题描述】:

我必须在 Python 中构建一个完整的 MIN-HEAP 实现,而不使用内置的堆函数。

所以我有了父、左子和右子的定义,其中考虑了从 0 开始的 python 编号列表元素:

from random import randint
import math 

def parent(i):
    x = int(l.index(l[i])) #########3
    y = int(math.floor(x/2))
    return y-1  

def lchild(i):
    x = int(l.index(l[i]))
    y = int(math.floor(x*2))
    return y-1

def rchild(i):
    x = int(l.index(l[i]))
    y = int(math.floor(x*2 + 1))
    return y-1

然后我有一部分代码为我生成(伪)随机列表到列表中l

l = []
dl = int(input)

for i in range (0, dl):
    x = int(randint(1,100)) 
    l.append(x)             

直到此时一切正常。然后我有一个函数 bkop 用于将表 l 变成最小堆。

def bkop(l):
        j = 0
        for i in range(0, len(l)):
                if int(l[i]) < int(parent(l[i])): #########2
                        l[i], l[parent(i)] = l[parent(i)], l[i]
                        j = j+1
                if j != 0:
                        bkop(l)

那我想运行一个程序,看看结果:

bkop(l) #########1
print l

程序崩溃,错误list index out of range指向我用#########标记的3行。我大约一个月前开始写这篇文章,我很确定,那位父母、lchild 和 rchild 当时都在工作。你知道,怎么了?

编辑1: 好的,所以我已经修复了 parent/lchild/rchild 定义。我检查过,它们返回正确的值。代码如下:

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

def lchild(i):
    x = i + 1
    y = x*2
    return y-1

def rchild(i):
    x = i + 1
    y = x*2 + 1
    return y-1

生成随机列表的函数几乎完好无损。然后我有这个 bkop 函数(从 l 列表中生成一个最小堆)。我故意在前后使用 print 来确定它是否有效......但它没有。它两次返回相同的列表,没有编译错误或任何东西。知道如何解决吗?

print(l)
def bkop(l): 
        j = 0
        for i in range(0, len(l)):
                if l[i] < parent(i):
                        l[i], l[parent(i)] = l[parent(i)], l[i]
                        j = j+1
                if j != 0:
                        bkop(l)
bkop(l)
print l

编辑2: 好的,我已经按照您的建议修复了 bkop

print bkop(l)
def bkop(l):
        j = 0
        for i in range(1, len(l)):
                if l[i] < l[parent(i)]:
                        l[i], l[parent(i)] = l[parent(i)], l[i]
                        j = j+1
                if j != 0:
                        bkop(l)
bkop(l)
print bkop(l)

但是当我运行它时,我首先得到一个随机生成的表(我应该这样做),而不是一个最小堆表,我得到 None 值,如下所示:

[34, 9, 94, 69, 77, 33, 56]
None

有什么想法吗?也许我应该换一种方式,不是将 l[i] 与父母进行比较,而是将 l[i] 与左右孩子进行比较?

【问题讨论】:

    标签: python min-heap


    【解决方案1】:

    所以我在 Wombatz 的帮助下完成了整个工作(非常感谢!)。这是未来用户的工作代码:

    from random import randint
    
    def parent(i):
        x = i + 1
        y = x//2
        return y-1
    
    def lchild(i):
        x = i + 1
        y = x*2
        return y-1
    
    def rchild(i):
        x = i + 1
        y = x*2 + 1
        return y-1
    
    
    
    l = []
    dl = int(input())
    
    for i in range (0, dl):
        x = int(randint(1,100)) 
        l.append(x) 
    
    print l
    def bkop(l):
            j = 0
            for i in range(1, len(l)):
                    if l[i] < l[parent(i)]:
                            l[i], l[parent(i)] = l[parent(i)], l[i]
                            j = j+1
                    if j != 0:
                            bkop(l)
    bkop(l)
    print l
    

    运行时,我输入了 13 作为列表长度的输入,我得到了结果:

    13
    [30, 62, 9, 100, 75, 73, 57, 82, 2, 76, 2, 50, 41] #before heapify
    [2, 2, 30, 62, 9, 41, 57, 100, 82, 76, 75, 73, 50] #after heapify
    

    【讨论】:

      【解决方案2】:

      一开始:你的parentlchildrchild函数有问题:

      • l[index] 获取给定索引的值。

      • l.index(...) 获取给定值的索引。

      您正在尝试获取特定索引处的值的索引。这就像x + 1 - 1。如果您的项目是唯一的,那么计算的索引将始终与您开始使用的索引相同。当有重复时,您的函数将计算该索引处第一次出现的值的父、左和右子。 那可能不是你想要的。所以将x 设置为i 或完全删除x

      实际问题如下:

      您的 parentlchildrchild 函数旨在在 index 上工作,但您将索引 i 处的 l 的值传递给函数:parent(l[i])

      由于列表中的值可能远高于可能的索引范围,您会得到列表索引超出范围。您可能想直接传递索引。

      此外:

      parentlchildrchild 返回不正确的值。在没有其他东西的情况下测试这些功能!

      我假设结果应该是这样的:

      • parent(1) == parent(2) == 0
      • lchild(0) == 1
      • rchild(0) == 2

      您的定义返回不同的值。

      一些小事:

      • 所有这些随机的int 强制转换都是无用的。将 int 转换为 int 没有任何作用。唯一真正需要强制转换的行是:``dl = int(input)`
      • int(math.floor(x/2))。改用整数除法x // 2
      • int(math.floor(x*2))。整数乘以 2 是整数。无需floor

      编辑 您的 bkop 函数有两个问题。

      • l[i] &lt; parent(i) 您将值与索引进行比较。我认为您希望将 i 的值与其父值而不是父索引合并。
      • 对于i == 0,您将索引0 处的值与parent(0) == -1 处的值进行比较。这包含了列表,可能不是您想要的。由于索引 0 没有父级,因此您不应尝试将其与其父级进行比较。

      编辑2

      bkop 不返回列表,而是就地修改它。最后只是print(l)。你会看到原来的列表被修改了。

      【讨论】:

      • 感谢您的提示。我已经清理了 parent/lchild/rchild 定义并检查了 - 它们运行良好(返回表中的索引)但我的 bkop 函数仍然存在问题。你能看看我原来帖子的EDIT1吗?
      • 谢谢,我已经忽略了这些错误。但我仍然没有让它工作。你能看看 EDIT 2 吗?
      • @Edit 2 - 没用。我仍然希望没有返回
      • 不需要返回任何东西。结果在l 中。只需致电bkop(l),无需返回或分配。 l 是一个堆。
      • 我确实调用了 bkop(l) 而没有返回或分配。我在循环完成后调用 print(l) ,它打印 None: [44, 59, 42, 71, 61, 96] #before the bkop None #after bkop
      猜你喜欢
      • 1970-01-01
      • 2018-01-10
      • 2018-04-15
      • 1970-01-01
      • 1970-01-01
      • 2011-09-29
      • 2019-12-17
      • 1970-01-01
      • 2011-07-27
      相关资源
      最近更新 更多