Kieran 发表于 2023-6-16 09:55:32

数据排序

本帖最后由 Kieran 于 2023-6-19 10:15 编辑

大家好,

我有一个数据文件。内容如下。         116
Parameter
   0.2951429939E+02    0.0000000000E+00    0.0000000000E+00
   0.0000000000E+00    0.1500000000E+02    0.0000000000E+00
   0.0000000000E+00   0.0000000000E+00   0.2510000038E+02
Parameter
   0.000000000    0.500000000    0.300000012
   0.041669998    0.500000000    0.328289986
   0.041669998    0.500000000    0.384860009
   0.000000000    0.500000000    0.413150012
   0.000000000    0.500000000    0.469720006
   0.041669998    0.500000000    0.498010010
   0.041669998    0.500000000    0.554579973
   0.000000000    0.500000000    0.582870007
   0.083329998    0.500000000    0.300000012
   0.125000000    0.500000000    0.328289986
   0.125000000    0.500000000    0.384860009
   0.083329998    0.500000000    0.413150012
   0.083329998    0.500000000    0.469720006
   0.125000000    0.500000000    0.498010010
。。。。。。我想重排各行的位置。重排标准是,先按每行中的第一数据,由小到达排列。如果有两行,或者多行的第一个数据相等,则按第二个数据由小到大重排这些行的位置。如果有两行,或者多行第二个数据也相等,则按第三个数据重排各行位置。这是我的代码。PROGRAM COMPAIMPLICIT NONE

INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(15,14)
INTEGER            :: i, j, k, l
REAL (KIND=dp)   :: ap(116,6), lr(3,3), pl(3), ns(2,116)

OPEN (UNIT=3, FILE='data.dat', STATUS='OLD')
READ (UNIT=3, FMT=*)
READ (UNIT=3, FMT=*)
DO i = 1, 3, 1
   READ (UNIT=3, FMT=*) pl
   lr(i,:) = pl
END DO
READ (UNIT=3, FMT=*)
DO i = 1, 116, 1
   READ (UNIT=3, FMT=*) pl
   ap(i,4:6) = pl
   ns(:,i) = i
END DO

DO i = 1, 116, 1
   ap(i,1) = ap(i,4)*lr(1,1)+ap(i,5)*lr(2,1)+ap(i,6)*lr(3,1)
   ap(i,2) = ap(i,4)*lr(1,2)+ap(i,5)*lr(2,2)+ap(i,6)*lr(3,2)
   ap(i,3) = ap(i,4)*lr(1,3)+ap(i,5)*lr(2,3)+ap(i,6)*lr(3,3)
END DO

DO i = 2, 116, 1
   DO j = 1, i-1, 1
      IF ((ap(i,1) < ap(j,1)) .OR. &
         ((ap(i,1) == ap(j,1)) .AND. (ap(i,2) < ap(j,2))) .OR. &
         ((ap(i,1) < ap(j,1)) .AND. (ap(i,2) == ap(j,2)) .AND. &
         (ap(i,3) < ap(j,3)))) THEN
         k = ns(1,i)
         DO l = j, i-1, 1
            ns(1,l+1) = ns(1,l)
         END DO
         ns(1,j) = k
      END IF
   END DO
END DO

OPEN (UNIT=4, FILE='compare.dat', STATUS='UNKNOWN')
DO i = 1, 116, 1
   DO j = 1, 116, 1
      IF (ns(1,j) == i) WRITE (UNIT=4, FMT=*) ns(:,j), ap(j,1:3)
   END DO
END DO

CLOSE (UNIT=3)
CLOSE (UNIT=4)
STOP
END PROGRAM COMPA
运行后,输出的重排结果如下。
    1.0000000000000000      1.0000000000000000      0.0000000000000000      7.5000000000000000      7.5300004152000044      91.000000000000000      3.0000000000000000      1.2298607965527013      7.5000000000000000      9.6599863721468040   
   91.000000000000000      4.0000000000000000      0.0000000000000000      7.5000000000000000      10.370065458197006   
   91.000000000000000      5.0000000000000000      0.0000000000000000      7.5000000000000000      11.789972329093603   
   91.000000000000000      6.0000000000000000      1.2298607965527013      7.5000000000000000      12.500051440243805   
   91.000000000000000      7.0000000000000000      1.2298607965527013      7.5000000000000000      13.919957533040389   
   91.000000000000000      8.0000000000000000      0.0000000000000000      7.5000000000000000      14.630037397190604   
   91.000000000000000      9.0000000000000000      2.4594265091401013      7.5000000000000000      7.5300004152000044   
   92.000000000000000      2.0000000000000000      1.2298607965527013      7.5000000000000000      8.2400787733501950   
   93.000000000000000      11.000000000000000      3.6892874237500002      7.5000000000000000      9.6599863721468040
