我正在尝试实施heapsort但是我得到了意想不到的结果。我认为这是由于我不了解Python如何处理变量(我在谈论副作用)。这是代码:
from math import *
def parent(i):
return floor((i+1)/2)-1
def left(i):
return 2*i+1
def right(i):
return 2*i+2
def maxheapify(A, i):
l = left(i)
r = right(i)
if l < len(A) and A[i] < A[l]:
largest = l
else:
largest = i
if r < len(A) and A[largest] < A[r]:
largest = r
if largest != i:
temp = A[i]
A[i] = A[largest]
A[largest] = temp
maxheapify(A, largest)
def buildmaxheap(A):
for i in range(int(floor(len(A)/2)), -1, -1):
maxheapify(A, i)
def heapsort(A):
n = len(A)
buildmaxheap(A)
for k in range(len(A), 0, -1):
temp = A[0]
A[0] = A[k-1]
A[k-1] = temp
C = A[0:k-1]
maxheapify(C, 0)
A = C + A[k-1:n]
print(A)
现在我跑
A = [2, 4, 1, 3, 7, 5, 9]
heapsort(A)
print(A)
我获得两条印刷线(一条来自堆垛内部,显示分拣工作,一条来自最后一幅印刷):
[1, 2, 3, 4, 5, 7, 9]
[1, 7, 5, 3, 4, 2, 9]
显然,我希望它们都是相同的(这意味着排序实际上有效,A在调用heapsort(A)后排序)
所以我得不到的是:
如果A被正确排序(在heapsort(A)的最后一行),为什么离开功能块后这种变化不会持续?
如果这是由于变量A的某些持久性,为什么最终结果不是A的原始值,而是heapsort的中间步骤,这是maxheapify调用的结果?
答案 0 :(得分:2)
在函数开始时,函数内的列表A
与函数外部的列表相同,对一个函数的任何修改都将反映在另一个函数中(它是一个可变对象)。
当您对列表进行分配时,您将新列表对象替换为旧列表对象。这会破坏与外部对象的连接。
您可以分配到A
的切片,而不是将新列表分配给A
,而是原来的对象将会被修改。
A[:] = C + A[k-1:n]
答案 1 :(得分:1)
A[:] = C + A[k-1:n]
这是您所看到的行为的责任。通过将A设置为等于A [0:k-1] + A [k-1:n],您将复制所有A的元素。如果您希望更改在传入的列表中保留,则必须将列表分配给A的所有元素,如下所示:
android:background="@drawable/food_wallpaper"
答案 2 :(得分:1)
以下实现显示了对代码的重写,但在最后一次调用print
函数之后包含了一个替代解决方案。注释掉的行可以替换其正上方的行,或者您可以选择在a
函数末尾返回heap_sort
并重新绑定a
中main
的值而不是函数。
def main():
a = [2, 4, 1, 3, 7, 5, 9]
heap_sort(a)
print(a)
parent = lambda i: (i + 1 >> 1) - 1
left = lambda i: (i << 1) + 1
right = lambda i: i + 1 << 1
def max_heapify(a, i, n):
l = left(i)
r = right(i)
largest = l if l < n and a[i] < a[l] else i
if r < n and a[largest] < a[r]:
largest = r
if largest != i:
a[i], a[largest] = a[largest], a[i]
max_heapify(a, largest, n)
def build_max_heap(a, n):
for i in reversed(range(n + 2 >> 1)):
max_heapify(a, i, n)
def heap_sort(a):
n = len(a)
build_max_heap(a, n)
for k in reversed(range(n)):
a[0], a[k] = a[k], a[0]
c = a[:k]
max_heapify(c, 0, k)
a[:k] = c
# the following would change "a" in this scope only
# a = c + a[k:]
# print(a)
if __name__ == '__main__':
main()