Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Εισαγωγή στον Προγ/μό Η/Υ Ενότητα 10: Πίνακες Διδάσκων: Μιχάλης Τίτσιας.

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "Εισαγωγή στον Προγ/μό Η/Υ Ενότητα 10: Πίνακες Διδάσκων: Μιχάλης Τίτσιας."— Μεταγράφημα παρουσίασης:

1 Εισαγωγή στον Προγ/μό Η/Υ Ενότητα 10: Πίνακες Διδάσκων: Μιχάλης Τίτσιας

2 Περιεχόμενα Ακολουθιακά δεδομένα σε πίνακες Αναφορές Εύρεση ελάχιστου στοιχείου Πολυδιάστατοι πίνακες

3 Ακολουθιακά δεδομένα Πολλές φορές δίνεται ακολουθία δεδομένων – Π.χ., θερμοκρασία τελευταίων 20 ημερών, στοιχεία φοιτητών, λίστα με ονόματα/τηλέφωνα Αναφέρονται ως το 1 ο, 2 ο, κτλ. Υπολογισμός βάσει ακολουθιακών δεδομένων – Π.χ., μέση θερμοκρασία, πλήθος «Γιώργων» στο 1 ο έτος, αλφαβητικά ταξινομημένος τηλεφωνικός κατάλογος.

4 Αναπαράσταση ακολουθιακών δεδομένων με πίνακες double[] temp = {27.4, 18.2, 31.9}; println(”H θερμοκρασία την 1 η μέρα = ”+ temp[0] ); println(”H θερμοκρασία την 3 η μέρα = ”+ temp[2] ); // Mέση θερμοκρασία double mean = ( temp[0]+temp[1]+temp[2] )/3;

5 Εισαγωγή στους πίνακες Ένας πίνακας είναι μια συλλογή μεμονωμένων τιμών δεδομένων με δύο διακριτικά χαρακτηριστικά : Οι μεμονωμένες τιμές ενός πίνακα ονομάζονται στοιχεία. Ο τύπος τους (που πρέπει να είναι ίδιος, επειδή πίνακες είναι ομοιογενής) ονομάζεται τύπος στοιχείων. Ο αριθμός των στοιχείων ονομάζεται μήκος του πίνακα. Κάθε στοιχείο προσδιορίζεται από τον αριθμό της θέσης του στον πίνακα, που ονομάζεται δείκτης. Οι αριθμοί ευρετηρίου αρχίζουν από το μηδέν και, επομένως, εκτείνονται μέχρι ένα μικρότερο από το μήκος του πίνακα. Ένας πίνακας διατάσσεται. Πρέπει να μπορείτε να απαριθμήστε τις τιμές: ποια είναι 1 η, ποια 2 η κτλ. 1. Ένας πίνακας είναι ομοιογενής. Κάθε τιμή στον πίνακα πρέπει να είναι του ίδιου τύπου. 2.

6 Δηλώνοντας μια μεταβλητή πίνακα Όπως και με τις άλλες μεταβλητές, οι μεταβλητές πίνακα πρέπει να δηλώνονται πριν τη χρήση. Στην Java, η πιο κοινή σύνταξη για τη δήλωση μιας μεταβλητής πίνακα είναι: type [] name = new type [ n ]; όπου type είναι ο τύπος στοιχείων, name είναι το όνομα του πίνακα, και n είναι ένας ακέραιος που δηλώνει το πλήθος των στοιχείων Αυτή η δήλωση συνδυάζει δύο λειτουργίες. Το τμήμα της γραμμής στα αριστερά του ίσον δηλώνει τη μεταβλητή. Το δεξιό τμήμα δημιουργεί ένα πίνακα με τον καθορισμένο αριθμό των στοιχείων και την εκχωρεί στην μεταβλητή. Παρότι οι δύο λειτουργίες είναι διαφορετικές, θα σας βοηθήσει να αποφύγετε τα λάθη, αν συνηθίσετε να αρχικοποιείτε τους πίνακες σας όταν τους δηλώνετε.

7 Παράδειγμα δήλωσης πίνακα Η ακόλουθη δήλωση δημιουργεί έναν πίνακα που ονομάζεται intArray που αποτελείται από 10 τιμές τύπου int : int[] intArray = new int[10]; ευκολότερος τρόπος για να απεικονιστούν πίνακες είναι να τους σκεφτείτε ως μια γραμμική συλλογή κουτιών, με το καθένα να χαρακτηρίζεται από τον αριθμό ευρετηρίου του. Επομένως η μεταβλητή intArray θα έμοιαζε κάπως έτσι: 012345678 0000000000 9 intArray Η Java αρχικοποιεί αυτόματα κάθε στοιχείο ενός νέου πίνακα στην προεπιλεγμένη τιμή, η οποία είναι μηδέν για αριθμητικούς τύπους, ψευδείς για τιμές τύπου Boolean και κενό για τα αντικείμενα.

