首页 > 解决方案 > 如何对嵌套类型的数组进行排序?

问题描述

我在 Fortran 95 中有以下数据结构:

        type :: timestamp_record
                integer                                 :: year
                integer                                 :: month
                integer                                 :: day
                integer                                 :: hour
                integer                                 :: minute
                integer                                 :: second
        end type
​
        type :: foo_record
                type(timestamp_record)                  :: timestamp
                integer                                 :: foo
                integer                                 :: bar
                integer                                 :: baz
        end type
​
        type(foo_record),dimension(10000)               :: my_array
​

我想排序my_array

   timestamp%year
   timestamp%month
   timestamp%day
   timestamp%hour
   timestamp%minute
   timestamp%second

我已经看到有 qsort 和 qsort64 可用,但我不明白我应该使用什么作为长度。

我还看到需要提供比较功能(类似于 C qsort)。

三个问题:

  1. qsort我在哪里可以找到为两个或三个字段实现的示例?
  2. 即使在我想对嵌套数组进行排序的这种情况下,我也可以使用它type吗?
  3. type结构在 Fortran 中称为 struct 吗?

标签: algorithmfortranqsort

解决方案


我无法评论您在哪里找到示例代码。这是题外话,但确实存在示例。使用我们搜索。试试 Github 或 RosettaCode 之类的网站。

但是,最好注意结构通常是如何排序的。您通常会创建一个比较函数来比较两个对象并说明它们应该如何排序,它们中的哪一个应该先行。

例如,从我的代码

  function CompareWMPoints(Aptr,Bptr) bind(C,name="CompareWMPoints") result(res)
    use iso_c_binding
    integer(c_int)         :: res
    type(c_ptr),value :: Aptr,Bptr
    type(WMPoint),pointer  :: A,B

    call c_f_pointer(Aptr,A)
    call c_f_pointer(Bptr,B)

    if ((A%xi+(A%yj-1)*Prnx+(A%zk-1)*Prnx*Prny) < (B%xi+(B%yj-1)*Prnx+(B%zk-1)*Prnx*Prny)) then
      res = -1_c_int
    else if ((A%xi+(A%yj-1)*Prnx+(A%zk-1)*Prnx*Prny) > (B%xi+(B%yj-1)*Prnx+(B%zk-1)*Prnx*Prny)) then
      res =  1_c_int
    else if (A%distx**2+A%disty**2+A%distz**2 < B%distx**2+B%disty**2+B%distz**2) then
      res = -1_c_int
    else if (A%distx**2+A%disty**2+A%distz**2 > B%distx**2+B%disty**2+B%distz**2) then
      res =  1_c_int
    else
      res =  0_c_int
    end if

  end function CompareWMPoints

这比较了两个对象AB。您可以引用嵌套在这两个对象中的任何其他结构。比较的结果是一个整数(-1、1 或 0)。

注意:AandB是通过 C 指针传递的,因为qsort()使用了 C。使用 Fortran 排序子例程可以避免这种情况。可以使用type(...), intent(in) ::,但如果类型不可互操作,这是不合法的。

因为我很懒,所以我只是qsort()从 C 标准库中调用

  interface
    subroutine qsort(array,elem_count,elem_size,compare) bind(C,name="qsort")
      import
      type(c_ptr),value       :: array
      integer(c_size_t),value :: elem_count
      integer(c_size_t),value :: elem_size
      type(c_funptr),value    :: compare !int(*compare)(const void *, const void *)
    end subroutine qsort !standard C library qsort
  end interface

但是您可以调用任何其他使用比较函数的子例程。

使用这些回调函数会带来一定的性能损失,但通常并不那么重要。


推荐阅读