。。。。。。 很显然,这个排序时错误的,但我没找到程序里的错误。能麻烦大家帮我看下,我的代码哪里出了错误码?谢谢。


谢谢。


necrohan 发表于 2023-6-20 10:02:11

你的意思是不是用数组ns保存排序的序号,我大概修改了一下

! nline=116
DO i = 1, nline-1
write(*,'(2i4)')i;
ins=ns(1,i); ! 数组排序序号,原始序号在ns(2,i)中
   DO j = i+1, nline
      jns=ns(1,j); ! 序号
      IF ((ap(jns,1) < ap(ins,1)) .OR. &
         ((abs(ap(jns,1)-ap(ins,1))<1.0e-6) .AND. (ap(jns,2) < ap(ins,2))) .OR. &
         ((abs(ap(jns,1)-ap(ins,1))<1.0e-6) .AND. (abs(ap(jns,2)-ap(ins,2))<1.0e-6) .AND. (ap(jns,3) < ap(ins,3))) & ! TODO: 原来是<
         ) THEN
         write(*,*)'swap ',i,j
         ns(1,i) = jns
         ns(1,j)=ins
         ins=jns
         cycle;
      END IF
   END DO
END DO

OPEN (UNIT=4, FILE='resu.txt')
DO i = 1, nline
   WRITE (UNIT=4, FMT='(2i6,2x,10(f12.4,2x))') ns(1:2,i), ap(ns(1,i),1:3)
END DO

Kieran 发表于 2023-6-20 11:55:15

本帖最后由 Kieran 于 2023-6-20 12:06 编辑

necrohan 发表于 2023-6-20 10:02
你的意思是不是用数组ns保存排序的序号,我大概修改了一下

! nline=116

非常感谢你的回复。

我的代码确实是在用ns变量保存各行在排序后的新序号。

我想请教几个问题。

1.你的代码的比较方式,是将各行中”最小“的那一行放在序号变量ns中的最前面,然后再放第二小的,紧接着是第三小,第四小。。。以此类推。我的理解正确吗?

2.请问你的代码中的CYCLE命令作用是什么呢?可不可以不用这个命令呢?

3.请问你觉得我的代码中哪里出了错误呢?我一直没找到原因。

谢谢,望指教。

necrohan 发表于 2023-6-20 15:06:12

Kieran 发表于 2023-6-20 11:55
非常感谢你的回复。

我的代码确实是在用ns变量保存各行在排序后的新序号。


1、我能大概明白你的代码的意思,但是排序那里和我思路不一样,我参考你的方式按自己的思路写的,结果就是你说的那样,从小到大排列。
2、cycle是直接进行下一次循环,不执行endif后面的语句节省点时间,这里因为endif后面没有语句了,所以不用也可以。
3、如果读入的lr是单位矩阵,那么你的代码ap(i,1:3)和ap(i,4:6)是相同的,我是这么测试查看输出结果的。
你的代码我没太明白,但是31行那个ap(i,1)<ap(j,1)应该是==。
我印象中浮点数比较用==的容易出问题,我用的绝对值差判断。
你的代码34~36行我不明白为什么要对ns循环赋值,我理解ns数组保存的序号,直接调换就行。
输出排序结果那段循环,就是43~47行,我不明白一共就116行你为什么要嵌套2次,直接循环116次输出就行。

Kieran 发表于 2023-6-20 15:16:59

necrohan 发表于 2023-6-20 15:06
1、我能大概明白你的代码的意思,但是排序那里和我思路不一样,我参考你的方式按自己的思路写的,结果就 ...

谢谢你的回复和指点。

我原本想着用insertion sorting方法排序,但我可能自己没想清楚每个步骤,所以代码不合理。

我再仔细想想吧。

再次感谢。
页: [1]
查看完整版本: 数据排序