8 Επιλογή πίνακα Σε ένα πίνακα, όπως ο intArray στο κάτω μέρος της διαφάνειας, μπορείτε να πάρετε την τιμή κάθε στοιχείου γράφοντας το δείκτη του στοιχείου σε αγκύλες μετά το όνομα του πίνακα. Αυτή η λειτουργία ονομάζεται επιλογή. 012345678 0000000000 9 intArray Μπορείτε, να επιλέξτε το πρώτο στοιχείο γράφοντας intArray[0] Το αποτέλεσμα της επιλογής είναι ουσιαστικά μια μεταβλητή. Μπορείτε ακόμα και να ορίσετε μια νέα τιμή. Η ακόλουθη δήλωση αλλάζει την τιμή του τελευταίου στοιχείου σε 42: intArray[9] = 42; 42

9 Διάσχιση πινάκων Ένα από τα πιο χρήσιμα πράγματα είναι ότι ο δείκτης δεν πρέπει να είναι μια σταθερά. Πολλές φορές, είναι χρήσιμο ο δείκτης να είναι η μεταβλητή ελέγχου ενός βρόχου for. for (int i = 0; i < intArray.length; i++) { intArray[i] = 0; } Για παράδειγμα, μπορείτε να επαναφέρετε κάθε στοιχείο του intArray σε 0 χρησιμοποιώντας το ακόλουθο for : H τυπική μορφή ενός for που περνάει από κάθε στοιχείο του πίνακα με την σειρά είναι: for (int i = 0; i < array.length; i++) { Operations involving the i th element of the array } Με το length να επιστρέφει τον αριθμό των στοιχείων.

10 /** * Calculates the sum of an integer array. * @param array An array of integers * @return The sum of the values in the array */ private int sumArray(int[] array) { int sum = 0; for (int i = 0; i < array.length; i++) { sum += array[i]; } return sum; } Άσκηση: Αθροίζοντας ένα πίνακα Γράψτε μια μέθοδο sumArray που παίρνει ένα πίνακα ακεραίων και επιστρέφει το άθροισμα των τιμών τους.

