Ε. ΠετράκηςΛίστες1 Λίστα: πεπερασμένη σειρά στοιχείων ίδιου τύπου Οι πράξεις εξαρτώνται από τον τύπο της λίστας και όχι από τον τύπο δεδομένων Λίστα: ο πιο γενικός τύπος Στοίβες,Ουρές: δεν ορίζονται όλες οι πράξεις Διατεταγμένη λίστα: κάθε στοιχείο έχει συγκεκριμένη θέση
Ε. ΠετράκηςΛίστες2 λίστα ή κεφαλή πληρο- φορία επόμενο λίστα νέο στοιχείο Εισαγωγή μετά την τρέχουσα θέση τρέχων κόμβος τέλος ή ουρά
Ε. ΠετράκηςΛίστες3 λίστα ή κεφαλή λίστα νέο στοιχείο εισαγωγή στην τρέχουσα θέση τρέχων κόμβος τέλος ή ουρά
Ε. ΠετράκηςΛίστες4 λίστα ή κεφαλή λίστα ή κεφαλή διαγραμμένο στοιχείο διαγραφή μετά την τρέχουσα θέση τρέχων τέλος ή ουρά
Ε. ΠετράκηςΛίστες5 λίστα ή Κεφαλή λίστα ή κεφαλή διαγραμμένο στοιχείο διαγραφή στην τρέχουσα θέση τρέχων κόμβος τέλος ή ουρά
Ε. ΠετράκηςΛίστες6 Ορολογία Άδεια λίστα: δεν έχει στοιχεία Μήκος: αριθμός στοιχείων στη λίστα κεφαλή ή λίστα: δείκτης στην αρχή της λίστας ουρά: δείκτης στο τέλος της λίστας τρέχων: δείκτης στο τρέχων στοιχείο διατεταγμένη: στοιχεία σε αύξουσα ή φθίνουσα σειρά
Ε. ΠετράκηςΛίστες7 Διαδικασίες setFirst: ο δείκτης “τρέχων” δείχνει στην “κεφαλή” της λίστας setPos(i): ο δείκτης “τρέχων” δείχνει στο i-ιοστό στοιχείο currValue: δίνει την τιμή του στοιχείου που δείχνει ο “τρέχων” next/prev: ο “τρέχων” δείχνει στο επόμενο/προηγούμενο στοιχείο clear: διαγραφή όλων των στοιχείων της λίστας insert: εισάγει ένα στοιχείο μετά τη θέση (ή στην θέση) που δείχνει ο τρέχων append: εισάγει ένα στοιχείο στην “ουρά” (στο τέλος της λίστας) remove: διαγράφει το στοιχείο μετά την θέση (ή στην θέση) που δείχνει ο “τρέχων” find(key): ο τρέχων δείχνει στο πρώτο στοιχείο με τιμή “key” isInList: ναί/όχι ανάλογα με αν ο τρέχων δείχνει σε στοιχείο της λίστα isEmpty: ναί/όχι ανάλογα με το αν η λίστα είναι άδεια ή όχι
Ε. ΠετράκηςΛίστες8 ΑΤΔ Λίστα template class list {// κλάση λίστα ΑΤΔ στην C++ public: list(const int = LIST_SIZE); // κατασκευαστής ~list( );// καταστροφέας void clear ( );// αφαίρεσε όλα τα στοιχεία void insert(const ELEM &); // εισαγωγή στοιχείου στην θέση του τρέχοντος void append(const ELEM &); // εισαγωγή στοιχείου στο τέλος ELEM remove ( );// διαγραφή στοιχείου στην θέση του τρέχοντος void setFirst ( );// ο τρέχων δείκτης στη κεφαλή void prev ( ) ;// ο τρέχων δείχνει στο προηγούμενο στοιχείο void next ( );// ο τρέχων δείκτης στο επόμενο στοιχείο int length ( ) const;// επιστρέφει το μήκος της λίστας void setPos(const int);// ο τρέχων δείχνει στη θέση του ι στοιχείου void setValue(const ELEM &) // βάλε τιμή στο στοιχείο που δείχνει ο τρέχων bool isEmpty( ) const;// ναί/όχι ανάλογα με το αν είναι άδεια η λίστα bool isInList( ) const;// ναί/όχι αν ο τρέχων δείχνει στην λίστα bool find(const ELEM &);// ναι/οχι αν υπάρχει στοιχείο με τιμή ELEM };
Ε. ΠετράκηςΛίστες9 Επανάληψη Διάσχιση λίστας MyList for (MyList.first( ); MyList.isInList( ); MyList.next( )) DoSomething(MyList.currValue( )); Αν MyList: ( ) και ο τρέχων δείχνει στο 32 τότε η MyList.insert(90) αλλάζει τη λίστα σε ( )
Ε. ΠετράκηςΛίστες10 Υλοποίηση Λίστας Με Πίνακα: πολύ γρήγορη υλοποίηση Τα στοιχεία μπαίνουν σε πίνακα Στατική: ο αριθμός των στοιχείων της λίστας μικρότερος από το δεσμευμένο μέγεθος Δυναμική Μνήμη: αργή αλλά γενική υλοποίηση Δεσμεύει δυναμικά μνήμη για νέα στοιχεία Αποδεσμεύει μνήμη για στοιχεία που δεν χρειάζονται Δυναμική: δεν υπάρχει περιορισμός στον αριθμό των στοιχείων (το όριο είναι η μνήμη του ΗΥ)
Ε. ΠετράκηςΛίστες11 Εφαρμογές Πίνακα (1) Στοιχεία σε συνεχόμενες θέσεις πίνακα Κεφαλή της λίστας στη θέση 0 Εισαγωγή ή διαγραφή προκαλεί μετατόπιση στοιχείων στον πίνακα
Ε. ΠετράκηςΛίστες12 template class list {//υλοποίηση με πίνακα private: int msize // μέγιστο αριθμός στοιχείων λίστας int numinlist// πραγματικός αριθμός στοιχείων στην λίστα int curr;// θέση του τρέχοντος δείκτη ELEM* listarray;// πίνακας που αποθηκεύει τα στοιχεία public: list (const int=LIST_SIZE); // κατασκευαστής ~list( );// καταστροφέας void clear( );// αφαίρεσε όλα τα στοιχεία από την λίστα void insert(const ELEM &);// εισαγωγή στοιχείου στη θέση τρέχων void append(const ELEM &);// εισαγωγή στοιχείου στην ουρά της λίστας ELEM remove( );// διαγραφή στοιχείου στη θέση που δείχνει ο τρέχων void setFirst( );// ο τρέχων δείκτης πάει στην πρώτη θέση void prev( );// ο τρέχων δείκτης πάει στη προηγούμενη θέση void next( );// ο τρέχων δείκτης πάει στην επόμενη θέση int length( ) const;// επέστρεψε το μέγεθος της λίστας void setPos(const int);// ο δείκτης τρέχων στην θέση i void setValue(const ELEM &);// βάλε τιμή ΕLEM στο στοιχείο που δείχνει ο τρέχων ELEM currValue( ) const;// επέστρεψε την τιμή του στοιχείου τρέχων bool isEmpty( ) const;// ναι/όχι ανάλογα αν η λίστα είναι άδεια bool isInList( ) const;// ναί/όχι αν ο δείκτης τρέχων δείχνει στη λίστα bool find(const ELEM &);// βρες την τιμή (από τη θέση του τρέχοντος) };
Ε. ΠετράκηςΛίστες13 template List ::List(int sz)// κατασκευαστής: αρχικοποίηση { msize = sz; numinlist = 0; curr = 0; listarray = new ELEM[sz]; } template List ::~List( ) // καταστροφέας { delete [ ] listarray; } template void List ::clear( ) // σβήσε όλα τα στοιχεία από τη λίστα { numinlist = 0; curr = 0; } // αρχικοποίηση τιμών λίστας template void List ::insert(const Elem item) { // βάλε το στοιχείο στη θέση τρέχων // ο πίνακας δεν πρέπει να είναι γεμάτος και ο “τρέχων” πρέπει να ανήκει στην λίστα assert((numinlist = 0) && (curr <= numinlist)); for(int i = numinlist; i > curr; i--) // μετακίνησε το στοιχείο για να δημιουργηθεί χώρος listarray[i] = listarray[i - 1]; listarray[curr] = item; numinlist++; // αύξησε τον αριθμό των στοιχείων της λίστας
Ε. ΠετράκηςΛίστες14 template void List ::append(const Elem item) { // βάλε το στοιχείο στο τέλος της λίστας assert(numinlist < msize); // η λίστα δεν πρέπει να είναι γεμάτη listarray[numinlist++] = item; // αύξησε τον αριθμό στοιχείων της λίστας } template ELEM List ::remove( ) { // σβήσε και επέστρεψε το τρέχων στοιχείο assert( !isEmpty( ) && isInList( ) ); // το στοιχείο πρέπει να είναι στην λίστα temp = listarray[curr]; // αποθήκευσε το στοιχείο που σβήστηκε for (int i=curr; i < numlist-1; i++) // μετακίνησε τα στοιχεία μη θέση κάτω listarray[i] = listarray[i+1]; numinlist--; // μείωσε τον αριθμό των στοιχείων της λίστας return temp; } template void List ::setFirst( )// ο δείκτης τρέχων πάει στην πρώτη θέση { curr = 0; } template void List ::prev( ) // ο δείκτης τρέχων πάει στην προηγούμενη θέση { curr--; }
Ε. ΠετράκηςΛίστες15 template void List ::next( ) // ο δείκτης τρέχων πάει στην επόμενη θέση { curr++; } template int List::length( ) const // ο αριθμός των στοιχείων της λίστας { return numinlist; } template void List ::setPos(int pos)// ο δείκτης τρέχων πάει στην θέση pos {curr = pos; } template void List ::setValue(const Elem val) { // βάλε τιμή στο στοιχείο τρέχων assert(isInList( )); // o δείκτης τρέχων πρέπει να δείχνει στην λίστα listarray[curr] = val; } template Elem List ::currValue( ) const { //η τιμή του στοιχείου που δείχνει ο τρέχων assert(isInList( )); return listarray[curr]; }
Ε. ΠετράκηςΛίστες16 template bool List ::isEmpty( ) const // ναι/όχι αν η λίστα είναι άδεια { return numinlist == 0; } template bool List ::isInList( ) const// ναί/όχι ανάλογα αν ο δείκτης τρέχων δείχνει σε στοιχείο της λίστας { return (curr >= 0) && (curr < numinlist); } template bool List ::find(int val) {// βρες την τιμή (ξεκίνησε από το τρέχων στοιχείο) while (isInList( )) // σταμάτησε αν φτάσεις στο τέλος if (key(currValue( )) == val) return TRUE; // βρέθηκε else next( ); return FALSE ; // δεν βρέθηκε }
Ε. ΠετράκηςΛίστες17 Υλοποίηση Πίνακα (2) λίστα κόμβοι NULL
Ε. ΠετράκηςΛίστες Λίστα Λίστα Λίστα Λίστα 4
Ε. ΠετράκηςΛίστες Λίστα 4 Λίστα 2 Λίστα 3 Λίστα 1
Ε. ΠετράκηςΛίστες20 template class list {// υλοποίηση συνδεδεμένη λίστας με πίνακα private: int msize // μέγιστος αριθμός στοιχείων int numinlist// αριθμός στοιχείων στην λίστα int curr;// θέση που δείχνει ο int avail;// επόμενη διαθέσιμη θέση ELEM* listarray;// πίνακας που αποθηκεύει τα στοιχεία int* listarray_next;// πίνακας που αποθηκεύει τον δείκτη για // τα επόμενα στοιχεία int get_node( );// πάρε τη θέση του διαθέσιμου κόμβου void free_node( );// επέστρεψε το κόμβο στο πίνακα void insert(int, const ELEM&); // εισαγωγή μετά τον κόμβο που δείχνει ο p void delete(int, ELEM*);// εισαγωγή μετά τον κόμβο που δείχνει ο p public: list (const int=LIST_SIZE); // κατασκευαστής ~list( );// καταστροφέας void clear( );// σβήσε όλα τα στοιχεία της λίστας void insert(const ELEM&);// εισαγωγή στοιχείου στη τρέχουσα θέση void append(const ELEM&);// εισαγωγή στοιχείου στο τέλος της λίστας ELEM remove( );// διαγραφή τρέχοντος στοιχείου void setFirst( );// ο τρέχων δείκτης πάει στην πρώτη θέση void prev( );// ο τρέχων δείκτης στη προηγούμενη θέση void next( );// ο τρέχων δείκτης στην επόμενη θέση int length( ) const;// ο αριθμός των στοιχείων της λίστας };
Ε. ΠετράκηςΛίστες21 template List ::list(int sz) {// κατασκευαστής: αρχικοποίηση msize = sz; numinlist = 0; curr = 0; listarray = new Elem[sz]; listarray_next = new int[sz]; avail = 0;// το πρώτο διαθέσιμο στοιχείο for (i=0; i < msize; i++) listarray_next[i] = i+1;// κάθε στοιχείο δείχνει στο επόμενο listarray_next[msize-1] = nothing;// το τελευταίο στοιχείο δεν έχει επόμενο } template List ::~list( ) // καταστροφέας { delete [ ] listarray; delete [ ] listarray_next; }
Ε. ΠετράκηςΛίστες22 template int list ::get_node( ) { //πάρε τον επόμενο διαθέσιμο κόμβο if (avail == nothing) // από την στοίβα error(‘list overflow’) else { int pos = avail; avail = listarray_next[avail]; return pos; } template // κάνε τον κόμβο διαθέσιμο void list ::free_node (int p) { listarray_next[p] = avail; // βάλε τον κόμβο πίσω στη στοίβα avail =p; }
Ε. ΠετράκηςΛίστες23 template //εισαγωγή μετά το στοιχείο που δείχνει ο “p” void list ::insert(int p, const ELEM& x) { if (p = msize) error (‘void insertion’) else { int q = get_node( ); listarray[q] = x; listarray_next[q] = listarray_next[p]; listarray_next[p] = q; } template void list ::delete(int p; ELEM* x) { if ( p > 0 || p >= msize) // σβήσε το στοιχείο μετά το στοιχείο error (‘void deletion’); // που δείχνει το “p” else { int q = listarray_next[p]; *x = listarray[q]; listarray_next[p] = listarray_next[q]; free_node(q); }
Ε. ΠετράκηςΛίστες24 Δυναμική Παραχώρηση Μνήμης Δεσμεύει μνήμη για νέα στοιχεία όταν χρειάζεται Κάθε κόμβος είναι ένα ανεξάρτητο στοιχείο Η κλάση κόμβος template class link { // ένας κόμβος διασυνδεδεμένης // λίστας public: ELEM element// τιμή κόμβου link *next;// δείκτης στον επόμενο κόμβο link(const ELEM & val, link *nextval = NULL); {element = val; next = nextval;} link(link *nextval = NULL) {next = nextval;} ~link( ) { } }
Ε. ΠετράκηςΛίστες25 template class List { // κλάση συνδεδεμένης λίστας private: Link * head;// δείκτης στη κεφαλή της λίστας Link * tail; // δείκτης στο τελευταίο στοιχείο της λίστας Link * curr; // θέση τρέχοντος στοιχείου public: List( ); // κατασκευαστής ~List( ); // καταστροφέας void clear( ); // αφαίρεσε όλα τα στοιχεία από τη λίστα void insert(const Elem); // εισαγωγή στοιχείου στην τρέχουσα θέση void append(const Elem); // εισαγωγή στοιχείου στο τέλος της λίστας Elem remove( ); // διαγραφή τρέχοντος στοιχείου void setFirst( ); // ο τρέχων δείκτης στην πρώτη θέση void prev( ); // ο τρέχων δείκτης στην προηγούμενη θέση void next( ); // ο τρέχων δείκτης στην επόμενη θέση int length( ) const; // αριθμός στοιχείων στην λίστα void setPos(int); // ο τρέχων δείκτης δείχνει στο στοιχείο i void setValue(const Elem); // δώσε τιμή στο στοιχείο που δείχνει ο τρέχων Elem currValue( ) const; // επέστρεψε την τιμή του τρέχοντος στοιχείου bool isEmpty( ) const; // ναί/όχι αν η λίστα είναι άδεια bool isInList( ) const; // ναί/όχι αν ο τρέχων δείκτης δείχνει στην λίστα bool find(Elem); // βρες την τιμή (από το στοιχείο τρέχων) };
Ε. ΠετράκηςΛίστες26 template List ::List( ) // κατασκευαστής { head = new Link ; tail = head; curr = head; } // αρχικοποίηση template List ::~List( ) { // καταστροφέας while(head != NULL) {// επέστρεψε τους κόμβους curr = head; // στην ελεύθερη μνήμη head = head next; delete curr; } template void List ::clear( ) {// αφαίρεσε όλα τα στοιχεία από τη λίστα while (head next != NULL) {// επέστρεψε τους κόμβους // στην ελεύθερη μνήμη curr = head next;// διατηρεί την κεφαλή-κόμβο!! head next = curr next; // αλλιώς, είναι ίδιο με το ~List( ) delete curr; } curr = head; tail = head; // αρχικοποίηση }
Ε. ΠετράκηςΛίστες27 template void List ::insert(const Elem item) // εισαγωγή στοιχείου στη τρέχουσα θέση { assert(curr != NULL); // πρέπει να δείχνει σε στοιχείο της λίστας curr next = new Link (item, curr next); if (tail == curr) new Elem tail = curr next; } template void List ::append(const Elem item) // εισαγωγή στοιχείου στο τέλος της λίστας { tail = tail next = new Link (item, NULL); } template Elem List ::remove( ) { // διαγραφή τρέχοντος στοιχείου assert(isInList( )); // ο τρέχων πρέπει να δείχνει σε στοιχείο λίστας Elem temp = curr next element; // η τιμή του κόμβου που θα σβηστεί Link * ltemp = curr next; // ο δείκτης στο κόμβο που θα σβηστεί curr next = ltemp next; // διαγραφή κόμβου από τη λίστα if (tail == ltemp) tail = curr; // αν είναι τελευταίο στοιχείο: δώσε τιμή δείκτη delete ltemp; // ελευθέρωση μνήμης return temp; // επέστρεψε την τιμή που σβήστηκε }
Ε. ΠετράκηςΛίστες28 template void List ::setFirst( ) // ο τρέχων δείκτης στη πρώτη θέση { curr = head; } template void List ::next( ) // ο τρέχων δείκτης στην επόμενη θέση { if (curr != NULL) curr = curr next; } template void List ::prev( ) { // ο τρέχων δείκτης στην προηγούμενη θέση Link * temp = head; if ((curr == NULL) || (curr == head)) // κανένα προηγούμενο στοιχείο { curr = NULL; return; } // άρα απλά επέστρεψε while ((temp!=NULL) && (temp next != curr)) temp=temp next; curr = temp; } template int List ::length( ) const { // ο αριθμός των στοιχείων της λίστας int cnt = 0; for (Link * temp = head next; temp != NULL; temp = temp next) cnt++; }
Ε. ΠετράκηςΛίστες29 template bool List ::find(Elem val) { // βρες την τιμή (ξεκινώντας από το τρέχων) while (isInList( )) if (key(curr next element) == val) return TRUE; else curr = curr next; return FALSE; // δεν βρέθηκε } template void List ::setPos(int pos) { // ο τρέχων δείκτης στη θέση pos curr = head; for (int i = 0; (curr != NULL) && (i < pos) i++) curr = curr next; } template void List ::setValue(const Elem val) {// δώσε τιμή στο τρέχων στοιχείο assert(isInList()); curr next element = val; }
Ε. ΠετράκηςΛίστες30 template Elem List ::currValue const // η τιμή του τρέχοντος στοιχείου { assert(isInList( )); return curr next element; } template bool List ::isEmpty( ) const // ναι/όχι αν η λίστα είναι άδεια { return head next == NULL; } template bool List ::isInList( ) const // ναι/όχι αν ο τρέχων δείκτης δείχνει // σε στοιχείο της λίστας { return (curr != NULL) && (curr next != NULL); }
Ε. ΠετράκηςΛίστες31 Σύγκριση Υλοποιήσεων Υλοποίηση Λίστας με πίνακα: Εισαγωγή και διαγραφή χρειάζονται χρόνο (n) Πρόσβαση στο επόμενο ή προηγούμενο στοιχείο σε χρόνο (1) Δέσμευση χώρου μνήμης από την αρχή Αναδιοργώνωση του χώρου όταν ο πίνακας γεμίσει Ταχύτερη υλοποίηση στις περισσότερες περιπτώσεις Συνδεδεμένες Λίστες (Δυναμική ή Στατική): Εισαγωγή και Διαγραφή χρειάζονται χρόνο (1) Πρόσβαση στο επόμενο ή προηγούμενο στοιχείο σε χρόνο (n) Ο χώρος μεγαλώνει όσο πληθαίνουν τα στοιχεία Η πιο αργή υλοποίηση (“delete” και “new” προκαλούν system interrupts)
Ε. ΠετράκηςΛίστες32 Διπλά Συνδεδεμένες Λίστες Επιτρέπει άμεση προσπέλαση σε επόμενα αλλά ή προηγούμενα στοιχεία του τρέχοντος δείκτη Οι εισαγωγές και οι διαγραφές πρέπει να ενημερώνουν τους δείκτες στα “επόμενα” και “προηγούμενα” στοιχεία του τρέχοντος κόμβου Εύκολη υλοποίηση curr next = new (item, curr next, curr); if (curr next != NULL) curr next prev = curr next
Ε. ΠετράκηςΛίστες33 τρέχων Εισαγωγή
Ε. ΠετράκηςΛίστες34 τρέχων Διαγραφή
Ε. ΠετράκηςΛίστες35 Κυκλικά Συνδεδεμένες Λίστες Ο δείκτης τελευταίου στοιχείου δείχνεί στο πρώτο στοιχείο κεφαλήτρέχωνουρά κεφαλήτρέχωνουρά