Πανεπιστήμιο Πειραιώς Σχολή Τεχνολογιών Πληροφορικής και Επικοινωνιών Τμήμα Ψηφιακών Συστημάτων 4. Συνδεδεμένες Λίστες 2 ομές εδομένων 4 5 Χρήστος ουλκερίδης Τμήμα Ψηφιακών Συστημάτων 10/11/2016
Εισαγωγή (1/2) Ως τώρα, εξετάσαμε δομές δεδομένων με στατική δέσμευση μνήμης Πίνακες, (Στοίβες, Ουρές) Η στατική δέσμευση μνήμης προσφέρει τυχαία προσπέλαση σε O(1) χρόνο Όμως Η τυχαία προσπέλαση δεν υποστηρίζεται σε στοίβες και ουρές Η στατική δέσμευση μνήμης έχει μειονεκτήματα Πρέπει να γνωρίζουμε το μέγιστο πλήθος στοιχείων που θα αποθηκευθούν τη στιγμή της κατασκευής της δομής Μπορεί σημαντικό μέρος της δεσμευμένης μνήμης να μένει αχρησιμοποιήτο Στο εξής θα εξετάσουμε δομές δεδομένων με δυναμική δέσμευση μνήμης Δομές Δεδομένων, 3ο Εξάμηνο 2
Εισαγωγή (2/2) Μία συνδεδεμένη λίστα αποτελείται από μία συλλογή δυναμικά δεσμευμένων θέσεων μνήμης (κόμβων) με συνδέσεις μεταξύ τους Ευμετάβλητη δομή δεδομένων που μπορεί να χρησιμοποιηθεί σε πολλές περιπτώσεις αποθήκευσης δεδομένων Μπορεί να αντικαταστήσει έναν πίνακα ως βάση για άλλες δομές αποθήκευσης, όπως στοίβες, ουρές Εκτός κι αν απαιτείται τυχαία πρόσβαση σε μεμονωμένα στοιχεία με τη χρήση δείκτη, π.χ. A[12] Δομές Δεδομένων, 3ο Εξάμηνο 3
Απλά Συνδεδεμένη Λίστα Απλά συνδεδεμένη λίστα Σύνολο κόμβων που αποθηκεύουν στοιχεία (δεδομένα) Κάθε κόμβος στη λίστα δείχνει στον επόμενο, εκτός από τον τελευταίο Κόμβος = αντικείμενο + αναφορά στον επόμενο κόμβο Δομές Δεδομένων, 3ο Εξάμηνο 4
Βασικές Πράξεις Λίστας Εισαγωγή (ύπαρξη διαφορετικών εκδοχών) Στην αρχή της λίστας ή στο τέλος λίστας Ο(1) Μετά από κόμβο με δεδομένο κλειδί Ο(Ν) ιαγραφή (ύπαρξη διαφορετικών εκδοχών) Πρώτου ή τελευταίου κόμβου της λίστας Ο(1) Ενός κόμβου με δεδομένο κλειδί Ο(Ν) Αναζήτηση κόμβου με δεδομένο κλειδί Ο(Ν) Δομές Δεδομένων, 3ο Εξάμηνο 5
Κόμβος Λίστας Αυτο-αναφερόμενη κλάση Δομές Δεδομένων, 3ο Εξάμηνο 6
Εισαγωγή σε Απλά Συνδεδεμένη Λίστα Πρέπει να οριστεί η θέση που θα γίνει η εισαγωγή. Έστω current η θέση μετά την οποία θα γίνει η εισαγωγή tmp = new Link(x, current.next); current.next = tmp; // ο επόμενος κόμβος του a είναι ο x tmp.element = x; tmp.next = current.next; current.next = new Link(x, current.next); Δομές Δεδομένων, 3ο Εξάμηνο 7
Διαγραφή από Απλά Συνδεδεμένη Λίστα ιαγραφή του στοιχείου x από τη λίστα Έστω current η θέση του κόμβου πριν το x Ο δείκτης προς τον επόμενο του current θα πρέπει να παρακάμψει τον x. current.next = (current.next).next; x Δομές Δεδομένων, 3ο Εξάμηνο 8
Βασική Υλοποίηση Απλά συνδεδεμένη λίστα Εισαγωγή Στην αρχή λίστας (insertfirst) Μετά από κόμβο με δεδομένο κλειδί ιαγραφή Από την αρχή λίστας Κόμβου με δεδομένο κλειδί Αναζήτηση κόμβου με δεδομένο κλειδί Δομές Δεδομένων, 3ο Εξάμηνο 9
Κλάση LinkedList Δομές Δεδομένων, 3ο Εξάμηνο 10
Εισαγωγή στην και Διαγραφή από την Αρχή Δομές Δεδομένων, 3ο Εξάμηνο 11
Εμφάνιση Περιεχομένων Λίστας Δομές Δεδομένων, 3ο Εξάμηνο 12
Αναζήτηση Κόμβου Σχόλιο: Αυτή η μέθοδος είναι private διότι: Επιστρέφει αντικείμενο τύπου Node «εσωτερικό» της λίστας ε θέλουμε ο χρήστης να μπορεί να «πειράζει» τέτοια αντικείμενα Εξυπηρετεί άλλες (public) μεθόδους: find, insertafter, delete Δομές Δεδομένων, 3ο Εξάμηνο 13
Αναζήτηση Δεδομένων Σχόλιο: Αυτή η μέθοδος είναι public: ιαθέσιμη στον τελικό χρήστη για την ανάκτηση των δεδομένων του Χρησιμοποιεί (εσωτερικά) την findnode για ανάκτηση του σχετικού κόμβου Δομές Δεδομένων, 3ο Εξάμηνο 14
Εισαγωγή μετά από Δομές Δεδομένων, 3ο Εξάμηνο 15
Εισαγωγή μετά από (σχηματικά) previous.next a next b next x next previous newnode Δομές Δεδομένων, 3ο Εξάμηνο 16
Διαγραφή με Κλειδί Δομές Δεδομένων, 3ο Εξάμηνο 17
Διαγραφή (σχηματικά) previous.next next next χ next previous current Δομές Δεδομένων, 3ο Εξάμηνο 18
Δομές Δεδομένων, 3ο Εξάμηνο 19
Παράδειγμα: Υλοποίηση Στοίβας με Λίστα Δομές Δεδομένων, 3ο Εξάμηνο 20
Παράδειγμα: Υλοποίηση Ουράς με Λίστα Η ουρά χρειάζεται εισαγωγή στο ένα άκρο και απομάκρυνση από το άλλο Απαιτείται η συντήρηση επιπλέον αναφοράς στο τέλος της λίστας Υλοποίηση των επιπλέον μεθόδων insertlast() Προσοχή στην ενημέρωση και της αναφοράς first, εάν χρειάζεται deletelast() Προσοχή στην ενημέρωση και της αναφοράς first, εάν χρειάζεται Δομές Δεδομένων, 3ο Εξάμηνο 21
Παράδειγμα: Υλοποίηση Ουράς με Λίστα Δομές Δεδομένων, 3ο Εξάμηνο 22
Απλοποίηση Υλοποίησης ιαχείριση ειδικών περιπτώσεων Προβλήματα με τη βασική περιγραφή λειτουργιών απλά συνδεδεμένης λίστας ιαγραφή: Κάθε φορά που διαγράφεται ένας κόμβος, πρέπει να βρίσκουμε τον προηγούμενο του Ειδική περίπτωση: διαγραφή πρώτου κόμβου Εισαγωγή: Ο κόμβος που εισάγουμε πρέπει να ακολουθεί κάποιον κόμβο. Ειδική περίπτωση: εισαγωγή κόμβου στην αρχή Μπορούμε να απλοποιήσουμε την υλοποίηση εξασφαλίζοντας την ιδιότητα: Κάθε κόμβος απλά συνδεδεμένης λίστας έχει προηγούμενο Δομές Δεδομένων, 3ο Εξάμηνο 23
Κόμβος Κεφαλής (Head Node) Κόμβος κεφαλή (head) της λίστας Επιπλέον κόμβος που δε διατηρεί δεδομένα Εξυπηρετεί στο να ικανοποιηθεί η απαίτηση κάθε κόμβος να έχει έναν προηγούμενο κόμβο στη λίστα Με χρήση του κόμβου κεφαλής μπορούμε να διαχειριστούμε εύκολα τις ειδικές περιπτώσεις εισαγωγής και διαγραφής στην αρχή της λίστας Δομές Δεδομένων, 3ο Εξάμηνο 24
header.ddata=null; Χρήση κόμβου κεφαλής για συνδεδεμένη λίστα header.next =null Κενή λίστα όταν χρησιμοποιούμε κόμβο κεφαλής Δομές Δεδομένων, 3ο Εξάμηνο 25
Πλεονεκτήματα Χρήσης Κόμβου Κεφαλής Ενοποίηση των insertfirst και insertafter Υλοποιούμε μία private μέθοδο myinsertafter(node node, int id, Object dd) insertafter(int key, int id, Object dd): node=findnode(key); myinsertafter(node, id, dd); insertfirst(int id, Object dd): myinsertafter(head, id, dd); Στη μέθοδο delete(int key) δε χρειάζονται Έλεγχος isempty() στην αρχή Ειδικός χειρισμός του πρώτου κόμβου (το if statement στο τέλος) Δομές Δεδομένων, 3ο Εξάμηνο 26
Διαγραφή/Εισαγωγή στο Τέλος Με την έως τώρα υλοποίηση απαιτούν O(n) χρόνο ιάσχιση όλης της λίστας μέχρι εύρεσης του τελευταίου κόμβου. ιαγραφή του τελευταίου κόμβου / Εισαγωγή μετά από τον τελευταίο κόμβο. Σε O(1) χρόνο, αν συντηρούμε αναφορά last, επιπλέον της first Αν έχουμε άδεια λίστα με κόμβο κεφαλή, τότε last=null Η Εισαγωγή μετά από τον τελευταίο κόμβο ελέγχει αν last==null και εισάγει μετά από την κεφαλή, αν αυτό είναι αληθές. Η ιαγραφή του τελευταίου κόμβου ελέγχει αν last==null και επιστρέφει null, αν αυτό είναι αληθές. Δομές Δεδομένων, 3ο Εξάμηνο 27
Διπλά Συνδεδεμένες Λίστες
Διπλά Συνδεδεμένες Λίστες Απλά Συνδεδεμένες Λίστες υνατότητα αποδοτικής διάσχισης της λίστας προς μία κατεύθυνση εν υπάρχει τρόπος να γνωρίζουμε τον προηγούμενο ενός δεδομένου κόμβου ιπλά Συνδεδεμένες Λίστες Κάθε κόμβος έχει επόμενο (next) και προηγούμενο (previous) υνατότητα διάσχισης διπλής κατεύθυνσης (π.χ. εκτύπωση σε ανάποδη σειρά), εφόσον διατηρούμε και μια αναφορά last. Δομές Δεδομένων, 3ο Εξάμηνο 29
Διπλά Συνδεδεμένες Λίστες: Πλεονεκτήματα Υλοποίηση Εισαγωγής και ιαγραφής ιαγραφή: απλοποιείται, γιατί δε χρειάζεται να κρατάμε τον προηγούμενο Είναι διαθέσιμος ως current.previous Εισαγωγή: μετά ή πριν από κόμβο με δεδομένο κλειδί Μπορούμε να έχουμε κόμβο κεφαλή και (τελείως ανάλογα) κόμβο ουρά (tail node). Συντηρούν την αναλλοίωτη ιδιότητα ενός προηγούμενου και ενός επόμενου για κάθε κόμβο δεδομένων. Δομές Δεδομένων, 3ο Εξάμηνο 30
Διπλά Συνδεδεμένες Λίστες Κάθε κόμβος έχει δύο αναφορές σε άλλους κόμβους Μία προς τον επόμενο και μία προς τον προηγούμενο κόμβο Δομές Δεδομένων, 3ο Εξάμηνο 31
Ορισμός Κόμβου Διπλά Συνδεδεμένης Λίστας Δομές Δεδομένων, 3ο Εξάμηνο 32
Κενή Διπλά Συνδεδεμένη Λίστα με Κεφαλή και Ουρά Δομές Δεδομένων, 3ο Εξάμηνο 33
Διπλά Συνδεδεμένη Λίστα: Εισαγωγή Δομές Δεδομένων, 3ο Εξάμηνο 34
Διπλά Συνδεδεμένη Λίστα: Διαγραφή Δομές Δεδομένων, 3ο Εξάμηνο 35
Ορισμός Διπλά Συνδεδεμένης Λίστας χωρίς Κεφαλή και Ουρά Θα εξετάσουμε εισαγωγή Στην αρχή της λίστας: insertfirst() Στο τέλος της λίστας: insertlast() Μετά από κόμβο με συγκεκριμένο κλειδί: insertafter(int key) Δομές Δεδομένων, 3ο Εξάμηνο 36
Εισαγωγή στην Αρχή Διπλά Συνδεδεμένης Λίστας Δομές Δεδομένων, 3ο Εξάμηνο 37
Εισαγωγή στο Τέλος Διπλά Συνδεδεμένης Λίστας Δομές Δεδομένων, 3ο Εξάμηνο 38
Εισαγωγή μετά από Κόμβο σε Διπλά Συνδεδεμένη Λίστα Δομές Δεδομένων, 3ο Εξάμηνο 39
Δομές Δεδομένων, 3ο Εξάμηνο 40
Διαγραφή από την Αρχή Διπλά Συνδεδεμένης Λίστας Δομές Δεδομένων, 3ο Εξάμηνο 41
Διαγραφή από το Τέλος Διπλά Συνδεδεμένης Λίστας Δομές Δεδομένων, 3ο Εξάμηνο 42
Δομές Δεδομένων, 3ο Εξάμηνο 43
Κυκλικά Συνδεδεμένες Λίστες Ο τελευταίος κόμβος έχει ως επόμενο κόμβο τον πρώτο κόμβο. Έστω: h πρώτος κόμβος στη λίστα. t τελευταίος κόμβος στη λίστα. t.next = h; h.previous = t; Εξ ορισμού, στην κυκλικά συνδεδεμένη λίστα κάθε κόμβος έχει προηγούμενο και επόμενο. Μπορούμε να αγνοήσουμε τον κόμβο κεφαλής (head) (εξυπηρετούσε: κάθε κόμβος να έχει έναν προηγούμενο). Μπορούμε να αγνοήσουμε τον κόμβο ουρά (tail) (εξυπηρετούσε: κάθε κόμβος να έχει έναν επόμενο). Σε λίστα με μόνο 1 κόμβο, ο προηγούμενος και επόμενός του είναι ο ίδιος. Δομές Δεδομένων, 3ο Εξάμηνο 44
Κυκλικά Διπλά Συνδεδεμένη Λίστα Δομές Δεδομένων, 3ο Εξάμηνο 45
Σύνοψη Οι λίστες σαν δομή μοιάζουν στις βασικές πράξεις με τους πίνακες. Υποστηρίζουν δυναμική δέσμευση μνήμης (αντίθετα με τους πίνακες). εν υποστηρίζουν τυχαία προσπέλαση. Υποστηρίζουν κάποιες διαγραφές σε O(1) χρόνο (αντίθετα με πίνακες). Εισαγωγή / ιαγραφή: Από αρχή / τέλος σε O(1) χρόνο. Ενδιαμέσως (μετά / πριν από κόμβο) σε O(n) χρόνο (λόγω αναζήτησης). Αναζήτηση: σε O(n) χρόνο. Ερώτηση: μπορούμε να έχουμε τόσο καλή αναζήτηση σε μια ταξινομημένη λίστα (απλά / διπλά συνδεδεμένη / κυκλική) όσο σε έναν ταξινομημένο πίνακα? Πώς / Γιατί? Δομές Δεδομένων, 3ο Εξάμηνο 46