首页 > 解决方案 > 如何使用fortran代码对二维数组中的距离进行排序?

问题描述

我想对距离进行排序。例如 r(1,3)< r(1,2) 那么 r(1,3) 应该排在第一位。dist.txt像这样的输入文件

1,2,3.5
1,3,0.5
1,4,4.7
1,5,4,5  

的输出文件sort.txt应该是这样的

1, 3, 0.5
1,2, 3.5
1,5, 4.5
1,4,4.7

这里第一列是i第二列j然后第三列是r(i,j)。所以在这里我用fortran写了一段代码,它可以对二维数组进行排序。但是该代码有问题,如果有人可以修复的话。我会很高兴的。

 program sort
  implicit none
  character CN*8,O*7
  integer i,m,k,j
  integer n,nmax,ind,num
  integer L
  parameter (n=3,m=n**2-n)
  double precision xbox,rq
  parameter (nmax=3091,nconf=1)
  double precision atom(nmax),id(nmax),ox(nmax),oy(nmax),oz(nmax)
  double precision xij,yij,zij,rij,t
  double precision a(n,n)
  double precision r(n,n)
  open(unit=10,status='unknown',file='a.gro')

   do i=1,n
     read(10,'(A8,A7,1i5,3f8.3)')CN,O,num,ox(i),oy(i),oz(i)
   enddo
     read(10,*)xbox        ! read the xbox for PBC

   t=0.0d0
  open(unit=3,file='dist.txt')
  open(unit=4,file='2d_1d_dist.txt')
  open(unit=5,file='sort.txt')
   do i=1,n
    do j=1,n
   if(i .ne. j) then
   xij=ox(i)-ox(j)
   yij=oy(i)-oy(j)
   zij=oz(i)-oz(j)
   xij=xij - nint(xij/xbox)*xbox
   yij=yij - nint(yij/xbox)*xbox
   zij=zij - nint(zij/xbox)*xbox
   r(i,j)=dsqrt(xij**2 + yij**2 + zij**2) !distance calculation
    write(3,'(i3,2x,i3,4x,f17.15)') i,j, r(i,j)
    endif
    enddo
    enddo


  t=0.0d0
  do i = 1,m-2
  do j = i+1,m-1
  if(i .ne. j) then
  write(4,*) r(i,j),"   ", r(i,j+1)
  if (r(i,j) .gt. r(i,j+1)) then
   t=r(i,j)
  r(i,j)=r(i,j+1)
  r(i,j+1)=t
  endif
   endif
  write(5,*) r(i,j)
  enddo
  enddo
  END program sort

请看代码。

标签: sortingfortran

解决方案


遇到这样的情况,我首先想到的是:我需要自己写程序吗?

这里的快速回答是否定的:Linux/Unix 的sort命令可以正常工作:

sort -t, -k3 -g dist.txt
  • -t,告诉 sort 字段分隔符是逗号,
  • -k3告诉它根据第三个字段排序,
  • -g告诉它使用一般的数字排序

如果我需要使用 Fortran 来执行此操作,我可能会将 、 和 读取ij单独r的一维数组中,然后编写一个排序例程,该例程不仅可以排序r,还可以返回顺序。然后您可以轻松地重新排列ij数组以对应相同的顺序。看这个例子:

program sort_r

    implicit none
    integer :: u
    integer, parameter :: num_of_elements = 4
    integer :: i(num_of_elements), j(num_of_elements)
    real :: r(num_of_elements)
    integer :: order(num_of_elements)
    integer :: ii
    open(newunit=u, file='dist.txt')
    do ii=1, num_of_elements
        read(u, *) i(ii), j(ii), r(ii)
    end do
    close(u)
    order = [(ii, ii=1, num_of_elements)]
    call qsort(r, first=1, last=num_of_elements, order=order)
    i(:) = i(order)
    j(:) = j(order)
    do ii = 1, num_of_elements
        write(*,'(I0,",",I0,",",F3.1)') i(ii), j(ii), r(ii)
    end do

contains
    recursive subroutine qsort(a, first, last, order)
        real, intent(inout) :: a(:)
        integer, intent(in) :: first, last
        integer, intent(inout) :: order(:)
        ! Prerequsits:
        !       first >= lbound(a, 1)
        !       last <= lbound(a, 1)
        !       lbound(a, 1) == lbound(order, 1)
        !       ubound(a, 1) == ubound(order, 1)
        real :: pivot
        integer :: i, j

        if (.not. first < last) return ! less than 2 elements

        ! Get pivot from middle to beginning of subarray.
        call swap(a, first, (first+last)/2, order)
        pivot = a(first)
        i = first + 1
        j = last

        do while (j >= i)
            ! move up from left while elements are smaller than pivot
            do while (a(i) < pivot)
                i = i + 1
            end do
            ! move down from right while elements are larger than pivot
            do while (a(j) > pivot)
                j = j - 1
            end do
            ! If we moved past the other index, exit loop
            if (j < i) exit

            ! We have found a larger than pivot element left of a smaller than
            ! pivot element to the right, swap the two, move the indices to next
            call swap(a,i,j,order)
            i = i + 1
            j = j - 1
        end do

        ! Move pivot back to centre
        call swap(a,first,j, order)

        call qsort(a,first=first,last=j-1,order=order)
        call qsort(a,first=i,last=last,order=order)

    end subroutine qsort

    subroutine swap(a, i, j, order)
        real, intent(inout) :: a(:)
        integer, intent(in) :: i, j
        integer, intent(inout) :: order(:)
        real :: t
        integer :: k
        t = a(i)
        a(i) = a(j)
        a(j) = t
        k = order(i)
        order(i) = order(j)
        order(j) = k
    end subroutine swap

end program sort_r

推荐阅读