MergeSort vs.抗锯齿规则

时间:2019-06-27 18:54:36

标签: fortran language-lawyer mergesort array-merge fortran95

我在Fortran中实现了MergeSort算法的以下实现。

我的问题是关于call merge(work(1 : half), A(half + 1:), A)。 显然,我有重叠的内存,但是只要看一下merge中的代码,只要输入数组已排序,这应该没问题。 (假设它们仍然存在。)

另一方面,Fortran编译器可能会假定非别名内存, 所以我一直认为“不要这样做”。

我现在有两个问题:

  1. 我何时merge子例程遇到问题。
  2. 如果我不能像这样实现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参数,因为以后它与重叠内存一起使用。

1 个答案:

答案 0 :(得分:0)

在调用merge中使用别名是错误的。

使用

call merge(work(1 : half), A(half + 1:), A)

伪参数BA(half+1:)关联,伪参数CA关联,这是可以理解的重叠。

这种别​​名意味着可能无法定义B的元素(意图还要求),并且可能不会定义C的最后几个元素。

但是,如果我们查看merge中的主循环,就会发现C的每个元素通常都出现在类似于C(k)=...的语句中:我们希望其中至少有一个里面的条件是真实的。因此,这是无效的。

请注意:C(k)=B(j)这样的语句即使结果C(k)不变,也是非法定义。

幸运的是,也许有一种简单的方法可以创建一个临时数组来避免混叠:为伪参数B提供value属性。您甚至可以对A进行同样的操作,然后删除工作区数组。