Προγραμματισμός ΙΙ: Έλεγχος Ροής και Επαναλήψεις

Προγραμματισμός ΙΙ
Έλεγχος ροής προγράμματος
Συνθήκες
- Μια συνθήκη είναι μια λογική καλώς συντεταγμένη έκφραση η οποία μπορεί να εκτιμηθεί
μονοσήμαντα είτε ως αληθής είτε ως ψευδής.
- Με τη βοήθεια συνθηκών μπορούμε να ελέγξουμε τη ροή ενός προγράμματος καθώς και
να επαναλάβουμε ρουτίνες.
- Φυσικά κάθε boolean μεταβλητή, από μόνη της, είναι μια συνθήκη.
- Μπορούμε να δημιουργήσουμε συνθήκες απο μη boolean μεταβλητές με τη βοήθεια
συγκριτικών τελεστών (παρακάτω).
- Μπορούμε να παράγουμε σύνθετες συνθήκες από πιο απλές με τη βοήθεια των λογικών
τελεστών (παρακάτω).
Συγκρισιακοί τελεστές.
- Οι "φυσικοί" συγκρισιακοί τελεστές στην Java είναι οι εξής:
> |
μεγαλύτερο |
>= |
μεγαλύτερο ή ίσο |
< |
μικρότερο |
<= |
μικρότερο ή ίσο |
== |
ίσο |
!= |
διάφορο |
- Επίσης, μπορούν να φτιαχτούν από τον χρήστη δικοί του συγκρισιακοί τελεστές
ανάλογα με τις ανάγκες του.
Λογικοί τελεστές.
- Οι βασικοί λογικοί τελεστές && ("και"), || ("ή") και ! ("όχι/δεν") είναι χρήσιμοι
για να κατασκευάσουμε σύνθετες συνθήκες από άλλες απλούστερες.
| boolean x | boolean y | x && y | x || y | | boolean x | !x |
|-----------|-----------|--------|--------| |-----------|-------|
| true | true | true | true | | true | false |
| true | false | false | true | | true | true |
| false | true | false | true |
| false | false | false | false |
boolean x = true;
int y = 4, z = 5;
System.out.println(!x || ((y == z) || x));
if
- Με τη βοήθεια των "if" μπορούμε να εκτελέσουμε ένα κομμάτι κώδικα μόνο όταν
ικανοποιείται μια συγκεκριμένη συνθήκη. Η δομή της "if" είναι η ακόλουθη:
if (συνθήκη) {
// σώμα κώδικα
}
Παράδειγμα
int mark = 7;
if (mark >= 5) {
System.out.println("Student didn't fail the exams");
}
if/else
Με το "if/else" μπορούμε να εκτελέσουμε ένα κομμάτι κώδικα μόνο όταν
ικανοποιείται μια συγκεκριμένη συνθήκη αλλιώς θα εκτελεστεί ενα διαφορετικό
κομμάτι κώδικα. Η δομή της "if/else" είναι η ακόλουθη:
if (συνθήκη) {
// σώμα κώδικα
} else {
// άλλο σώμα κώδικα
}
Παράδειγμα
int mark = 7;
if (mark >= 5) {
System.out.println("Student didn't fail the exams");
} else {
System.out.println("Student failed the exams");
}
if/elseif/else
- Με το "if/else if/else" μπορούμε να αντιστοιχίσουμε συγκεκριμένες συνθήκες
με συγκεκριμένα κομμάτια. Το κομμάτι κώδικα που θα εκτελεστεί θα είναι εκείνο του
οποίου η αντίστοιχη συνθήκη θα ικανοποιηθεί πρώτα. Η δομή είναι η ακόλουθη:
if (συνθήκη) {
// σώμα κώδικα
} else if (αλληΣυνθηκη) {
// άλλο σώμα κώδικα
} else if (καιΑλληΣυνθηκη) {
// κι αλλο σώμα κώδικα
} else {
// αν δεν ικανοποιηθεί καμία από τις παραπάνω συνθήκες σώμα κώδικα
}
Παράδειγμα
int mark = 7;
if (mark < 5) {
System.out.println("Student failed the exams");
} else if (mark >= 5 && mark < 8) {
System.out.println("Student is good");
} else { // equivalent with "else if (mark >= 8) {"
System.out.println("Student is excellent");
}
Παρατηρήσεις
- Σε μια "if/else if/else" μπορεί να ικανοποιούνται πολλές συνθήκες αλλά μόνο ο
κώδικας της πρώτης στη σειρά ικανοποιημένης συνθήκης θα εκτελεστεί. Στο παράδειγμα
μόνο το δεύτερο σώμα κώδικα θα εκτελεσθεί παρ' όλο που ικανοποιείται και η τρίτη
συνθήκη.
int mark = 7;
if (mark < 5) {
System.out.println("Student failed the exams");
} else if (mark < 8) {
System.out.println("Student is good");
} else if (mark <= 10) {
System.out.println("Student is excellent");
}
switch
- Σε περιπτώσεις που η συνθήκη που θα εξεταστεί είναι απλή και οι περιπτώσεις
είναι πολλές αντί να χρησιμοποιηθεί "if/else if/else", μπορεί να χρησιμοποιηθεί
η "switch". Η δομή της "switch" είναι η ακόλουθη:
switch (variable) {
case value1:
// σώμα 1
break;
case value2:
// σώμα 2
break;
default:
// σώμα 3
}
όπου εξετάζεται σε κάθε case αν "variable == value'i'".
παράδειγμα
int numOfAngles = 3;
switch (numOfAngles) {
case 3:
System.out.println("triangle");
break;
case 4:
System.out.println("rectangle");
break;
case 5:
System.out.println("pentagon");
break;
default:
System.out.println("Higher polygon");
}
Παρατηρήσεις
- Αν παραληφθεί το "break" σε μια ικανοποιημένη "case" τότε θα τρέξει και τον κώδικα
των επόμενων "case" μέχρι να βρει "break" ή να τελειώσει το switch. Στο προηγούμενο
παράδειγμα αν αφαιρεθεί το "break" στην "case 3" τότε θα τρέξει και τον κώδικα της
"case 4".
?:
- Σε περίπτωση που έχουμε μια σύντομη συνθήκη σε "if/else" με μικρό σώμα εντολών
μπορούμε να χρησιμοποιήσουμε "?:" με την ακόλουθη δομή:
συνθήκη ? εντολή 1 : εντολή 2;
που σημαίνει ότι αν ικανοποιείται η συνθήκη το πρόγραμμα θα τρέξει την "εντολή 1"
αλλιώς θα τρέξει την "εντολή 2"
for
- Συχνά στον προγραμματισμό υπάρχει η ανάγκη να γίνει μια επαναλαμβανόμενη
διαδικασία πάνω σε ένα σύνολο στοιχείων που ικανοποιούν κάποια συνθήκη.
- Η "for" επανάληψη είναι ένας από τους τρόπους, όπου η Java, δίνει τη δυνατότητα σε
κάποιο χρήστη να χειρίζεται τέτοιες επαναλαμβανόμενες διαδικασίες. Η δομή της
"for" επανάληψης είναι η ακόλουθη:
for (αρχικοποίηση; συνθήκη; μεταβολή) {
// κώδικας
}
for(2)
- Η 'αρχικοποίηση' είναι μια δέσμη εντολών η οποία τρέχει μια φορά αμέσως πριν
αρχίσει η επανάληψη. Συνήθως στην 'αρχικοποίηση' υπάρχει μόνο μια αρχικοποίηση
κάποιου δείκτη.
- Η 'συνθήκη' εξετάζεται αν ικανοποιείται πριν από κάθε κύκλο (iteration) στην
επανάληψη σε μια 'for'. Όσο ικανοποιείται η 'συνθήκη' τότε ο κώδικας στο σώμα της
'for' θα εκτελείται. Αν κάποια στιγμή η 'συνθήκη' δεν ικανοποιηθεί τότε το σώμα
δε θα εκτελεστεί και το πρόγραμμα θα συνεχίσει στην πρώτη εντολή μετά την 'for'.
Παράδειγμα
// Άθροισμα στοιχείων ενός πίνακα για κάθε δεύτερο δείκτη του.
public static int calculateSumOfEvenIndexes(int[] array) {
int sum = 0;
for (int i = 1; i < array.length; i += 2) {
sum += array[i]; // sum = sum + array[i];
}
return sum;
}
while
- Ένας άλλος τρόπος για να χειριστεί κάποιος επαναλαμβανόμενες καταστάσεις στη
java είναι με τη χρήση της 'while' επανάληψης. Η δομή της 'while' είναι η εξής:
while (συνθήκη) {
// κώδικας
}
- Όπως και στη 'for' έτσι και στη 'while' η συνθήκη ελέγχεται πριν από κάθε
κύκλο στην επανάληψη και όσο ικανοποιείται εκτελείται ο κώδικας στο σώμα της.
Όταν σταματήσει να ικανοποιείται η συνθήκη για πρώτη φορά τότε το πρόγραμμα δεν
εκτελεί το σώμα της επανάληψης και μεταβαίνει στη πρώτη εντολή μετά από αυτήν.
Παράδειγμα
// Άθροισμα στοιχείων ενός πίνακα για κάθε δεύτερο δείκτη του.
public static int calculateSumOfEvenIndexes(int[] array) {
int sum = 0;
int index = 1;
while (index < array.length) {
sum += array[i];
index += 2;
}
return sum;
}
Άσκηση
- Να εξηγήσετε γιατί η επανάληψη 'for' και η επανάληψη 'while' είναι ισοδύναμες,
δηλαδή κάθε εργασία που μπορεί να γίνει με 'for' μπορεί να γίνει με 'while' και
ανάποδα.
do...while
- Ένας ακόμη τρόπος για την υλοποίηση επαναλαμβανόμενων διαδικασιών ειναι μέσω
της 'do...while'. Η δομή της 'do...while' είναι η εξής:
do {
// κώδικας
} while (συνθήκη);
- Σε αντίθεση με την 'while', στη 'do...while' η συνθήκη εξετάζεται αφού
εκτελεστεί ο κώδικας στο σώμα της. Αν ικανοποιήθει η συνθήκη τότε η επανάληψη
συνεχίζει, αλλιώς σταματάει και συνεχίζει το πρόγραμμα από την πρώτη εντολή μετά
από αυτή.
Άσκηση
- Να εξηγήσετε τις διαφορές 'while' με τη 'do...while'. Είναι ισοδύναμες;
Η ενισχυμένη for
- Συχνά θέλουμε να προσπελάσουμε όλα τα στοιχεία μιας συλλογής όπως κάποιος
πίνακας, ή κάποιο αντικείμενο της ArrayList κλάσης. Τότε η java προσφέρει ένα
κομψό τρόπο χωρίς τον ρητό ορισμό δεικτών ή συνθηκών στο μήκος της συλλογής.
Η δομή της ενισχυμένης 'for' είναι η εξής:
for (Τύπος μεταβλητή : συλλογή) {
// Κώδικας
}
Παρατηρήσεις
- Η 'συλλογή' αναφέρεται σε σύλλογη αντικειμένων που θα προσπελαστεί όπως ένας πίνακας ή ένα object της ArrayList.
- Ο 'Τύπος' αναφέρεται στον τύπο των στοιχείων που βρίσκονται μέσα στη συλλογή.
- Η 'μεταβλητή' αναφέρεται στο στοιχείο που προσπελαύνει εκείνη τη στιγμή η επανάληψη. Η προσπέλαση θα γίνει σε όλα τα στοιχεία με την σειρα που βρίσκονται στη συλλογή εκτός κι αν υπάρξει εντολή εξόδου (return, break) ή κάποιο σφάλμα.
- Η ενισχυμένη 'for' είναι γνωστή και ως 'for-each' επανάληψη.
- Μπορεί ο χρήστης να φτιάξει δικές του δομές δεδομένων που να μπορεί να τις προσπελάσει με την ενισχυμένη 'for' αρκεί να υλοποιήσει τη διεπαφή (interface) iterable.
(Πληροφορίες https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)
Η εντολή 'break'
Σε κάποιες περιπτώσεις μπορεί να είναι απαραίτητο να διακοπεί η επανάληψη
πρόωρα. Η εντολή 'break' με το που διαβαστεί στο σώμα κάποιας επανάληψης,
τερματίζει άμεσα αυτή την επανάληψη και συνεχίζει το πρόγραμμα απο την αμέσως
επόμενη εντολή. Αν η επανάληψη με την εντολή 'break' είναι εμφολευμένη σε άλλη
εξωτερική επανάληψη, τοτέ η δεύτερη επανάληψη δεν επηρρεάζεται από το 'break'
της πρώτης.
Παράδειγμα
public static findSpecificNumber(int[] array, int number) {
for (int i = 0; i < array.lenght; ++i) {
if (array[i] == number) {
System.out.println("Number found at position " + i);
break;
}
}
}
Η εντολή 'continue'
Είναι πιθανό κάποιος από τους κύκλους της επανάληψης να είναι αδιάφορος είτε
να μη πρέπει να επεξεργαστεί. Σε αυτή τη περίπτωση μπορεί να χρησιμοποιήθει η
εντολή 'continue'. Με το που διαβαστεί αυτή η εντολή το πρόγραμμα δε διαβάζει το
υπόλοιπο σώμα της επανάληψης και ξεκινάει κατευθείαν τον επόμενο κύκλο. Όπως και
στην περίπτωση της 'break' η 'continue' επηρρεάζει μόνο την άμεση επανάληψη στο
σώμα της οποίας βρίσκεται η εντολή.
Παράδειγμα
// Εξετάζει αν ο πίνακας έχει θετικό άρτιο αριθμό.
public static boolean arrayHasEvenPositiveNumber(int[] array) {
boolean outcome = false;
for (int number : array) {
if (number < 0 || number % 2 != 0) {
continue;
}
outcome = true;
break;
}
return outcome;
}
Αναδρομή
Αναδρομή, στον προγραμματισμό συγκεκριμένα, είναι η διαδικασία με την οποία
μια συνάρτηση καλεί τον εαυτό της στο σώμα της. Η διαδικασία αυτή είναι συχνά
χρήσιμη για την πραγματοποίηση επαναληπτικών ρουτινών. Για την αποφυγή ατέρμονων
κλήσεων, ο χρήστης, όταν καταφεύγει στην αναδρομή, θα πρέπει να διασφαλίσει δύο
πράγματα.
- Kάθε επόμενη κλήση της συνάρτησης θα πρέπει να αντιμετωπίζει μικρότερο κομμάτι του προβλήματος από ότι η προηγούμενη κλήση.
- Θα πρέπει να υπάρχει μια βασική διαχείριση από τη συνάρτηση όταν το πρόβλημα γινει αρκετά μικρό (τερματική συνθήκη).
Παράδειγμα
public static int binarySearch(int[] array, int key, int start,
int end) {
if (start > end) {
return -1;
}
int middle = (end + start) / 2;
if (array[middle] == key) {
return middle;
} else if (array[middle] < key) {
return binarySearch(array, key, middle + 1, end);
} else {
return binarySearch(array, key, start, middle - 1);
}
}
Παράδειγμα (2)
Επανάληψη
private static long factorialIterative (int theNumber) {
int theFactorial = 1;
for (int i = 0; i < theNumber; i++) {
theFactorial = theFactorial * i;
}
return theFactorial;
}
Αναδρομή
private static long factorialRecursive (int theNumber) {
if (theNumber == 1)
return 1;
else
return theNumber * factorialRecursive(theNumber - 1);
}
Παρατηρήσεις - Τα θετικά της αναδρομής
- Συχνά ο κώδικας με χρήση αναδρομής είναι πιο "συμπαγής" και κομψός από ότι με
άλλους τρόπους επανάληψης.
- Υπάρχουν κομψοί μη τετριμμένοι αλγόριθμοι όπου η αναδρομική προσέγγιση
ενδείκνυται για τη μελέτη τους. Ένα παράδειγμα είναι οι αλγόριθμοι που
ακολουθούν το αλγοριθμικό πρότυπο του "διαίρει και βασίλευε".
Παρατηρήσεις - Τα αρνητικά της αναδρομής
- Στη java, σε αντίθεση με άλλες συναρτησιακές γλώσσες, η αναδρομή απο άποψη
απόδοσης, δεν είναι βελτιστωποιημένη σε σχέση με άλλους τρόπους επανάληψης.
- Η αναδρομή συχνά δυσκολεύει τους χρήστες στην κατανόηση της.
- Η αναδρομή συχνά δυσκολεύει τους χρήστες στην εύρεση σφαλμάτων.
Άσκηση
- Προσπαθείστε να εξηγήσετε γιατί οποιαδήποτε επανάληψη με 'while' μπορεί να
γραφεί μέσω αναδρομικής συνάρτησης και το ανάποδο.
Άσκηση
- Να γράψετε πρόγραμμα που να υπολογίζει τη σειρά Σ(1/n!) για 100 πρώτους όρους και ύστερα για 1000. Ποια τιμή προσεγγίζει
η σειρά;
Άσκηση
- Να γράψετε boolean συνάρτηση που να δέχεται τρεις αριθμούς και να επιστρέφει true
αν και οι τρεις είναι ίσοι αλλιώς να επιστρέφει false.
Άσκηση
- Να γράψετε συνάρτηση που να δέχεται ακέραιο και να επιστρέφει πόσα ψηφία περιέχει
που είναι είτε 3 είτε 7. Παράδειγμα ο 372 περιέχει 2 ψηφία 3 ή 7 ενώ ο αριθμός
52 κανένα. Μπορείτε να τη γράψετε με αναδρομή;

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.