11 Πίνακες αναζήτησης σταθερών Μία από τις πιο κοινές εφαρμογές της αρχικοποίησης πίνακα είναι η δημιουργία πινάκων σταθερών για την αναζήτηση μιας τιμής με βάση ένα δείκτη. Τέτοιοι πίνακες ονομάζονται πίνακες αναζήτησης. private static String[] MONTH_NAMES = { null /* Included because there is no month #0 */, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; Έτσι, μπορείτε να χρησιμοποιήσετε την έκφραση MONTH_NAMES[month] για την μετατροπή ενός αριθμητικού μήνα στο όνομά του. Για παράδειγμα, υποθέστε τους ακέραιους 1 έως 12 ως αναπαράσταση των ονομάτων των μηνών (Ιαν. έως Δεκ.). Μπορείτε εύκολα να μετατρέψετε τους ακέραιους στον αντίστοιχο μήνα, δηλώνοντας τον ακόλουθο πίνακα:

12 Αλλαγή διαστήματος τιμών δεικτών Tο γεγονός ότι η Java ξεκινά την αρίθμηση δεικτών από το 0 μπορεί να προκαλέσει σύγχυση. Ειδικότερα, συχνά οι μη- προγραμματιστές χρήστες είναι προτιμότερο να εργάζονται με αριθμούς ευρετηρίου που αρχίζουν με 1. Υπάρχουν δύο τυπικές προσεγγίσεις για τη μετατροπή αριθμών ευρετηρίου μεταξύ Java και ανθρώπινων: Χρησιμοποιήστε εσωτερικά τους αριθμούς ευρετηρίου της Java και στη συνέχεια προσθέστε 1 κάθε φορά που οι αριθμοί παρουσιάζονται στον χρήστη. 1. Χρησιμοποιήστε τιμές δείκτη που αρχίζουν στο 1 αγνοώντας το στοιχείο 0. Η στρατηγική αυτή απαιτεί την κατανομή ενός επιπλέον στοιχείου σε κάθε πίνακα, αλλά έχει το πλεονέκτημα ότι οι εσωτερικοί και εξωτερικοί αριθμοί ευρετηρίου είναι ίδιοι. 2.

13 Πίνακες και γραφικά Πίνακες συναντάμε συχνά στο γραφικό προγραμματισμό. Κάθε φορά που έχετε επαναλαμβανόμενες συλλογές παρόμοιων αντικείμενων, ο πίνακας είναι μια βολική δομή για την αποθήκευση τους. Ως παράδειγμα της χρήσης των πινάκων και της δυνατότητας δημιουργίας δυναμικών εικόνων χρησιμοποιώντας μόνο ευθείες γραμμές, το πρόγραμμα YarnPattern, προσομοιώνει την ακόλουθη διαδικασία : –Τοποθετεί στύλους σε ίσα διαστήματα σε ένα ορθογώνιο πλαίσιο. –Δένει ένα χρωματιστό νήμα στον στύλο στην επάνω αριστερή γωνία. –Δέστε το νήμα γύρω από ένα στύλο μια ορισμένη απόσταση DELTA –Συνεχίστε μετακινούμενοι DELTA στύλους μέχρι το τέλος.

14 Ένα μεγαλύτερο δείγμα εκτέλεσης YarnPattern

15 import acm.graphics.*; import acm.program.*; import java.awt.*; /** * This program creates a pattern that simulates the process of * winding a piece of colored yarn around an array of pegs along * the edges of the canvas. */ public class YarnPattern extends GraphicsProgram { public void run() { initPegArray(); int thisPeg = 0; int nextPeg = -1; while (thisPeg != 0 || nextPeg == -1) { nextPeg = (thisPeg + DELTA) % N_PEGS; GPoint p0 = pegs[thisPeg]; GPoint p1 = pegs[nextPeg]; GLine line = new GLine(p0.getX(), p0.getY(), p1.getX(), p1.getY()); line.setColor(Color.MAGENTA); add(line); thisPeg = nextPeg; } Το YarnPattern Program skip code page 1 of 2

16 import acm.graphics.*; import acm.program.*; import java.awt.*; /** * This program creates a pattern that simulates the process of * winding a piece of colored yarn around an array of pegs along * the edges of the canvas. */ public class YarnPattern extends GraphicsProgram { public void run() { initPegArray(); int thisPeg = 0; int nextPeg = -1; while (thisPeg != 0 || nextPeg == -1) { nextPeg = (thisPeg + DELTA) % N_PEGS; GPoint p0 = pegs[thisPeg]; GPoint p1 = pegs[nextPeg]; GLine line = new GLine(p0.getX(), p0.getY(), p1.getX(), p1.getY()); line.setColor(Color.MAGENTA); add(line); thisPeg = nextPeg; } /* Initializes the array of pegs */ private void initPegArray() { int pegIndex = 0; for (int i = 0; i < N_ACROSS; i++) { pegs[pegIndex++] = new GPoint(i * PEG_SEP, 0); } for (int i = 0; i < N_DOWN; i++) { pegs[pegIndex++] = new GPoint(N_ACROSS * PEG_SEP, i * PEG_SEP); } for (int i = N_ACROSS; i > 0; i--) { pegs[pegIndex++] = new GPoint(i * PEG_SEP, N_DOWN * PEG_SEP); } for (int i = N_DOWN; i > 0; i--) { pegs[pegIndex++] = new GPoint(0, i * PEG_SEP); } /* Private constants */ private static final int DELTA = 67; /* How many pegs to advance */ private static final int PEG_SEP = 10; /* Pixels separating each peg */ private static final int N_ACROSS = 50; /* Pegs across (minus a corner) */ private static final int N_DOWN = 30; /* Pegs down (minus a corner) */ private static final int N_PEGS = 2 * N_ACROSS + 2 * N_DOWN; /* Private instance variables */ private GPoint[] pegs = new GPoint[N_PEGS]; } Tο YarnPattern Program page 2 of 2

17 Μια παράκαμψη για τα ++ και -- pegs[pegIndex++] = new GPoint( x, y ); Το πρόγραμμα YarnPattern επιδεικνύει μια νέα μορφή του ++ σε εντολές της παρακάτω μορφής: Η έκφραση pegIndex++ προσθέτει 1 στο pegIndex όπως έκανε πάντα. Το ερώτημα είναι ποια τιμή χρησιμοποιείται ως δείκτης, που εξαρτάται από το πού εμφανίζεται το ++ –Αν το ++ βρίσκεται μετά τη μεταβλητή, αυτή αυξάνει αφού γίνει η αποτίμηση της έκφρασης. Στο παράδειγμα η έκφραση pegs[pegIndex++] επιλέγει το στοιχείο του πίνακα στην τρέχουσα αξία της pegIndex και μετά προσθέτει 1 στην pegIndex, που μετακινεί τον δείκτη στην επόμενη θέση. –Εάν το ++ βρίσκεται πριν τη μεταβλητή, η μεταβλητή αυξάνεται πρώτα και η νέα τιμή χρησιμοποιείται στην περιβάλλοντα δομή. Ο τελεστής -- συμπεριφέρεται παρόμοια, με διαφορά ότι αφαιρεί μία μονάδα από τη μεταβλητή.

18 Εσωτερική Αναπαράσταση Πινάκων Οι πίνακες στην Java υλοποιούνται ως αντικείμενα, πράγμα που σημαίνει ότι αποθηκεύονται στο σωρό. Η τιμή που είναι αποθηκευμένη σε μια μεταβλητή πίνακα είναι απλώς μια αναφορά στον πραγματικό πίνακα. double[] scores = new double[5]; Σκεφτείτε, για παράδειγμα, την ακόλουθη δήλωση : stack 1000 scores FFFC H μεταβλητή scores αποθηκεύεται στη στοίβα και της ανατίθεται η διεύθυνση ενός νέου πίνακα στο σωρό: heap 5 length 1004 1000 0.0 scores[0] 1008 0.0 scores[1] 1010 0.0 scores[2] 1018 0.0 scores[3] 1020 0.0 scores[4] 1028

19 Περνώντας πίνακες ως παραμέτρους Όταν περνάτε ένα πίνακα ως παράμετρο σε μια μέθοδο μόνο η αναφορά περνά ως όρισμα. Αυτό έχει ως αποτέλεσμα τα στοιχεία του πίνακα να διαμοιράζονται μεταξύ του καλούντος και του καλούμενου. Αν μια μέθοδος αλλάζει ένα στοιχείο ενός πίνακα, η αλλαγή θα παραμείνει και μετά τον τερματισμό της.

20 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Τι εμφανίζεται; } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 }

21 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Τι εμφανίζεται; } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 } Πλαίσιο εκτέλεσης της run x int

22 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Τι εμφανίζεται; } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 } Πλαίσιο εκτέλεσης της run x int 1

