Πίνακες (i) Δομημένη μεταβλητή: αποθηκεύει μια συλλογή από τιμές δεδομένων Πίνακας (array): δομημένη μεταβλητή που αποθηκεύει πολλές τιμές του ίδιου τύπου INTEGER:: pinakas(100)ή INTEGER, DIMENSION(100)::pinakas ορίζει έναν πίνακα εκατό ακεραίων, τα στοιχεία του οποίου είναι: pinakas(1), pinakas(2), pinakas(3)... pinakas(100) και έχουν τύπο integer 1
Πίνακες (ii) Παραδείγματα INTEGER:: a(12), Y(5) REAL:: b(5) CHARACTER(LEN=10):: NAMES(12) Εντολές εκχώρησης a(1) = 4; a(2)=5; a(12)=8 b=(/2.3, 4.6, 5.8, 9.1, 10.0/) Y=(/(i, i=1,22,5)/) READ(*.*) (NAMES(k), k=1,12) αρχή, τέλος, βήμα 2
Πίνακες (iii) Διάβασμα ενός πίνακα REAL:: a(12) READ(*,*) (a(k), k=1,12) ή DO i=1,12 READ (*,*) a(i) Εκτύπωση ενός πίνακα WRITE (*,*) a(:) ή DO i=1,12 WRITE (*,*) a(i) 3
Πράξεις με πίνακες Απλές πράξεις, π.χ. a(k) = a(k)+1; a(k) = a(1)+a(n); DO i=1,10 WRITE(*,*) a(i) IF (a(k) > a(k+1)) THEN... Αρχικοποίηση (με μηδενικά) DO i=1,10; a(i)=0; Εύρεση ελάχιστου στοιχείου x = a(1) DO i=2,10 IF (a(i) < x) THEN x = a(i) END IF 4
Γραμμική αναζήτηση (i) Πρόβλημα (αναζήτησης): δίνεται ένας πίνακας ακεραίων a και ζητείται να βρεθεί αν υπάρχει ο ακέραιος x σταστοιχείατου IMPLICIT NONE INTEGER:: x,a(10) άλλες δηλώσεις; διάβασμα του πίνακα a; διάβασμα του ακεραίου x; ψάξιμο στον πίνακα για τον x; παρουσίαση αποτελεσμάτων END 5
Γραμμική αναζήτηση (ii) Μια δυνατή συγκεκριμενοποίηση READ(*,*) (a(i) i=1,10) j=1 DO WHILE ((j<10).and. (a(j)/=x)) j=j+1 IF (a(j)==x) THEN WRITE(*,*) 'To βρήκα στη θέση ', ELSE WRITE(*,*) 'Δεν το βρήκα' END IF Στη χειρότερη περίπτωση θα ελεγχθούν όλα τα στοιχεία του πίνακα Απαιτούνται a n + b βήματα γραμμική (a, b σταθερές, n το μέγεθος του πίνακα) j 6
Γραμμική αναζήτηση (iii) Εναλλακτική συγκεκριμενοποίηση #1 i=1; found=.false. DO WHILE ((i<=10).and. (.NOT. found)) IF a(i)==x THEN found=.true. ELSE found =.FALSE. END IF i=i+1 IF (found) THEN WRITE(*,*) 'To βρήκα στη θέση ', (i-1) ELSE WRITE (*,*) 'Δεν το βρήκα' END IF 7
Γραμμική αναζήτηση (iv) Εναλλακτική συγκεκριμενοποίηση #2 i=1; found=.false. DO WHILE ((i<=10).and. (.NOT. found)) IF a(i)==x THEN found=.true. END IF i=i+1 IF (found) THEN WRITE(*,*) 'To βρήκα στη θέση ', (i-1) ELSE WRITE (*,*) 'Δεν το βρήκα' END IF 8
Γραμμική αναζήτηση (v) Εναλλακτική συγκεκριμενοποίηση #3 i=1; found=.false. DO WHILE ((i<=10).and. (.NOT. found)) found=(a(i)==x) i=i+1 IF (found) THEN WRITE(*,*) 'To βρήκα στη θέση ', (i-1) ELSE WRITE(*,*) 'Δεν το βρήκα' END IF 9
Δυαδική αναζήτηση (i) Προϋπόθεση: ο πίνακας να είναι ταξινομημένος, π.χ. σε αύξουσα διάταξη Είναι πολύ πιο αποδοτική από τη γραμμική αναζήτηση Στη χειρότερη περίπτωση απαιτούνται a log 2 n + b βήματα λογαριθμική (a, b σταθερές, n το μέγεθος του πίνακα) 10
Δυαδική αναζήτηση (ii) Το πρόγραμμα PROGRAM binsearch INTEGER, PARAMETER:: n=100; INTEGER:: i,howmany,mid,first,last INTEGER:: a(n), x LOGICAL:: found Μήνυμα επικεφαλίδα και οδηγίες χρήσης read(howmany) (* κατά αύξουσα σειρά *) DO i=1,howmany READ(*,*) (a(i)) READ(*,*) x Αναζήτηση και εμφάνιση αποτελέσματος END 11
Δυαδική αναζήτηση (iii) Αναζήτηση και εμφάνιση αποτελέσματος first=1; last=howmany found = false DO WHILE ((.NOT.found).AND.(first<=last)) mid = (first+last) / 2 found = (x==a(mid)) IF (x<a(mid)) THEN last=mid-1 ELSE first=mid+1 END IF IF (found) THEN WRITE(*,*) mid ELSE WRITE(*,*) 'not found' END IF 12
Ταξινόμηση (i) Πρόβλημα: να αναδιαταχθούν τα στοιχεία ενός πίνακα ακεραίων σε αύξουσα σειρά Μια από τις σημαντικότερες εφαρμογές των ηλεκτρονικών υπολογιστών Βασική διαδικασία: εναλλαγή τιμών (swap) SUBROUTINE SWAP (x,y) IMPLICIT NONE INTEGER:: x,y,save save=x x=y y=save END 13
Ταξινόμηση (ii) Μέθοδος της φυσαλίδας DO i=1,(n-1) DO j=(n-1),i,-1 IF (a(j)>a(j+1)) THEN CALL swap (a(j),a(j+1)) END IF Πλήθος συγκρίσεων (n 1) + (n 2) +... + 2 + 1 = n (n 1) / 2 της τάξης του n 2 O(n 2 ) 14
Ταξινόμηση (iii) Παράδειγμα εκτέλεσης 15
Πολυδιάστατοι πίνακες (i) Παράδειγμα INTEGER:: a(77,99) ή INTEGER, DIMENSION (77,99):: a DO i=1,10 DO j=1,5 READ(*,*) a(i,j) Πίνακες περισσοτέρων Διαστάσεων Η Fortran επιτρέπει μέχρι επτά διαστάσεις με οποιοδήποτε αριθμό στοιχείων ανά διάσταση. 16
Αποθήκευση πίνακα στη μνήμη Θέσεις Μνήμης Πίνακας Α με μία διάσταση Πίνακας Β(2,4) Πίνακας C(2,2,2) Πίνακας D(-1:2,0:1) 1 A(1) B(1,1) C(1,1,1) D(-1,0) 2 A(2) B(2,1) C(2,1,1) D(0,0) 3 A(3) B(1,2) C(1,2,1) D(1,0) 4 A(4) B(2,2) C(2,2,1) D(2,0) 5 A(5) B(1,3) C(1,1,2) D(-1,1) 6 A(6) B(2,3) C(2,1,2) D(0,1) 7 A(7) B(1,4) C(1,2,2) D(1,1) 8 A(8) B(2,4) C(2,2,2) D(2,1) 17
Πολλαπλασιασμός πινάκων (i) Δίνονται οι πίνακες: a (m n), b (n q) Ζητείται ο πίνακας: c = a b (m q) όπου: c i, j = n k = 1 a i, k b k, j 18
Πολλαπλασιασμός πινάκων (ii) To πρόγραμμα INTEGER:: a(m,n), b(n,q), c(m,q) DO i=1,m DO j=1,q c(i,j)=0 DO k=1,n c(i,j)=c(i,j)+a(i,k)*b(k,j) 19
Μαγικά τετράγωνα (i) Διδιάστατοι πίνακες (n n) που περιέχουν όλους τους φυσικούς μεταξύ 0 και n 2 1 το άθροισμα των στοιχείων κάθε στήλης, γραμμής και διαγωνίου είναι σταθερό Πρόβλημα: κατασκευή μαγικού τετραγώνου (n n) για περιττό n 10 9 3 22 16 17 11 5 4 23 24 18 12 6 0 1 20 19 13 7 8 2 21 15 14 20
Μαγικά τετράγωνα (ii) 21
Μαγικά τετράγωνα IMPLICIT NONE INTEGER, PARAMETER:: n=5 INTEGER::h,i,j,k,m,a(n,n) i=n/2 j=n k=0 DO i=1,n DO j=1,n WRITE(*,10) a(i,j) 10 FORMAT (I4,1X\) WRITE(*,*) END Δηλώσεις, Αρχικοποιήσεις Εκτύπωση των στοιχείων (iii) DO h=1,n Υπολογισμός j=j-1 των στοιχείων a(i+1,j+1)=k k=k+1 DO m=2,n j=mod((j+1),n) i=mod((i+1),n) a(i+1,j+1)=k k=k+1 22
Ανάστροφος πίνακας PROGRAM YPOLOGOISMOS_ANASTROFOU IMPLICIT NONE INTEGER, PARAMETER:: N=4, M=3 INTEGER:: i, j, A(N,M), B(M,N) WRITE(*,*) "Δώσε τιμές για τα στοιχεία του πίνακα" READ(*,*) ((A(i,j), j=1,m), i=1,n) DO i=1,n DO j=1,m B(j,i)=A(i,j) WRITE(*,10) ((A(i,j), j=1,m), i=1,n) WRITE(*,20) ((B(i,j), j=1,n), i=1,m) 10 FORMAT (' A='/4(' ',3(I3),' '/)) 20 FORMAT (' B='/3(' ',4(I3),' '/)) END 23
Κατηγορίες Πινάκων (i) Οι διαστάσεις και το πλήθος του πίνακα είναι γνωστές από τη δήλωση του πίνακα INTEGER:: p1(3,5,8) INTEGER:: p2(4:7, 5:9, -3:2) O p1 έχει τις θέσεις 1,2,3 στην πρώτη διάσταση, τις 1,2,3,4,5 στη δεύτερη και τα τις 1,2,3,4,5,6,7,8 στην τρίτη. (Μέγεθος του πίνακα 3*5*8=120) Ο p2 έχει τις θέσεις 4,5,6,7 στην πρώτη διάσταση, τις 5,6,7,8,9 στη δεύτερη και τις -3 έως 2 στην τρίτη π.χ. p2(5,7,-1)=6. (Μέγεθος του πίνακα 4*5*6=120) Οι δείκτες ενός πίνακα μπορεί να είναι οποιαδήποτε ορθή έκφραση ακεραίων π.χ. X(10,2), X(2*i), X(INT(ABS(a))) 24
Κατηγορίες Πινάκων (ii) Οι διαστάσεις είναι γνωστές αλλά όχι και το μέγεθος. Το πλήθος των στοιχείων ανά διάσταση καθορίζεται τη στιγμή της χρήσης του και είναι ίδιες με αυτές κάποιου άλλου πίνακα. INTEGER:: p1(5,8) CALL R(p1) SUBROUTINE R(p2) INTEGER p2(:,:) Τη στιγμή που καλείται η υπορουτίνα καθορίζεται ο αριθμός των στοιχείων ανά διάσταση. 25
Κατηγορίες Πινάκων (iii) PROGRAM pinakes IMPLICIT NONE INTEGER I,J,X(3,2) DO I=1,3; DO J=1,2 X(I,J)=I+J ; WRITE(*,*), SHAPE(X) WRITE(*,*), X(1,:) CALL SUB1(X) CALL SUB2(X) END SUBROUTINE SUB1(V) INTEGER V(2,*) WRITE(*,*) SIZE(V,1) WRITE(*,*) V(:,1) WRITE(*,*), V(:,2) END SUBROUTINE SUBROUTINE SUB2(V) INTEGER V(*) WRITE(*,*) V(6) END SUBROUTINE αποτέλεσμα 32 23 2 23 43 5 26
Κατηγορίες Πινάκων (iv) Οι διαστάσεις είναι γνωστές αλλά όχι και το μέγεθος. Το μέγεθος καθορίζεται κατά τη διάρκεια εκτέλεσης του προγράμματος. Δηλώνονται με τη χρήση της εντολής ALLOCATE. INTEGER, ALLOCATABLE, DIMENSION(:,:,:):: pin1 ALLOCATE (pin1(10,10,10)) DEALLOCATE(pin1) ALLOCATE (pin1(15,15,15)) 27
Κατηγορίες Πινάκων (v) INTEGER, ALLOCATABLE, DIMENSION(:,:,:):: pin1 ALLOCATE (pin1(10,10,10)) DEALLOCATE(pin1) ALLOCATE (pin1(15,15,15)) PROGRAM allocatable_array IMPLICIT NONE INTEGER:: i,j INTEGER, ALLOCATABLE, DIMENSION(:,:,:):: pin1 ALLOCATE (pin1(5,5,5)) pin1=5 WRITE(*,*) pin1; WRITE(*,*)!τυπώνει τον αριθμό 5 125=5*5*5 φορές DEALLOCATE(pin1) ALLOCATE (pin1(10,10,10)) pin1=8 WRITE(*,*) pin1; WRITE(*,*)!τυπώνει τον αριθμό 8 1000=10*10*10 φορές DEALLOCATE(pin1) END 28
Δείκτες στοιχείων πίνακα τα στοιχεία άλλου πίνακα Τα στοιχεία ενός πίνακα μπορούν να χρησιμοποιηθούν ως δείκτες στοιχείων άλλου αρκεί οι δείκτες να είναι ακέραιοι INTEGER:: pin(5) INTEGER:: pin1(8) INTEGER:: pin2(5) pin=(/2,3,4,5,8/) pin1=(/2,3,4,5,8,3,4,5/) pin2=pin1(pin) Οι τιμές των στοιχείων του πίνακα pin2 είναι 3,4,5,8,5 29
Τμήματα πινάκων (υποπίνακες) (i) Κάποιο τμήμα ενός πίνακα (ένας υποπίνακας) μπορεί να πάρει τιμές από κάποιο άλλο τμήμα του πίνακα με ορισμένες προϋποθέσεις. Εστω για παράδειγμα ο πίνακας INTEGER, DIMENSION(1:6,1:8) :: P Επιτρεπτές εκχωρήσεις τιμών είναι οι παρακάτω: P(1:3,1:4)=P(1:6:2,1:8:2). Υποπίνακας παίρνει τιμές από άλλον ίδιων διαστάσεων P(1:3,1:4)=2. Υποπίνακας παίρνει την σταθερή τιμή 2 P(2:6:2,1:7:3)=P(1:3,1:4) Υποπίνακας διαστάσεων 3x3 παίρνει τις τιμές υποπίνακα διαστάσεων 3x4 (δεν είναι επιτρεπτή σε όλους τους compilers) Μη επιτρεπτές εκχωρήσεις τιμών Οταν υποπίνακας παίρνει τιμές από υποπίνακα μικρότερων διαστάσεων π.χ. P(2:6:2,1:7:3)=P(2:5,7) 30
Τμήματα πινάκων (υποπίνακες) (ii) INTEGER, DIMENSION(1:6,1:8):: P INTEGER:: I,J DO I=1,6 DO J=1,8 P(I,J)=I+J DO I=1,6 WRITE(*,*) P(I,:); WRITE(*,*) WRITE(*,*) P(1:3,1:4)=P(1:6:2,1:8:2) DO I=1,6 WRITE(*,*) P(I,:); WRITE(*,*) WRITE(*,*) WRITE(*,*) P(1:3,1:4)=2 DO I=1,6 WRITE(*,*) P(I,:) WRITE(*,*) END P(2:6:2,1:7:3)=P(1:3,1:4) DO I=1,6 WRITE(*,*) P(I,:) WRITE(*,*) P(2:6:2,1:7:3)=P(2:5,7) DO I=1,6 WRITE(*,*) P(I,:) WRITE(*,*) 31
Χειρισμός πινάκων χωρίς την εντολή DO Εκχώρηση τιμών DO i=1,5 A(i)=A(i+1) Απλουστευμένος Τρόπος γραφής A(1:5)=A(2:6) Το αντίστροφο δεν μπορεί να γίνει DO i=1,5 A(i+1)=A(i) Απλουστευμένος Τρόπος γραφής A(2:6)=A(1:5) 32
Χειρισμός πινάκων χωρίς την εντολή DO DO i=1,5 A(i)=A(i+1) Τυπώνει: 2 3 4 5 6 DO i=1,10 A(i)=i A(1:5)=A(2:6) Τυπώνει: 2 3 4 5 6 Προσοχή! Το αντίστροφο δεν δίνει το ίδιο αποτέλεσμα DO i=1,5 A(i+1)=A(i) Τυπώνει: 1 1 1 1 1 Δίνει διαφορετικό αποτέλεσμα A(2:6)=A(1:5) Τυπώνει: 1 1 2 3 4 5 33
Υποπίνακες με μη συνεχή στοιχεία Η χρήση βήματος δίνει τη δυνατότητα πρόσβασης σε μη συνεχή στοιχεία πίνακα. π.χ. Β = Α(10:20:2). Ο υποπίνακαςα(10:20:2) περιλαμβάνει τα στοιχεία Α(10), Α(12), Α(14), Α(16), Α(18) και Α(20). Τα στοιχεία του πίνακα Β παίρνουν τις τιμές του υποπίνακα Α όπως αυτός ορίστηκε παραπάνω. Δηλ. τα Β(1), Β(2),..., Β(10) θα πάρουν τις τιμές των στοιχείων Α(10), Α(12),...,Α(20) αντίστοιχα Στοβήμαμπορείναέχουμεκαιαρνητικέςτιμές. Για παράδειγμα Β(10:1:-1). Και αν ορίσω μονοδιάστατο πίνακα Γ(10) και δώσω την εντολή Γ= Β(10:1:-1) παίρνω τον αντίστροφο πίνακα του Β. Τα άνω και κάτω όρια ενός πίνακα μπορεί να παραλειφθούν αν έχουν δηλωθεί προηγούμενα. Για π.χ. Η εντολήγ(:10)=5 θα εκχωρήσει την τιμή 5 στα στοιχεία του πίνακα Γ από το Γ(1) έως το Γ(10). Το ίδιο ισχύει και αν γράψω Γ(1:)=5 ή Γ(:)=5 34
Εντολή WHERE (i) Εκτέλεση εντολών υπό συνθήκη σε πίνακα WHERE (συνθήκη) Εκχωρήσεις τιμών σε στοιχεία πίνακα ELSEWHERE Άλλες Εκχωρήσεις τιμών ENDWHERE WHERE (Α>5) Β= -Α ELSEWHERE Β=Α ENDWHERE 35
Εντολή WHERE (ii) PROGRAM WHERE_ARRAY IMPLICIT NONE INTEGER :: A(10), B(10), G(10) WRITE(*,*) "Δώσε 10 τιμές για τα στοιχεία του Α"; READ(*,*) A B=0; G=10 WHERE (A >= 5) B=B+1; G=G-1 ELSEWHERE A=20 ENDWHERE WRITE(*,*) "PINAKAS A" WRITE(*,*) A WRITE(*,*) "PINAKAS B" WRITE(*,*) B WRITE(*,*) "PINAKAS G" WRITE(*,*) G END Αν ο χρήστης δώσει τιμές 1,2,3,4,5,6,7,8,9,10 στον πίνακα Α Το πρόγραμμα τυπώνει: 20 20 20 20 5 6 7 8 9 10 (τιμές του Α) 0 0 0 0 1 1 1 1 1 1 (τιμές του Β) 10 10 10 10 9 9 9 9 9 9 (τιμές του G) 36
Εντολή FORALL (i) Εκτέλεση εντολών υπό συνθήκη σε πίνακα FORALL (συνθήκη) Εντολές ανάθεσης END FORALL Παραδείγματα: FORALL (i=1:10) A(i,i) =20 FORALL (i=1:3, (A(i,i)/=0)) A(i,i) =20 FORALL (i=1:n, j=1:n) A(i,j)= 1/REAL(i+j) FORALL (i=1:5) WHERE (C(i,:)==0) C(:,i)=I ELSEWHERE (C(i,:)>2) C(i,:)=23 ENDWHERE ENDFORALL 37
Εντολή FORALL PROGRAM forall_array IMPLICIT NONE INTEGER :: i, j, A(3,3) READ(*,*) A FORALL (i=1:3, (A(i,i)/=0)) A(i,i) =20 WRITE(*,*) "ΠΙΝΑΚΑΣ A" WRITE(*,*) A FORALL (i=1:3) A(i,2)=48 WRITE(*,*) "ΠΙΝΑΚΑΣ A" WRITE(*,*) A END (ii) Αν ο χρήστης δώσει τον πίνακα Α με τιμές 123 456 789 Το πρόγραμμα θα τυπώσει: ΠΙΝΑΚΑΣ Α 20 2 3 4 20 6 7 8 20 ΠΙΝΑΚΑΣ Α 20 2 3 48 48 48 7 8 20 FORALL (i=1:5) WHERE (C(i,:)==0) C(:,i)=i ELSEWHERE (C(i,:)>2) C(i,:)=9 ENDWHERE ENDFORALL Για τιμές του C: 1 0 0 0 0 2 1 1 1 0 1 2 2 0 2 2 1 0 2 3 1 0 0 0 0 Τι θα τυπώσει το πρόγραμμα μετά τη WHERE? Το πρόγραμμα μετά την FORALL τυπώνει: 1 0 0 0 0 1 1 1 1 5 1 2 2 4 9 1 1 3 2 9 1 2 0 0 5 38
PROGRAM PINAKES IMPLICIT NONE REAL, DIMENSION(4):: HEIGHTS=(/ 5.1, 5.6, 4.0, 3.6 /) CHARACTER (LEN=5), DIMENSION(3)::COLORS=(/ 'BLUE ', ' RED ', 'GREEN' /) INTEGER::i INTEGER, DIMENSION(10)::INTS=(/ 100, (i, i=1,8), 100 /) WRITE(*,*) HEIGHTS WRITE(*,*) COLORS WRITE(*,*) INTS END PROGRAM CHANGE_COLUMNS IMPLICIT NONE INTEGER, PARAMETER:: N=2, M=4 INTEGER::i,j,A(N,M), j1, j2, temp WRITE(*,*) "GIVE ARRAY ELEMENTS" READ(*,*) A WRITE(*,*) "old array" DO i=1,n WRITE(*,*) A(i,:) WRITE(*,*) "GIVE COLUMNS J1,J2" READ(*,*) J1,J2 DO i=1,n temp=a(i,j1) A(i,j1)=A(i,j2) A(i,j2)=temp WRITE(*,*) "new array" DO i=1,n WRITE(*,*) A(i,:) END 39