Δομές δεδομένων Πίνακες Οι πίνακες είναι το πιο απλό «μέσο» αποθήκευσης ομοειδούς πληροφορίας. Χρησιμοποιούν ακριβώς όση μνήμη χρειάζεται για την αποθήκευση της πληροφορίας Επιτρέπουν την προσπέλαση άμεσα στο στοιχείο, άρα και τη γρήγορη αναζήτηση όταν ο πίνακας είναι ταξινομημένος Μπορούν να έχουν πολλές διαστάσεις με τρόπο κοντινό στο πως έχουμε συνηθίσει να σκεφτόμαστε Απαιτούν χρονοβόρα διαδικασία για να αλλάξει το μέγεθος τους (χρήση ου πίνακα και αντιγραφή του ου ) Απαιτούν χρονοβόρα διαδικασία για να εισαχθεί ή διαγραφεί ένα στοιχείο στη «μέση» του πίνακα Λίστες Οι λίστες, χάνοντας τα πλεονεκτήματα των πινάκων, λύνουν προβλήματα που παρουσιάζουν οι πίνακες Έχουν αόριστο μήκος Χρησιμοποιούν πρόσθετη μνήμη για τη «σύνδεση» των στοιχείων μεταξύ τους Η προσπέλασή τους γίνεται σειριακά, από την αρχή (κεφαλή) ή/και από το τέλος (ουρά). Η εισαγωγή ή η διαγραφή ενός στοιχείου είναι πολύ απλή(=γρήγορη) διαδικασία Τα στοιχεία τους δεν απαιτείται να είναι συνεχόμενα στη μνήμη Μπορεί να είναι κυκλικές, δηλαδή το επόμενο στοιχείο από το τελευταίο τους να είναι το ο Απλά Συνδεδεμένες Λίστες Wikipedia: http://en.wikipedia.org/wiki/linked structure Υπόδειγμα Υλοποίησης σε C Ο κόμβος είναι: struct node { int val; struct node *next; ; Και η ίδια η λίστα, είναι πολύ απλά: struct node *head; ή struct node *list; Διπλά Συνδεδεμένες Λίστες Wikipedia: http://en.wikipedia.org/wiki/doubly_linked_list
Εδώ ο δείκτης δείχνει το στοιχείο, όχι το «τέλος» του, απεικονίζεται έτσι για απλότητα. Tail Ενδεικτικός κώδικας Εισαγωγή και διαγραφή στοιχείου από διπλά συνδεδεμένη λίστα. void remove(struct node_t *node) { Tail void insertafter(struct note_t *newnode, struct node_t *existing) { newnode>next = existing>next; newnode>prev = existing; if (existing>next!= NULL) { existing>next>prev = newnode; existing>next = newnode; if (node>prev!= NULL) { node>prev>next = node>next; if (node>next!= NULL) { node>next>prev = node>prev; node>next = node>prev = NULL; Εφαρμογές Στοίβα Stack Wikipedia: http://en.wikipedia.org/wiki/stack_(abstract type) Οι στοίβες είναι δομές τύπου LastIn, FirstOut (LIFO) δηλαδή αποθηκεύουμε σε αυτές πληροφορία (με την εντολή push) και την ανακτούμε (με την εντολή pop) με την αντίστροφη σειρά που την αποθηκεύσαμε. Υλοποιείται τόσο με χρήση πινάκων, όσο και με χρήση λιστών. Η χρήση πινάκων φαίνεται να προσφέρει πιο απλή υλοποίηση. Τυπικές της εφαρμογές είναι:. Υπολογισμός (μαθηματικών και όχι μόνο) εκφράσεων και συντακτική ανάλυση. Διαχείριση μνήμης κατά τη λειτουργία λογισμικού ή και του ίδιου του λειτουργικού συστήματος. Ιχνηλασία
4. Λειτουργίες «Αναίρεσης» (Undo). Εκεί η σειρά αναίρεσης είναι η αντίστροφη από τις πράξεις. Ουρές Queues Wikipedia: http://en.wikipedia.org/wiki/queue_(abstract type) Είναι το συμμετρικό της στοίβας. Είναι τύπου FIFO, δηλαδή FirstIn, FirstOut δομή δεδομένων όπου η πληροφορία που εισάγεται σε μια ουρά είναι (με την εντολή enqueue) λαμβάνεται από την ουρά (με την εντολή dequeue) με την ίδια σειρά. Ακριβώς όπως μια ουρά ανθρώπων σε ένα ταμείο μιας πολιτισμένης χώρας. Η χρήση λιστών για την υλοποίηση της ουράς δίνει πιο απλό κώδικα. Τυπικές εφαρμογές είναι:. Λειτουργίες τύπου server όπου εξυπηρετούνται πρώτα όσοι έχουν αιτηθεί πρώτοι.. Ακολουθίες ενεργειών που πρέπει να γίνουν με συγκεκριμένη σειρά πχ μακροεντολές Δένδρα Αποτελούν ιεραρχική οργάνωση δεδομένων. Λύνουν κάποια από τα προβλήματα που παρουσιάζουν οι λίστες ως προς τους πίνακες σε βάρος μιας αυξημένης διαχείρισης. Πάνω στα δένδρα υπάρχει τεράστια θεωρητική ανάλυση στην επιστήμη της Πληροφορικής. root / ρίζα ο επίπεδο 8 ο επίπεδο 9 4 4 ο επίπεδο 4ο επίπεδο 8 leaves / φύλλα Το παραπάνω δένδρο (πάντα σχεδιάζονται με τη ρίζα στο επάνω μέρος) έχει μέγεθος (αριθμό κόμβων) 0 και ύψος 4. Απλά Δένδρα Wikipedia: http://en.wikipedia.org/wiki/tree_(_structure) Δυαδικά Δένδρα Wikipedia: http://en.wikipedia.org/wiki/binary_tree Στα δυαδικά δένδρα ο κάθε κόμβος (node) έχει το πολύ δύο παιδιά.
8 Δυαδικά Δένδρα Αναζήτησης Wikipedia: http://en.wikipedia.org/wiki/binary_search_tree Τα δυαδικά δένδρα αναζήτησης έχουν την εξής ιδιότητα. Σε κάθε κόμβο όλα τα παιδιά του που είναι από τη δεξιά πλευρά έχουν μεγαλύτερες τιμές από τον κόμβο και όλα τα αριστερά μικρότερες. Αυτό επιτρέπει την γρήγορη αναζήτηση τιμών καθώς με αριθμό πράξεων της τάξης του ύψους του δένδρου, φτάνουμε στην επιθυμητή τιμή (εφόσον υπάρχει). Όμως προσοχή χρειάζεται κατά την εισαγωγή ή διαγραφή κόμβων του δένδρου καθώς ανάλογα με τη σειρά εισαγωγής των στοιχείων το δένδρο παίρνει διαφορετικές μορφές. Πχ Κάποιες φορές γίνεται άσκοπα «ψηλό». 8 8 vs Πχ στο αριστερά δένδρο οι τιμές,, μπήκαν με αυτή τη σειρά, ενώ στο δεξιά μπήκαν με τη σειρά,,. Επειδή όσο πιο κοντό είναι ένα δένδρο, τόσο πιο γρήγορα γίνονται αρκετές από τις ενέργειες που θέλουμε να του εφαρμόσουμε, επιδιώκουμε πάντα τα δένδρα να είναι ισορροπημένα/συμμετρικά. Υπάρχουν όμως εφαρμογές όπου θέλουμε το αντίθετο. Για παράδειγμα στο ακόλουθο σχήμα βλέπετε ένα δένδρο που χρησιμοποιείται στη συμπίεση ενός αρχείου. Σε αυτό το παράδειγμα με δεδομένο το δένδρο που βλέπουμε μπορούμε να παραστήσουμε τους αριθμούς,,, με λιγότερα bits. Εάν για παράδειγμα βάζαμε τα δεδομένα σε έναν πίνακα με 4 στοιχεία, θα θέλαμε bits για να παραστήσουμε τον δείκτη με τιμές 0. Όπως βλέπουμε στον πίνακα η τιμή εμφανίζεται 00 φορές ενώ η, 8 φορές. Με συνολικά 40 τιμές θέλουμε 40xbits/(8bits/Byte) = 0, = 0 Bytes.
Εάν όμως χρησιμοποιήσουμε το δένδρο και αντιστοιχίσουμε τις τιμές των bits το 0=δεξιά και το =αριστερά, τότε το παριστάνεται ως, το ως 0, το ως 00 και το ως 000. Αυτό μας επιτρέπει να αποθηκεύσουμε την πληροφορία σε 00x + 80x + x+8x = 0 bits = 67Bytes << 0Bytes που ήθελε η πινακοποιημένη μορφή. 00 0 8 0 00 0 0 0 00 0 0 0 000 8 00 0 Παρόλα αυτά αν προσθέσουμε τη μνήμη που χρειάζεται ο πίνακας ή το δένδρο στην κάθε περίπτωση, τότε ο πίνακας δίνει συνολικά μικρότερο μέγεθος, αλλά καθώς μεγαλώνει το αρχείο ή αυξάνουν οι αντιθέσεις στη στατιστική ανάλυση των τιμών, το δένδρο δίνει κατά πολύ καλύτερα αποτελέσματα από τον πίνακα.