23 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Τι εμφανίζεται; } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 } Πλαίσιο εκτέλεσης της run x int 1 Πλαίσιο εκτέλεσης της incr a int 1

24 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Τι εμφανίζεται; } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 } Πλαίσιο εκτέλεσης της run x int 1 Πλαίσιο εκτέλεσης της incr a int 2

25 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Εμφανίζει 1 } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 } Πλαίσιο εκτέλεσης της run x int 1

26 Πίνακες ως παράμετροι συναρτήσεων public void run() { int x = 1; incr(x); println(x); //Εμφανίζει 1 } void incr(int a) { // Η a έχει την τιμή της x, δεν είναι η x a++; //Αυξάνεται η τιμή της a, όχι αυτή της x println(a); // Εμφανίζει 2 }

27 Πίνακες ως παράμετροι συναρτήσεων Κάθε κλήση συνάρτησης αντιγράφει τις τιμές των ορισμάτων στις αντίστοιχες μεταβλητές του νέου πλαίσιου εκτέλεσης. Χρονοβόρο εάν το όρισμα είναι μεγάλος πίνακας αφού θα πρέπει να αντιγραφούν οι τιμές όλων των στοιχείων. Τρόπος αποφυγής αντιγραφής στοιχείων: στη JAVA οι πίνακες υλοποιούνται ως αναφορές στα στοιχεία του πίνακα – δεν είναι τα ίδια τα στοιχεία.

28 Αναφορές int[] a = {1, 4, 2, -9, 33}; println(a); // Τι θα εμφανιστεί; Όχι τα στοιχεία του πίνακα! Η τιμή της μεταβλητής a δεν είναι τα στοιχεία του πίνακα Η a έχει τύπο αναφορά σε στοιχεία πίνακα int int[] σημαίνει αναφορά στα στοιχεία του πίνακα

29 int[] a = new int[5]; Αναφορές

30 int[] a = new int[5]; Αναφορές a int[]

31 int[] a = new int[5]; Αναφορές int 0 0 0 0 0 a int[]

32 int[] a = new int[5]; Αναφορές a int[] int 0 0 0 0 0

33 int[] a = new int[5]; a[2] = 2011; Αναφορές a int[] int 0 0 0 0 0

34 int[] a = new int[5]; a[2] = 2011; Αναφορές a int[] int 0 0 0 0 0

35 int[] a = new int[5]; a[2] = 2011; Αναφορές a int[] int 0 0 2011 0 0 int

36 int[] a = {1, 4, 2}; int[] b; b = a; b[2] = 3; println(a[2]); Αναφορές

37 int[] a = {1, 4, 2}; int[] b; b = a; b[2] = 3; println(a[2]); Αναφορές a int[] int 1 4 2

38 int[] a = {1, 4, 2}; int[] b; b = a; b[2] = 3; println(a[2]); b int[] Αναφορές a int[] int 1 4 2

39 int[] a = {1, 4, 2}; int[] b; b = a; b[2] = 3; println(a[2]); b int[] Αναφορές a int[] int 1 4 2

40 int[] a = {1, 4, 2}; int[] b; b = a; b[2] = 3; println(a[2]); b int[] Αναφορές a int[] int 1 4 3

41 int[] a = {1, 4, 2}; int[] b; b = a; b[2] = 3; println(a[2]); b int[] Αναφορές a int[] int 1 4 3

42 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5

43 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5

44 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

45 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 0 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

46 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 1 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

47 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 1 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

48 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 2 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

49 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 2 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

50 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 3 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

51 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 3 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

52 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 4 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

53 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 4 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

54 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Πλαίσιο εκτέλεσης της run a int[] int 2 7 4 9 -5 Πλαίσιο εκτέλεσης της printArray a int[] i int 5 Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

55 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] a = {2, 7, 4, 9, -5}; printArray(a); } void printArray(int[] a) { for ( int i = 0; i < a.length; i++ ) println(a[i]); } Με τη χρήση αναφορών, αντιγράφεται η αναφορά και όχι τα ίδια τα στοιχεία του πίνακα!

