这是CLSR书中我要遵循的算法:
这是我在Python中的代码:
#merge sort
def merge_sort(A, p, q, r):
n_prime = q - p + 1
n_second = r - q
L = [x for x in range(n_prime + 1)]
R = [y for y in range(n_second + 1)]
for i in range(n_prime):
L[i] = A[p + i - 1]
for j in range(n_second):
R[j] = A[q + j]
L[n_prime] = float("inf")
R[n_second] = float("inf")
i = 0
j = 0
for k in range(p, r):
if L[i] <= R[i]:
A[k] = L[i]
i += 1
elif A[k] = R[j]:
j += 1
return A
A = [2, 4, 5, 7, 8, 6, 9, 1]
print(merge_sort(A, 0, 3, 7))
其余所有代码都可以正常工作。根据VSCode Debugger的介绍,L和R的创建没有任何障碍,但是在最后一个循环中,存在一个问题:它从不枚举j。 elif
条件永远不会满足,因此它永远不会到达第二个列表。
我的算法实现有什么问题?我敢打赌这与本书的数组从1开始但python list的索引从0开始有关。为什么他们这样做呢?在翻译算法时,我应该遵循一条一般规则吗?
谢谢。
答案 0 :(得分:1)
可能应该是elif A [k] == R [j](两个“ =”符号),您写的是一个赋值。
我认为我发现了问题:应该是L [i] <= R [ j ],而不是R [i]。
为我运行的代码:
#merge sort
def merge_sort(A, p, q, r):
n_prime = q - p + 1
n_second = r - q
L = [x for x in range(n_prime + 1)]
R = [y for y in range(n_second + 1)]
for i in range(n_prime):
L[i] = A[p + i - 1]
for j in range(n_second):
R[j] = A[q + j]
L[n_prime] = float("inf")
R[n_second] = float("inf")
i = 0
j = 0
print("L:", len(L), ", R:", len(R))
for k in range(p, r):
if L[i] <= R[j]:
print("if", i)
print(L[i])
print(R[i])
A[k] = L[i]
i += 1
else:
print("else", k, j, A[k], R[j])
A[k] = R[j]
j += 1
return A
}
答案 1 :(得分:0)
您写道:
elif A[k] = R[j]:
j += 1
当算法说:
else:
A[k] = R[j]
j += 1
此处的拼写错误将导致“数组索引超出范围”错误:
if L[i] <= R[i]:
您可能是说:
if L[i] <= R[j]:
我的算法实现有什么问题?
不完整;您仅实现了合并过程,而没有实现整个mergesort算法。因此,运行具有上述更正的代码将输出部分排序的列表。
答案 2 :(得分:0)
这是我上周第二次看到CLSR版本。我不喜欢使用“前哨值”(无穷大)来避免对索引进行边界检查的想法,因为它不需要太多代码,并且如果A []是整数数组并且已经存在,则将不起作用包括最大值。必须修改代码,因为数组的CLSR索引范围是1到n,而不是0到n-1。
这里是示例代码,该代码在每次移动后进行边界检查,如果到达子运行的末尾,它将追加剩余的子运行的其余部分。同样,输入参数是beg(运行的第一个索引)和结束(1 +运行的最后一个索引),类似于C ++ std :: vector :: begin()和std :: vector :: end(),这是典型的合并排序的用法。
def mergesort(a,beg,end):
if (end-beg) > 1:
mid=(beg+end)//2
mergesort(a,beg,mid)
mergesort(a,mid,end)
merge(a,beg,mid,end)
def merge(a,beg,mid,end):
left = a[beg:mid]
right = a[mid:end]
i = 0
j = 0
k = beg
while True:
if left[i] <= right[j]:
a[k] = left[i]
i += 1
k += 1
if(i < len(left)):
continue
a[k:end] = right[j:len(right)]
break
else:
a[k] = right[j]
j += 1
k += 1
if(j < len(right)):
continue
a[k:end] = left[i:len(left)]
break
....
mergesort(a,0,len(a)) #call to merge sort to sort a[]
这不是最佳实现。最好一次分配一个工作数组,而不是在每次合并时分配两个工作子数组,并在每次递归级别上交替合并方向(或者如果每次进行自下而上的合并排序,则更好) ),以避免复制数据。