我在Fortran中实现了MergeSort算法的以下实现。
我的问题是关于call merge(work(1 : half), A(half + 1:), A)
。
显然,我有重叠的内存,但是只要看一下merge
中的代码,只要输入数组已排序,这应该没问题。 (假设它们仍然存在。)
另一方面,Fortran编译器可能会假定非别名内存, 所以我一直认为“不要这样做”。
我现在有两个问题:
merge
子例程遇到问题。MergeSort
,如何在不创建临时数组的情况下做到这一点。!> Merge sorted arrays A and B into C while preversing order.
subroutine merge(A, B, C)
implicit none
integer, intent(in) :: A(:), B(:)
integer, intent(inout) :: C(:)
integer :: i, j, k
if (size(A) + size(B) > size(C)) abort
i = 1; j = 1
do k = 1, size(C)
if (i <= size(A) .and. j <= size(B)) then
if (A(i) <= B(j)) then
C(k) = A(i)
i = i + 1
else
C(k) = B(j)
j = j + 1
end if
else if (i <= size(A)) then
C(k) = A(i)
i = i + 1
else if (j <= size(B)) then
C(k) = B(j)
j = j + 1
end if
end do
end subroutine merge
recursive subroutine MergeSort(A, work)
implicit none
integer, intent(inout) :: A(:)
integer, intent(inout) :: work(:)
integer :: half
half = (size(A) + 1) / 2
if (size(A) < 2) then
continue
else if (size(A) == 2) then
call naive_sort(A)
else
call MergeSort(A( : half), work)
call MergeSort(A(half + 1 :), work)
if (A(half) > A(half + 1)) then
work(1 : half) = A(1 : half)
! TODO: Non aliasing rule.
call merge(work(1 : half), A(half + 1:), A)
endif
end if
end subroutine MergeSort
PS:您可能已经注意到,merge
子例程中的数组C被声明为inout
参数,因为以后它与重叠内存一起使用。
答案 0 :(得分:0)
在调用merge
中使用别名是错误的。
使用
call merge(work(1 : half), A(half + 1:), A)
伪参数B
与A(half+1:)
关联,伪参数C
与A
关联,这是可以理解的重叠。
这种别名意味着可能无法定义B
的元素(意图还要求),并且可能不会定义C
的最后几个元素。
但是,如果我们查看merge
中的主循环,就会发现C
的每个元素通常都出现在类似于C(k)=...
的语句中:我们希望其中至少有一个里面的条件是真实的。因此,这是无效的。
请注意:C(k)=B(j)
这样的语句即使结果C(k)
不变,也是非法定义。
幸运的是,也许有一种简单的方法可以创建一个临时数组来避免混叠:为伪参数B
提供value
属性。您甚至可以对A
进行同样的操作,然后删除工作区数组。