如何制作一个自下而上的合并排序函数来改变输入列表?
How can I make a bottom-up mergesort function that mutates the input list?
我正在尝试按照此维基百科页面上第二个示例(据说是用“类 C 代码”编写的)在 Python 中实现自下而上的合并排序:
https://en.m.wikipedia.org/wiki/Merge_sort
我创建了一个可以运行的脚本,但是当我尝试将它封装在一个函数中时,该函数无法改变输入列表。改变输入列表 是 我想要它做的。
有人知道为什么我的函数 BottomUpMergeSort 不能改变输入列表吗?我知道不推荐嵌套的 while 循环,但第一个脚本似乎工作正常。非常感谢。
我的第一个脚本,它改变了列表 A:
import random
A = list(range(10))
random.shuffle(A)
def Merge(a, b, start, mid, end):
i = start
j = mid
for k in range(start, end):
if i < mid and (j >= end or a[i] <= a[j]):
b[k] = a[i]
i += 1
else:
b[k] = a[j]
j += 1
print(f'A: {A}')
# 'A: [3, 4, 5, 1, 8, 7, 2, 9, 0, 6]'
n = len(A)
B = A[:]
width = 1
while width < n:
start = 0
while start < n:
mid = min(n, start + width)
end = min(n, start + (2 * width))
Merge(A, B, start, mid, end)
start += 2 * width
A = B[:]
width *= 2
print(f'A: {A}')
# 'A: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
我的第二个脚本,它不改变列表 A:
import random
A = list(range(10))
random.shuffle(A)
def Merge(a, b, start, mid, end):
i = start
j = mid
for k in range(start, end):
if i < mid and (j >= end or a[i] <= a[j]):
b[k] = a[i]
i += 1
else:
b[k] = a[j]
j += 1
print(f'A: {A}')
# 'A: [1, 9, 5, 3, 4, 8, 7, 6, 0, 2]'
def BottomUpMergeSort(a):
n = len(a)
b = a[:]
width = 1
while width < n:
start = 0
while start < n:
mid = min(n, start + width)
end = min(n, start + (2 * width))
Merge(a, b, start, mid, end)
start += 2 * width
a = b[:]
width *= 2
BottomUpMergeSort(A)
print(f'A: {A}')
# 'A: [1, 9, 5, 3, 4, 8, 7, 6, 0, 2]'
如您所见,第一个脚本更改了 A,而第二个脚本没有。
问题来自这一行:
a = b[:]
通过在 BottomUpMergeSort
中为 a
赋值,您可以使它成为此函数的局部变量。因此,您分配给此本地 a
的列表只会在您退出该函数时被丢弃。
如果你想让你的原始列表发生变化,就改变它。一个简单的方法是分配给一个切片,像这样:
a[:] = b[:]
这样,原始 a
的所有值都会被替换,但不会创建新对象。
修改后的代码输出:
BottomUpMergeSort(A)
print(A)
# A: [8, 9, 4, 7, 1, 3, 6, 2, 5, 0]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
我正在尝试按照此维基百科页面上第二个示例(据说是用“类 C 代码”编写的)在 Python 中实现自下而上的合并排序:
https://en.m.wikipedia.org/wiki/Merge_sort
我创建了一个可以运行的脚本,但是当我尝试将它封装在一个函数中时,该函数无法改变输入列表。改变输入列表 是 我想要它做的。
有人知道为什么我的函数 BottomUpMergeSort 不能改变输入列表吗?我知道不推荐嵌套的 while 循环,但第一个脚本似乎工作正常。非常感谢。
我的第一个脚本,它改变了列表 A:
import random
A = list(range(10))
random.shuffle(A)
def Merge(a, b, start, mid, end):
i = start
j = mid
for k in range(start, end):
if i < mid and (j >= end or a[i] <= a[j]):
b[k] = a[i]
i += 1
else:
b[k] = a[j]
j += 1
print(f'A: {A}')
# 'A: [3, 4, 5, 1, 8, 7, 2, 9, 0, 6]'
n = len(A)
B = A[:]
width = 1
while width < n:
start = 0
while start < n:
mid = min(n, start + width)
end = min(n, start + (2 * width))
Merge(A, B, start, mid, end)
start += 2 * width
A = B[:]
width *= 2
print(f'A: {A}')
# 'A: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
我的第二个脚本,它不改变列表 A:
import random
A = list(range(10))
random.shuffle(A)
def Merge(a, b, start, mid, end):
i = start
j = mid
for k in range(start, end):
if i < mid and (j >= end or a[i] <= a[j]):
b[k] = a[i]
i += 1
else:
b[k] = a[j]
j += 1
print(f'A: {A}')
# 'A: [1, 9, 5, 3, 4, 8, 7, 6, 0, 2]'
def BottomUpMergeSort(a):
n = len(a)
b = a[:]
width = 1
while width < n:
start = 0
while start < n:
mid = min(n, start + width)
end = min(n, start + (2 * width))
Merge(a, b, start, mid, end)
start += 2 * width
a = b[:]
width *= 2
BottomUpMergeSort(A)
print(f'A: {A}')
# 'A: [1, 9, 5, 3, 4, 8, 7, 6, 0, 2]'
如您所见,第一个脚本更改了 A,而第二个脚本没有。
问题来自这一行:
a = b[:]
通过在 BottomUpMergeSort
中为 a
赋值,您可以使它成为此函数的局部变量。因此,您分配给此本地 a
的列表只会在您退出该函数时被丢弃。
如果你想让你的原始列表发生变化,就改变它。一个简单的方法是分配给一个切片,像这样:
a[:] = b[:]
这样,原始 a
的所有值都会被替换,但不会创建新对象。
修改后的代码输出:
BottomUpMergeSort(A)
print(A)
# A: [8, 9, 4, 7, 1, 3, 6, 2, 5, 0]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]