2.1 Τι είναι η Αναδρομή;
Η αναδρομή είναι μια τεχνική στον προγραμματισμό όπου μια συνάρτηση καλεί τον εαυτό της. Αυτό ακούγεται παράξενο στην αρχή — πώς μπορεί μια συνάρτηση να καλεί τον εαυτό της;
Η λογική είναι η εξής: ένα μεγάλο πρόβλημα το λύνουμε λύνοντας ένα μικρότερο ίδιο πρόβλημα, και αυτό πάλι λύνεται λύνοντας ένα ακόμα μικρότερο, μέχρι που φτάνουμε σε ένα πρόβλημα τόσο απλό που η απάντηση είναι άμεση.
2.1.1 Τα δύο μέρη κάθε αναδρομικής συνάρτησης
Κάθε αναδρομική συνάρτηση έχει υποχρεωτικά δύο μέρη. Αν λείπει το ένα, το πρόγραμμα δεν θα δουλέψει σωστά:
🛑 1. Βασική Περίπτωση (Base Case)
Είναι η συνθήκη που σταματάει την αναδρομή. Χωρίς αυτή, η συνάρτηση θα καλεί τον εαυτό της επ' αόριστον και το πρόγραμμα θα καταρρεύσει.
Π.χ.: if (n == 0) return 1;
🔁 2. Αναδρομική Περίπτωση (Recursive Case)
Είναι το σημείο όπου η συνάρτηση καλεί τον εαυτό της με ένα μικρότερο πρόβλημα, πλησιάζοντας κάθε φορά τη βασική περίπτωση.
Π.χ.: return n * factorial(n-1);
2.2 Παράδειγμα: Παραγοντικό n!
Το παραγοντικό είναι το πιο κλασικό παράδειγμα για να καταλάβουμε την αναδρομή, γιατί ο ίδιος ο μαθηματικός ορισμός του είναι αναδρομικός:
2.2.1 Κώδικας C
2.3 Πώς υπολογίζεται το 5! — Βήμα-Βήμα
Αυτό που συχνά δυσκολεύει είναι το εξής: όταν η factorial(5) καλεί την factorial(4), τι γίνεται με την τιμή n=5; Χάνεται; Αντικαθίσταται; Η απάντηση είναι ότι αποθηκεύεται αυτόματα στη στοίβα (stack) και περιμένει.
factorial δημιουργεί ένα νέο αντίγραφο της μεταβλητής n στη μνήμη. Τα αντίγραφα αυτά είναι εντελώς ανεξάρτητα το ένα από το άλλο.
2.3.1 Εικόνα εκτέλεσης
2.4 Animated Βήμα-Βήμα: factorial(5)
Χρησιμοποιήστε τα κουμπιά για να δείτε ακριβώς πώς χτίζεται και αποχτίζεται η στοίβα κλήσεων:
2.5 Πώς Αποθηκεύεται στη Μνήμη (Stack)
Κάθε κλήση της factorial δημιουργεί ένα νέο πλαίσιο στοίβας (stack frame). Σκεφτείτε τη στοίβα σαν στοίβα από πιάτα — βάζετε ένα-ένα και παίρνετε από πάνω.
- Η τιμή της παραμέτρου
n(π.χ. n=5, n=4, …) - Η διεύθυνση επιστροφής — δηλαδή πού θα συνεχίσει ο κώδικας όταν τελειώσει
- Το αποτέλεσμα που αναμένεται από την επόμενη κλήση
n. Όταν επιστρέψει το αποτέλεσμα, το πλαίσιο αφαιρείται από τη στοίβα και ο έλεγχος επιστρέφει στο προηγούμενο, που συνεχίζει από εκεί που σταμάτησε.
2.6 Άλλα Παραδείγματα Αναδρομής
2.6.1 Δύναμη αριθμού xy
Το xy σημαίνει ότι πολλαπλασιάζουμε το x με τον εαυτό του y φορές. Αναδρομικά, αυτό γράφεται ως: xy = x × xy-1. Βασική περίπτωση: οποιοσδήποτε αριθμός υψωμένος στο 0 ισούται με 1.
Ας δούμε βήμα-βήμα πώς εκτελείται το power(2, 4). Η λογική είναι ακριβώς η ίδια με το παραγοντικό: η αναδρομή κατεβαίνει μέχρι τη βασική περίπτωση power(2, 0) = 1 και στη συνέχεια ανεβαίνει πολλαπλασιάζοντας με 2 κάθε φορά: 1 → 2 → 4 → 8 → 16.
2.6.2 Fibonacci
Η ακολουθία Fibonacci είναι μια από τις πιο γνωστές ακολουθίες στα μαθηματικά και εμφανίζεται παντού στη φύση — από τα πέταλα λουλουδιών μέχρι τα κελύφη σαλιγκαριών. Κάθε αριθμός είναι το άθροισμα των δύο προηγούμενων:
📐 Οι αναλογίες 38 και 62 στο ανθρώπινο σώμα αντιστοιχούν στους αριθμούς Fibonacci (38/62 ≈ 0.618 — η Χρυσή Τομή!)
Το Fibonacci είναι διαφορετικό από το παραγοντικό σε ένα κρίσιμο σημείο: κάθε κλήση κάνει δύο αναδρομικές κλήσεις, όχι μία. Αυτό σημαίνει ότι το δέντρο εκτέλεσης δεν είναι γραμμικό — διακλαδίζεται. Για το fibonacci(5) γίνονται συνολικά 15 κλήσεις!
Παρακάτω φαίνεται βήμα-βήμα η εκτέλεση του fibonacci(4). Προσέξτε πώς η στοίβα πρώτα κατεβαίνει στον αριστερό κλάδο (fibonacci(n-1)), τον ολοκληρώνει, και μετά πιάνει τον δεξί κλάδο (fibonacci(n-2)):
2.6.3 Άθροισμα 1 + 2 + ... + n
Ένα ακόμα απλό παράδειγμα: το άθροισμα των πρώτων n ακεραίων. Η λογική είναι: το άθροισμα μέχρι το n ισούται με n συν το άθροισμα μέχρι το n-1. Βασική περίπτωση: όταν n=1, το άθροισμα είναι 1.
2.7 Κίνδυνοι και Λάθη στην Αναδρομή
2.7.1 Stack Overflow — Άπειρη Αναδρομή
Αν παραλειφθεί η βασική περίπτωση, ή αν η συνθήκη τερματισμού δεν μπορεί ποτέ να επιτευχθεί, η συνάρτηση συνεχίζει να καλεί τον εαυτό της ατέρμονα. Κάθε κλήση χρησιμοποιεί χώρο στη στοίβα, και όταν αυτή γεμίσει, το πρόγραμμα τερματίζεται με σφάλμα Stack Overflow.
factorial(10000) θα χρειαστούν 10.000 πλαίσια — η στοίβα θα γεμίσει και το πρόγραμμα θα τερματιστεί με σφάλμα.
2.7.2 Σωστή Αναδρομή — Checklist
- Έχω βασική περίπτωση που τερματίζει;
- Κάθε κλήση πλησιάζει τη βασική περίπτωση; (π.χ. n μειώνεται;)
- Δεν δέχομαι αρνητικές τιμές χωρίς έλεγχο;
- Έχω δοκιμάσει για n=0, n=1, n=2 χειροκίνητα;
2.8 Αναδρομή vs Επανάληψη
Οτιδήποτε γράφεται αναδρομικά μπορεί να γραφεί και επαναληπτικά (με for ή while), και το αντίστροφο. Η επιλογή εξαρτάται από το πρόβλημα και το πόσο ευανάγνωστος θέλουμε να είναι ο κώδικας.
| Χαρακτηριστικό | Αναδρομή (Recursion) | Επανάληψη (Loop) |
|---|---|---|
| Κώδικας | Πιο σύντομος, κομψός | Πιο λεπτομερής |
| Κατανόηση | Κοντά στον μαθηματικό ορισμό | Πιο «μηχανιστική» |
| Μνήμη | Χρησιμοποιεί στοίβα (επιπλέον) | Σταθερή μνήμη |
| Ταχύτητα | Συνήθως πιο αργή | Συνήθως πιο γρήγορη |
| Κίνδυνος | Stack overflow | Ατέρμων βρόχος |
| Χρησιμοποιείται για | Δέντρα, γράφους, D&C αλγόριθμοι | Απλές επαναλήψεις |
2.8.1 Το ίδιο παράδειγμα με βρόχο
Για σύγκριση, ο ίδιος υπολογισμός χωρίς αναδρομή. Παρατηρήστε ότι δεν χρειάζεται στοίβα — η τιμή συσσωρεύεται στη μεταβλητή result απευθείας:
2.9 Ασκήσεις
📝 Άσκηση 1: Χειρονακτικός Υπολογισμός
Γράψτε χειρονακτικά (χωρίς υπολογιστή) τα βήματα εκτέλεσης του factorial(4). Σχεδιάστε τη στοίβα κλήσεων.
📝 Άσκηση 2: Δύναμη
Γράψτε αναδρομική συνάρτηση int power(int x, int n) που υπολογίζει xn. Βασική περίπτωση: x0=1. Δοκιμάστε: power(2,8)=256, power(3,0)=1.
📝 Άσκηση 3: Ψηφία Αντίστροφα
Γράψτε αναδρομική συνάρτηση void printReverse(int n) που εμφανίζει τα ψηφία ενός ακεραίου αντίστροφα. Π.χ. 1234 → 4 3 2 1. Υπόδειξη: τυπώστε n%10 και μετά καλέστε printReverse(n/10).
📝 Άσκηση 4: Άθροισμα Ψηφίων
Γράψτε αναδρομική συνάρτηση int digitSum(int n) που υπολογίζει το άθροισμα των ψηφίων. Π.χ. digitSum(1234) = 10. Υπόδειξη: n%10 + digitSum(n/10).
📝 Άσκηση 5 (Πρόκληση): Fibonacci με Print
Τροποποιήστε τη συνάρτηση Fibonacci ώστε να εκτυπώνει κάθε βήμα: "Υπολογίζω F(n)..." και "F(n) = αποτέλεσμα". Παρατηρήστε πόσες φορές καλείται για κάθε τιμή!
2.10 Σύνοψη Κεφαλαίου
- Τι είναι η αναδρομή — συνάρτηση που καλεί τον εαυτό της
- Τα δύο απαραίτητα μέρη: βασική περίπτωση (σταματάει) και αναδρομική περίπτωση (προχωρά)
- Πώς η C χρησιμοποιεί τη στοίβα (stack) για να αποθηκεύει τις ενδιάμεσες τιμές
- Τις δύο φάσεις: κάθοδο (κλήσεις) και άνοδο (επιστροφές)
- Τον κίνδυνο stack overflow από ατέρμονη αναδρομή
- Πότε να επιλέγουμε αναδρομή vs επανάληψη
Επόμενο κεφάλαιο: Τελεστές και Εκφράσεις — πράξεις με μεταβλητές και τυχαίους αριθμούς!