如何根据升序列值对数组中的行进行排序?

时间:2018-03-06 23:26:49

标签: arrays sorting multidimensional-array fortran row

例如,如果我有以下2D数组:

2   1   4
1   2   3
2   1   2

并希望按行排序,我如何使用列值升序?在这种情况下,我能够对数组中的第一列进行排序,得到

1 2 3
2 1 4
2 1 2 

通过这个例子,我的最终结果应该是:

1 2 3
2 1 2
2 1 4

首先,我想查看第一列,然后对行进行排序。由于两行以2开头,我想查看第二列,然后排序。如果那些仍然是相同的数字,我想看下一栏等等。我该怎么做?

2 个答案:

答案 0 :(得分:1)

您需要的是两个不同的程序:

将两行相互比较并决定哪一行应该更早出现,另一行实际进行排序。

以下是使用实施不当的冒泡排序的版本:

program sort

    implicit none
    integer, parameter :: num_rows = 3
    integer, parameter :: num_cols = 3
    character(len=*), parameter :: fmt = '(3I4)'
    integer :: a(num_cols,num_rows)

    a = reshape([2, 1, 4, 1, 2, 3, 2, 1, 2], [3, 3])

    call sortrow(a)

    print fmt, a

contains

    subroutine sortrow(a)
        implicit none
        integer, intent(inout) :: a(num_cols, num_rows)
        integer :: i, j
        integer :: tmp(num_cols)
        do i = 1, num_rows
            do j = i+1, num_rows
                if (islarger(a(:,i), a(:,j))) then
                    tmp(:) = a(:, i)
                    a(:, i) = a(:, j)
                    a(:, j) = tmp(:)
                end if
            end do
        end do
    end subroutine sortrow

    function islarger(a, b)
        implicit none
        integer, intent(in) :: a(num_cols), b(num_cols)
        logical :: islarger
        integer :: i
        do i = 1, num_cols
            if (a(i) > b(i)) then
                islarger = .TRUE.
                return
            end if
            if (b(i) > a(i)) then
                islarger = .FALSE.
                return
            end if
        end do
        islarger = .FALSE.
        return
    end function islarger

end program sort

或者你可以编写一个函数,将一行映射到一个整数值,这样如果 n 行必须在 m 之后,那么这个值 n 大于 m

例如,如果所有值都是单个数字(0到9),那么您可以将[2, 1, 4]转换为214,这将更容易排序。

答案 1 :(得分:0)

我尝试了将接口写入standard C library subroutine qsort的懒惰方法。为了避免全局数据,我将比较函数作为调用qsort的子例程的内部函数,并保存要排序的数组。中间子例程分配qsort实际排序的索引数组,然后索引数组用于拉直输入数组。以下是它的工作原理:

module sortmod
   use ISO_C_BINDING
   implicit none
   interface
      subroutine qsort(base,nitems,size,compar) bind(C,name='qsort')
         import
         implicit none
         type(C_PTR), value :: base
         integer(C_SIZE_T), value :: nitems
         integer(C_SIZE_T), value :: size
         interface
            function compar(x,y) bind(C)
               import
               implicit none
               integer(C_INT) compar
               type(C_PTR),value :: x
               type(C_PTR),value :: y
            end function compar
         end interface
      end subroutine qsort
   end interface
   contains
      recursive subroutine startsort(array)
         integer(C_INT) array(:,:)
         integer(C_INT), allocatable, target :: indices(:)
         integer i
         indices = [(i,i=1,size(array,1))]
         call qsort(C_LOC(indices),size(indices,1,kind=C_SIZE_T),C_SIZEOF(indices(1)),callback)
         array = array(indices,:)
         contains
            function callback(x,y) bind(C)
               integer(C_INT) callback
               type(C_PTR), value :: x, y
               integer(C_INT), pointer :: ix,iy
               integer j
               call C_F_POINTER(x,ix)
               call C_F_POINTER(y,iy)
               callback = 0
               do j = 1, size(array,2)
                  callback = array(ix,j) - array(iy,j)
                  if(callback /= 0) return
               end do
            end function callback
      end subroutine startsort
end module sortmod

program testsort
   use sortmod
   implicit none
   integer(C_INT), allocatable :: array(:,:)
   character(20) fmt
   array = reshape([2, 1, 4, &
                    1, 2, 3, &
                    2, 1, 2], &
                    [3, 3], order = [2, 1])
   call startsort(array)
   write(fmt,'(*(g0))') '(',size(array,2),'i3)'
   write(*,fmt) transpose(array)
end program testsort

使用gfortran输出:

  1  2  3
  2  1  2
  2  1  4