56 Πίνακες ως παράμετροι συναρτήσεων public void run() { int[] x = {1, -1}; incr(x); println(x[0]); // Τι εμφανίζεται; } void incr(int[] a) { //Ο a αναφέρεται στα στοιχεία του πίνακα x, όχι σε κάποιο αντίγραφο του a[0]++; //Αυξάνεται το x[0] println(a[0]); }

57 Αντίγραφο πίνακα Πως αντιγράφουμε τα στοιχεία ενός πίνακα; int[] a = {1, 4, 2}; int[] b; b = copyArray(a); //Φτιάχνει πίνακα αντίγραφο b[2] = 3; println(a[2]); // Εμφανίζει 2

58 Αντίγραφο πίνακα int[] copyArray(int[] original) { int[] copy = new int[original.length]; for ( int i = 0; i < original.length; i++ ) copy[i] = original[i]; return copy; // επιστρέφει αναφορά στα νέα στοιχεία }

59 Αντίγραφο πίνακα original int[] int 1 4 2 copy int[]

60 Αντίγραφο πίνακα original int[] int 1 4 2 0 0 0 copy int[]

61 Αντίγραφο πίνακα original int[] int 1 4 2 0 0 0 copy int[]

62 Αντίγραφο πίνακα original int[] int 1 4 2 1 0 0 copy int[]

63 Αντίγραφο πίνακα original int[] int 1 4 2 1 4 0 copy int[]

64 Αντίγραφο πίνακα original int[] int 1 4 2 1 4 2 copy int[]

65 Αντιμετάθεση στοιχείων void swap(int[] a, int i, int j) { int tmp; // προσωρινή μεταβλητή tmp = a[i]; a[i] = a[j]; a[j] = tmp; } 2 int 7 a[i] a[j] tmp

66 Αντιμετάθεση στοιχείων void swap(int[] a, int i, int j) { int tmp; // προσωρινή μεταβλητή tmp = a[i]; a[i] = a[j]; a[j] = tmp; } 2 int 7 2 a[i] a[j] tmp

67 Αντιμετάθεση στοιχείων void swap(int[] a, int i, int j) { int tmp; // προσωρινή μεταβλητή tmp = a[i]; a[i] = a[j]; a[j] = tmp; } 7 int 7 2 a[i] a[j] tmp

68 Αντιμετάθεση στοιχείων void swap(int[] a, int i, int j) { int tmp; // προσωρινή μεταβλητή tmp = a[i]; a[i] = a[j]; a[j] = tmp; } 7 int 2 2 a[i] a[j] tmp

69 Πίνακες ως τιμή συνάρτησης String[] union(String[] a, String[] b) { String[] c = new String[a.length+b.length]; for ( int i = 0; i < a.length; i++ ) c[i] = a[i]; for ( int i = 0; i < b.length; i++ ) c[a.length+i] = b[i]; return c; // Επιστρέφει συγκόλληση των a και b }

70 To Πρόγραμμα ReverseArray Η επόμενη διαφάνεια περιέχει μια προσομοίωση ενός προγράμματος που εκτελεί τις ακόλουθες ενέργειες: Φτιάχνει έναν πίνακα που περιέχει ακέραιους 0 ως N-1.1. Εκτυπώνει τα στοιχεία του πίνακα.2. Αντιστρέφει τα στοιχεία του πίνακα.3. Εκτυπώνει τα αντεστραμμένα στοιχεία στην κονσόλα.4.

71 To Πρόγραμμα ReverseArray skip simulation public void run() { int n = readInt("Enter number of elements: "); int[] intArray = createIndexArray(n); println("Forward: " + arrayToString(intArray)); reverseArray(intArray); println("Reverse: " + arrayToString(intArray)); } n 10 intArray ReverseArray Enter number of elements: 10 Forward: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Reverse: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] private int[] createIndexArray(int n) { int[] array = new int[n]; for ( int i = 0; i < n; i++ ) { array[i] = i; } return array; } 10 narrayi 012345678910 012345678 0000000000 9 0 9 1 8 2 7 3 6 4 5 5 4 6 3 7 2 8 1 9 0 private String arrayToString(int[] array) { String str = ""; for (int i = 0; i < array.length; i++) { if (i > 0) str += ", "; str += array[i]; } return "[" + str + "]"; } arrayistr 012345678910 00, 10, 1, 20, 1, 2, 30, 1, 2, 3, 40, 1, 2, 3, 4, 50, 1, 2, 3, 4, 5, 60, 1, 2, 3, 4, 5, 6, 70, 1, 2, 3, 4, 5, 6, 7, 80, 1, 2, 3, 4, 5, 6, 7, 8, 9 private void reverseArray(int[] array) { for (int i = 0; i < array.length / 2; i++) { swapElements(array, i, array.length - i - 1); } arrayi 012345 private void swapElements(int[] array, int p1, int p2) { int temp = array[p1]; array[p1] = array[p2]; array[p2] = temp; } array 9 p2 0 p1temp 0 public void run() { int n = readInt("Enter number of elements: "); int[] intArray = createIndexArray(n); println("Forward: " + arrayToString(intArray)); reverseArray(intArray); println("Reverse: " + arrayToString(intArray)); } nintArray 012345678 9876543210 9 0 10

72 Πίνακες και Πινακοποίηση Οι πίνακες αποδεικνύονται χρήσιμοι όταν έχετε ένα σύνολο τιμών και πρέπει να μετρήσετε πόσες εμπίπτουν σε κάθε ένα από ένα εύρος τιμών. Αυτή η διαδικασία ονομάζεται Πινακοποίηση. Μετρήστε πόσες φορές κάθε ένα από τα 26 γράμματα εμφανίζεται σε μια σειρά από γραμμές κειμένου. Ένα τέτοιο πρόγραμμα θα ήταν πολύ χρήσιμο για την επίλυση κωδικοποιήσεων και αλγόριθμων κρυπτογράφησης, όπως περιγράφεται στην επόμενη διαφάνεια. Η πινακοποίηση χρησιμοποιεί πίνακες με έναν ελαφρώς διαφορετικό τρόπο από τις εφαρμογές που τους χρησιμοποιούν για να αποθηκεύσουν μια λίστα στοιχείων. Όταν φτιάχνετε ένα πρόγραμμα πινακοποίησης, χρησιμοποιήτε τις τιμές δεδομένων για τον υπολογισμό ενός δείκτη σε έναν πίνακα ακεραίων που παρακολουθεί πόσες τιμές εμπίπτουν σε κάθε κατηγορία.

73 Κρυπτογραφήματα Ένα κρυπτογράφημα είναι ένας γρίφος στον οποίο ένα μήνυμα κωδικοποιείται με την αντικατάσταση κάθε γράμματος του αρχικού κείμενου με κάποιο άλλο γράμμα. Το σχέδιο υποκατάστασης παραμένει η ίδια καθ 'όλη τη δημιουργία του μηνύματος. Η δουλειά σας είναι να καταλάβετε αυτήν την αλληλογραφία. Αντί του υπολογισμού των χαρακτήρων με το χέρι, θα ήταν ευκολότερο εάν είχατε ένα πρόγραμμα για αυτή τη δουλειά. Πληκτρολογείτε το κωδικοποιημένο μήνυμα, και λαμβάνετε ένα πίνακα με το πόσο συχνά εμφανίζεται κάθε γράμμα. Η συνήθης στρατηγική για την επίλυση του είναι να υποθέσουμε ότι τα πιο κοινά γράμματα στο κωδικοποιημένο μήνυμα αντιστοιχούν στα πιο κοινά γράμματα στα αγγλικά, τα οποία είναι τα E, T, A, O, I, N, S, H, R, D, L, και U.

74 Υλοποίηση στρατηγικής 012345678910111213141516171819202122232425 Η βασική ιδέα εδώ είναι να χρησιμοποιήσετε έναν πίνακα με 26 στοιχεία για να παρακολουθείτε πόσες φορές εμφανίζεται κάθε γράμμα. Καθόσον το πρόγραμμα διαβάζει το κείμενο, θα αυξάνει το στοιχείο του πίνακα που αντιστοιχεί σε κάθε γράμμα. 00000000000000000000000000 TWASBRILLIG 1 1 1 1 11 1 1 1 2 2

75 import acm.program.*; /** * This program creates a table of the letter frequencies in a * paragraph of input text terminated by a blank line. */ public class CountLetterFrequencies extends ConsoleProgram { public void run() { println("This program counts letter frequencies."); println("Enter a blank line to indicate the end of the text."); initFrequencyTable(); while (true) { String line = readLine(); if (line.length() == 0) break; countLetterFrequencies(line); } printFrequencyTable(); } /* Initializes the frequency table to contain zeros */ private void initFrequencyTable() { frequencyTable = new int[26]; for (int i = 0; i < 26; i++) { frequencyTable[i] = 0; } skip code page 1 of 2 CountLetterFrequencies

76 import acm.program.*; /** * This program creates a table of the letter frequencies in a * paragraph of input text terminated by a blank line. */ public class CountLetterFrequencies extends ConsoleProgram { public void run() { println("This program counts letter frequencies."); println("Enter a blank line to indicate the end of the text."); initFrequencyTable(); while (true) { String line = readLine(); if (line.length() == 0) break; countLetterFrequencies(line); } printFrequencyTable(); } /* Initializes the frequency table to contain zeros */ private void initFrequencyTable() { frequencyTable = new int[26]; for (int i = 0; i < 26; i++) { frequencyTable[i] = 0; } /* Counts the letter frequencies in a line of text */ private void countLetterFrequencies(String line) { for (int i = 0; i < line.length(); i++) { char ch = line.charAt(i); if (Character.isLetter(ch)) { int index = Character.toUpperCase(ch) - 'A'; frequencyTable[index]++; } /* Displays the frequency table */ private void printFrequencyTable() { for (char ch = 'A'; ch <= 'Z'; ch++) { int index = ch - 'A'; println(ch + ": " + frequencyTable[index]); } /* Private instance variables */ private int[] frequencyTable; } CountLetterFrequencies skip code page 2 of 2

77 Πολυδιάστατοι πίνακες Επειδή τα στοιχεία ενός πίνακα στην Java μπορεί να είναι οποιουδήποτε τύπου, μπορεί να είναι τα ίδια πίνακες. Οι πίνακες πινάκων λέγονται πολυδιάστατοι πίνακες. Στην Java, μπορείτε να δημιουργήσετε ένα πολυδιάστατο πίνακα με τη χρήση πολλαπλών αγκυλών τόσο στον τύπο όσο και στην δήλωσης αρχικοποίησης. Π.χ. μπορείτε να δημιουργήσετε έναν πίνακα για τρίλιζα, χρησιμοποιώντας την δήλωση: char[][] board = new char[3][3]; Η δήλωση αυτή δημιουργεί ένα δισδιάστατο πίνακα χαρακτήρων που είναι οργανωμένος έτσι: board[0][0]board[0][1]board[0][2] board[1][0]board[1][1]board[1][2] board[2][0]board[2][1]board[2][2]

78 Αρχικοποίηση τιμών int[][] array = { {1,2,3}, {4,5,6}}; Ή εναλλακτικά ως εξής: int[][] array = new int[2][3]; for ( int i = 0; i < 2; i++ ) for ( int j = 0; j < 3; j++ ) a[i][j] = 3*i+j+1;

79 int[][] a = new int[2][5]; Αναφορές σε πολυδιάστατους πίνακες

80 int[][] a = new int[2][5]; Αναφορές σε πολυδιάστατους πίνακες a int[][]

81 int[][] a = new int[2][5]; Αναφορές σε πολυδιάστατους πίνακες a int[][] int 0 0 0 0 0 0 0 0 0 0 int[]

82 int[][] a = new int[2][5]; Αναφορές σε πολυδιάστατους πίνακες a int[][] int 0 0 0 0 0 0 0 0 0 0 int[]

83 int[][] a = new int[2][5]; a[1][3] = 999; Αναφορές σε πολυδιάστατους πίνακες a int[][] int 0 0 0 0 0 0 0 0 0 0 int[]

84 int[][] a = new int[2][5]; a[1][3] = 999; Αναφορές σε πολυδιάστατους πίνακες a int[][] int 0 0 0 0 0 0 0 0 0 0 int[]

85 int[][] a = new int[2][5]; a[1][3] = 999; Αναφορές σε πολυδιάστατους πίνακες a int[][] int 0 0 0 0 0 0 0 0 0 0 int[]

86 int[][] a = new int[2][5]; a[1][3] = 999; Αναφορές σε πολυδιάστατους πίνακες a int[][] int 0 0 0 0 0 0 0 0 999 0 int int[]

87 Εμφάνιση στοιχείων πινάκων 2 διαστάσεων void printArray(int[][] a) { for ( int i = 0; i < a.length; i++ ) { for ( int j = 0; j < a[i].length; j++ ) print(a[i][j]+” ”); println(); }

88 Πολλαπλασιασμός μαθηματικών πινάκων int[][] multiply(int[][] A, int[][] B) { int nA = A.length; int mA = A[0].length; int nB = B.length; int mB = B[0].length; int[][] C = new int[nA][mB]; for ( int i = 0; i < nA; i++ ) for ( int j = 0; j < mB; j++ ) for ( int k = 0; k < mA; k++ ) C[i][j] += A[i][k]*B[k][j]; return C; }

89 int[][] a = new int[2][]; Πίνακες με διαφορετικό αριθμό στηλών a int[][] int[]

90 int[][] a = new int[2][]; a[0] = new int[5]; Πίνακες με διαφορετικό αριθμό στηλών a int[][] int 0 0 0 0 0 int[]

91 int[][] a = new int[2][]; a[0] = new int[5]; a[1] = new int[3]; Πίνακες με διαφορετικό αριθμό στηλών a int[][] int 0 0 0 0 0 0 0 0 int[]

92 int[][] a = new int[2][]; a[0] = new int[5]; a[1] = new int[3]; for … Πίνακες με διαφορετικό αριθμό στηλών a int[][] int 1 2 3 4 5 5 6 7 int[]

93 Πίνακες με διαφορετικό αριθμό στηλών int[][] a = new int[2][]; a[0] = new int[5]; a[1] = new int[3]; for ( int i = 0, k = 0; i < a.length; k += a[i].length, i++ ) for ( int j = 0; j < a[i].length; j++ ) a[i][j] = i == 0 ? j+1: k+j+1; printArray(a);

94 Πίνακες με διαφορετικό αριθμό στηλών Γίνεται και απευθείας: int[][] a = {{1, 2, 3, 4, 5}, {6, 7, 8}}; printArray(a);

95 Περισσότερες διαστάσεις; Πίνακας τριών διαστάσεων 6×5×3 int[][][] a = new int[6][][]; for ( int i = 0; i < a.length; i++ ) a[i] = new int[5][3]; // πίνακας 2 διαστάσεων Παρόμοια για διαστάσεις > 3

96 Αρχικοποίηση πολυδιάστατων πινάκων Παρατηρήστε ότι μπορείτε να αρχικοποιείτε ένα πολυδιάστατο πίνακα κατά την δήλωση χρησιμοποιώντας ένθετα άγκιστρα που αντανακλούν τα επίπεδα του πίνακα. Για παράδειγμα, μπορείτε να δηλώσετε και να αρχικοποιήσετε ένα πίνακα προπαιδείας για τα ψηφία 0 έως 9, όπως εδω: private static int[][] MULTIPLICATION_TABLE = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 }, { 0, 3, 6, 9, 12, 15, 18, 21, 24, 27 }, { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36 }, { 0, 5, 10, 15, 20, 25, 30, 35, 40, 45 }, { 0, 6, 12, 18, 24, 30, 36, 42, 48, 56 }, { 0, 7, 14, 21, 28, 35, 42, 49, 56, 63 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72 }, { 0, 9, 18, 27, 36, 45, 54, 63, 72, 81 } };

97 Άσκηση: Πολυδιάστατοι πίνακες Γράψτε μια δήλωση Java που να δηλώνει και να αρχικοποιεί ένα δισδιάστατο πίνακα που ονομάζεται chessboard έτσι ώστε να περιέχει μια αναπαράσταση της αρχικής θέσης σε ένα παιχνίδι σκάκι: Τα επιμέρους στοιχεία θα πρέπει να είναι χαρακτήρες χρησιμοποιώντας τα τυποποιημένα σύμβολα για τα κομμάτια :

98 Λύση: Το πρόβλημα σκακιέρας private char[][] chessboard = { { 'r', 'n', 'b', 'q', 'k', 'b', 'n', 'r' }, { 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' }, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, { 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P' }, { 'R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R' }, };

99 H τάξη ArrayList Παρότι οι πίνακες είναι σημαντικοί ως δομή δεδομένων, δεν χρησιμοποιούνται τόσο πολύ στη Java, όσο στις περισσότερες άλλες γλώσσες. Ο λόγος είναι ότι το πακέτο java.util περιέχει μια τάξη που ονομάζεται ArrayList που παρέχει την συμπεριφορά πίνακα μαζί με άλλες χρήσιμες λειτουργίες. Οι κύριες διαφορές μεταξύ πινάκων και ArrayList προέρχονται από το γεγονός ότι η ArrayList είναι τάξη και όχι χαρακτηριστικό της γλώσσας. Έτσι όλες οι πράξεις στην ArrayList γίνονται με την κλήση μεθόδων. Οι πιο εμφανείς διάφορες είναι: –Δημιουργείτε μια ArrayList καλώντας τον κατασκευαστή της. –Μαθαίνετε το πλήθος των στοιχείων μέσω την μεθόδου size αντί τις ιδιότητας length. –Χρησιμοποιείτε τις μεθόδους get και set για τα περιεχόμενα. Η επόμενη διαφάνεια συνοψίζει τις πιο σημαντικές μεθόδους της ArrayList. O συμβολισμός δηλώνει τον βασικό τύπο.

100 Μέθοδοι της ArrayList boolean add( element) Προσθέτει ένα νέο στοιχείο στο τέλος της ArrayList ; η τιμή επιστροφής είναι πάντα true. void add(int index, element) Προσθέτει ένα νέο στοιχείο στην ArrayList πριν την θέση που καθορίζεται από το index. remove(int index) Καταργεί το στοιχείο στην καθορισμένη θέση και επιστρέφει την τιμή του. boolean remove( element) Καταργεί την πρώτη εμφάνιση του element, αν υπαρχει; επιστρέφει true αν βρέθηκε void clear() Αφαιρεί όλα τα στοιχεία από το ArrayList. int size() Επιστρέφει τον αριθμό των στοιχείων στην ArrayList. get(int index) Επιστρέφει το αντικείμενο στη συγκεκριμένη θέση. set(int index, value) Θέτει την τιμή του στοιχείου στο συγκεκριμένο δείκτη και επιστρέφει την παλιά τιμή. int indexOf( value) Επιστρέφει το δείκτη της πρώτης εμφάνισης της καθορισμένης τιμής, ή -1 εάν δεν βρέθει. boolean contains( value) Επιστρέφει true αν η ArrayList περιέχει την καθορισμένη τιμή. boolean isEmpty() Επιστρέφει true αν η ArrayList δεν περιχέει στοιχεία.

101 Γενικοί τύποι στη Java 5.0 Ο συμβολισμός που χρησιμοποιείται στο προηγούμενο slide είναι ένα χαρακτηριστικό της Java, που εισήχθη sτην έκδοση 5.0. Στις περιγραφές των μεθόδων, ο συμβολισμός είναι ένα σύμβολο κράτησης θέσης για τον τύπο στοιχείου που χρησιμοποιείται στον πίνακα. Οι ορισμοί της τάξης που περιλαμβάνουν μια παράμετρο τύπου ονομάζεται γενικοί τύποι Το πλεονέκτημα της διευκρίνισης του τύπου των στοιχείων είναι ότι η Java ξέρει πλέον το είδος των περιεχομένων της ArrayList. Όταν καλείτε την set, η Java εξασφαλίζει ότι η τιμή ταιριάζει με τον τύπο του στοιχείου. Όταν καλείτε την get, η Java γνωρίζει τι είδους αξία περιμένει. Για παράδειγμα, για να δηλώσετε και να αρχικοποιήσετε ένα ArrayList με όνομα names που περιέχει String, θα γράφατε ArrayList names = new ArrayList ();

102 Πλαισίωση και Αποπλαισίωση Οι Γενικοί τύποι ωφελούνται σημαντικά από την τεχνική της πλαισίωσης και αποπλαισίωσης, που είχαμε συζητήσει στις διαφάνειες για Αντικείμενα και Μνήμη. Από την έκδοση 5.0 η Java μετατρέπει αυτόματα τις τιμές μεταξύ του στοιχειώδους τύπου και της αντίστοιχης τάξης. Αυτό το χαρακτηριστικό καθιστά δυνατή την αποθήκευση στοιχειωδών τιμών σε μια ArrayList, παρότι τα στοιχεία μιας ArrayList πρέπει να είναι τάξεις. Στη δεύτερη δήλωση, η Java χρησιμοποιεί πλαισίωση για να εισαγάγει το 42 σε ένα αντικείμενο τύπου Integer. Όταν η Java εκτελεί την τρίτη δήλωση, γίνεται αποπλαισίωση του Integer για να ληφθεί ο int. ArrayList list = new ArrayList (); list.add(42); int answer = list.get(0); Π.χ. υποθέστε ότι εκτελείτε τις ακόλουθες γραμμές:

103 Διάβασμα για το σπίτι Κεφάλαιο 11 εκτός της ενότητας 11.7 από «Η Τέχνη και Επιστήμη της JAVA: Μια εισαγωγή στην Επιστήμη των Υπολογιστών», E. Roberts


Κατέβασμα ppt "Εισαγωγή στον Προγ/μό Η/Υ Ενότητα 10: Πίνακες Διδάσκων: Μιχάλης Τίτσιας."

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google