📑 Περιεχόμενα
5.1 Τι είναι οι αυτοαναφορικές δομές
Μια αυτοαναφορική δομή (self-referential structure) είναι μια struct που περιέχει pointer προς δομή του ίδιου τύπου.
Με απλά λόγια: η δομή «δείχνει» σε άλλη δομή ίδιου τύπου. Σκεφτείτε το σαν μια αλυσίδα — κάθε κρίκος γνωρίζει ποιος είναι ο επόμενος.
📌 Πού χρησιμοποιούνται;
Οι αυτοαναφορικές δομές αποτελούν τη βάση για πολλές δομές δεδομένων:
- Linked Lists (Συνδεδεμένες Λίστες)
- Trees (Δέντρα)
- Graphs (Γραφήματα)
Linked Lists (Συνδεδεμένες Λίστες)
Φανταστείτε ένα τρένο: κάθε βαγόνι είναι συνδεδεμένο με το επόμενο. Κάθε κόμβος «δείχνει» στον επόμενο, σχηματίζοντας μια αλυσίδα. Ο τελευταίος κόμβος δείχνει σε NULL (τέλος).
🌍 Πού τις συναντάμε στην καθημερινότητα;
- Playlist μουσικής — κάθε τραγούδι «ξέρει» ποιο είναι το επόμενο
- Undo/Redo — κάθε ενέργεια συνδέεται με την προηγούμενη (π.χ. Ctrl+Z στο Word)
- Browser history — κάθε σελίδα δείχνει στην προηγούμενη (κουμπί «Πίσω»)
- Ουρά εκτύπωσης — τα έγγραφα εκτυπώνονται με τη σειρά που μπήκαν
Trees (Δέντρα)
Σκεφτείτε ένα οικογενειακό δέντρο: ένας γονέας μπορεί να έχει πολλά παιδιά. Στην πληροφορική, κάθε κόμβος «δείχνει» σε δύο ή περισσότερα παιδιά-κόμβους. Ξεκινάμε πάντα από τη ρίζα (root) και κατεβαίνουμε προς τα φύλλα.
🌍 Πού τα συναντάμε στην καθημερινότητα;
- Φάκελοι στον υπολογιστή — κάθε φάκελος περιέχει υποφακέλους (Documents → Projects → myApp)
- Οργανόγραμμα εταιρείας — διευθυντής → τμηματάρχες → υπάλληλοι
- HTML σελίδα — κάθε στοιχείο περιέχει παιδιά-στοιχεία (<html> → <body> → <div>)
- Τουρνουά — οι αγώνες σχηματίζουν δέντρο μέχρι τον τελικό
Graphs (Γραφήματα)
Σκεφτείτε ένα χάρτη πόλεων: κάθε πόλη συνδέεται με πολλές άλλες, χωρίς συγκεκριμένη ιεραρχία. Κάθε κόμβος μπορεί να «δείχνει» σε οποιονδήποτε άλλο — ακόμα και πίσω στον εαυτό του. Είναι η πιο γενική μορφή σύνδεσης.
🌍 Πού τα συναντάμε στην καθημερινότητα;
- Google Maps — δρόμοι που συνδέουν διασταυρώσεις, βρίσκει τη συντομότερη διαδρομή
- Κοινωνικά δίκτυα — Facebook/Instagram: κάθε χρήστης συνδέεται με φίλους, που συνδέονται με δικούς τους φίλους
- Δίκτυο Wi-Fi — συσκευές που επικοινωνούν μεταξύ τους μέσα στο ίδιο δίκτυο
- Σύστημα πτήσεων — αεροδρόμια συνδεδεμένα με απευθείας πτήσεις
5.2 Η δομή Node & η Linked List
Ας δούμε γραμμή-γραμμή τη δομή ενός κόμβου με αναλυτικά σχόλια, για να καταλάβεις ακριβώς τι κάνει κάθε μέρος:
🔎 Πώς φαίνεται στη μνήμη
Φαντάσου ότι έχουμε τη λίστα:
Τότε οι κόμβοι είναι περίπου έτσι στη μνήμη:
💡 Δηλαδή:
- data → αποθηκεύει την τιμή
- next → δείχνει στον επόμενο κόμβο
📌 Γιατί γράφουμε struct Node *next ;
Επειδή κάθε κόμβος πρέπει να δείχνει σε άλλον κόμβο του ίδιου τύπου, ο pointer πρέπει να είναι pointer σε Node. Δηλαδή:
📌 typedef με Node
Με το typedef μπορούμε να δώσουμε νέο (συντομότερο) όνομα στον τύπο. Αντί να γράφουμε struct Node παντού, γράφουμε απλά Node:
🔎 Τι κάνει κάθε μέρος:
- typedef → λέει στον compiler: «θα δώσω νέο όνομα σε έναν τύπο»
- struct Node { ... } → ορίζει τη δομή κανονικά (όπως πριν)
- Node; στο τέλος → αυτό είναι το νέο όνομα του τύπου
📌 Παράδειγμα δημιουργίας ενός κόμβου
📌 Οπτικά
5.3 Παράδειγμα: Playlist με Linked List
Πώς μοιάζει η playlist
🎵 Γιατί Linked List για playlist;
Γιατί μπορείς εύκολα να:
- Προσθέσεις τραγούδι στη μέση
- Αφαιρέσεις τραγούδι
- Πας στο επόμενο τραγούδι
🤔 Πότε χρησιμοποιείται η Linked List;
Η linked list δεν έχει νόημα όταν ξέρεις από πριν πόσα στοιχεία έχεις (όπως εδώ: 3 τραγούδια). Χρησιμοποιείται όταν:
✅ 1. Δεν ξέρεις πόσα στοιχεία θα έχεις
π.χ. playlist που μεγαλώνει δυναμικά
✅ 2. Θες εύκολη προσθήκη/αφαίρεση
- να βάλεις τραγούδι στη μέση
- να διαγράψεις τραγούδι
✅ 3. Θες να τα διατρέχεις με loop
π.χ.:
👉 Αυτό είναι το βασικό νόημα της linked list:
Δεν χρειάζεται να ξέρεις πόσα είναι.
⚖️ Σύγκριση
| ❌ Χωρίς linked list (στατικά) | ✅ Με linked list |
|---|---|
| Ξέρεις τα τραγούδια από πριν | Μπορείς να έχεις όσα τραγούδια θέλεις |
| Γράφεις ένα-ένα | Τα διατρέχεις με loop |
| Δεν επεκτείνεται εύκολα | Είναι πιο «δυναμικό» |
5.4 Traversal — Διάσχιση της Linked List
Ξεκινάμε από το παράδειγμα της Playlist. Έχουμε μια playlist:
και έχουμε δημιουργήσει τους κόμβους:
Δηλαδή οι κόμβοι είναι συνδεδεμένοι μεταξύ τους.
⚠️ Το πρόβλημα
Αν θέλουμε να εμφανίσουμε όλα τα τραγούδια γράφουμε:
⛔ Αυτό όμως έχει πρόβλημα:
- Πρέπει να ξέρουμε πόσα τραγούδια υπάρχουν
- Αν προστεθεί νέο τραγούδι, πρέπει να αλλάξουμε τον κώδικα
Π.χ. αν η playlist γίνει:
θα πρέπει να γράψουμε:
Άρα αυτό δεν είναι πρακτικό.
💡 Η ιδέα της λύσης
Επειδή κάθε κόμβος έχει next, μπορούμε να ακολουθούμε αυτά τα pointers. Δηλαδή:
Βήματα:
- Ξεκινάμε από τον πρώτο κόμβο
- Πηγαίνουμε στον επόμενο
- Συνεχίζουμε μέχρι να βρούμε NULL
Αυτό λέγεται Traversal (Διάσχιση).
🧠 Η λύση
Χρησιμοποιούμε έναν pointer που κινείται στη λίστα:
🔎 Τι συμβαίνει βήμα-βήμα
Βήμα 1 — Αρχή:
current → Song1
Βήμα 2:
current → Song2
Βήμα 3:
current → Song3
Βήμα 4 — Τέλος:
current → NULL — το loop σταματά!
📌 Συμπέρασμα
Το Traversal επιτρέπει να:
- Διαβάζουμε όλη τη linked list
- Χωρίς να ξέρουμε πόσα στοιχεία έχει
Απλά ακολουθούμε τα next pointers μέχρι να βρούμε NULL.
5.5 Η λύση: head
Χρησιμοποιούμε έναν pointer που δείχνει στον πρώτο κόμβο της λίστας. Αυτός ο pointer λέγεται συνήθως:
Οπτικά
Παράδειγμα
Τώρα το traversal γίνεται έτσι:
✅ Πλήρες παράδειγμα με head + traversal
🔑 Γιατί είναι σημαντικό το head
Με το head μπορούμε να:
- Ξεκινάμε το traversal
- Προσθέτουμε κόμβους στην αρχή
- Διαγράφουμε κόμβους
- Περνάμε τη λίστα σε συναρτήσεις
Χωρίς head χάνουμε την αρχή της λίστας!
📌 Μικρό παράδειγμα
Traversal:
✅ Με μία πρόταση
Το head είναι ο pointer που κρατά τη διεύθυνση του πρώτου κόμβου της linked list και μας επιτρέπει να ξεκινήσουμε την επεξεργασία της.
5.6 Άσκηση
✏️ Άσκηση: Δημιουργία linked list με 3 κόμβους
Γράψε πρόγραμμα που:
- Δημιουργεί 3 κόμβους (με malloc)
- Τους συνδέει σε linked list
- Εκτυπώνει όλες τις τιμές
Χρησιμοποίησε τη δομή:
Η λίστα σου πρέπει να μοιάζει έτσι:
📋 Ανακεφαλαίωση
✔ Αυτοαναφορική δομή = struct με pointer σε δομή ίδιου τύπου
✔ Χρησιμοποιούμε pointer (όχι ολόκληρη δομή) για να αποφύγουμε άπειρο μέγεθος
✔ Η linked list τελειώνει πάντα με NULL
✔ Το head είναι ο pointer στον πρώτο κόμβο — χωρίς αυτόν χάνουμε τη λίστα
✔ Το Traversal μας επιτρέπει να διασχίσουμε όλη τη λίστα ακολουθώντας τα next