Λίστες (Lists) Ορέστης Τελέλης telelis@unipi.gr Τµήµα Ψηφιακών Συστηµάτων, Πανεπιστήµιο Πειραιώς Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 1 / 50
Σύνοψη Προηγούµενου Στοίβες (Stacks) «Last-In First-Out» (LIFO): Εισαγωγή (push) στην κορυφή της στοίβας O(1) χρόνος. Εξαγωγή (pop) από την κορυφή της στοίβας O(1) χρόνος. Ουρές (Queues) «First-In First-Out» (FIFO): Εισαγωγή (insert / enqueue) στο τέλος της ουράς O(1) χρόνος. Εξαγωγή (remove / dequeue) από την αρχή της ουράς O(1) χρόνος. Ουρές Προτεραιότητας (Priority Queues). Εισαγωγή (insert / enqueue) στη «σωστή ϑέση» στην ουρά O(n) χρόνος. Εξαγωγή (remove / dequeue) από το ένα άκρο της ουράς O(1) χρόνος. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 2 / 50
Ασκηση 2 Υλοποίηση Στοίβας µε ύο Ουρές ιαθέτουµε δύο αντικείµενα δοµής ουράς, Q1, Q2. Υποστηρίζουν τις συνήθεις λειτουργίες ουρών: insert, remove, peekfront, isempty, isfull, size Ζητούνται υλοποιήσεις των λειτουργιών push και pop «εικονικής» στοίβας: µόνο µε χρήση των δύο ουρών Q1, Q2, σαν αποθηκευτικό µέσο, µόνο µε χρήση των λειτουργιών ουράς (επί των Q1, Q2). Να δοθούν δύο υλοποιήσεις: 1. Στην πρώτη, η λειτουργία pop να είναι χρόνου O(1). 2. Στη δεύτερη, η λειτουργία push να είναι χρόνου O(1). Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 3 / 50
Ασκηση 2 Υλοποίηση Στοίβας µε ύο Ουρές class Stack { private Queue Q1; private Queue Q2; public Stack(int maxsize) { Q1 = new Queue(maxSize); Q2 = new Queue(maxSize); public void push(int item) { /* implementation??? */ public int pop() { /* implementation??? */ Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 4 / 50
Ασκηση 2 pop σε χρόνο O(1) public int pop() { return(q1.remove()); public void push(int item) { Q2.insert(item); while(!q1.isempty() ) Q2.insert( Q1.remove() ); // Insert in Q2 // "Empty" Q1 into Q2 Queue tempq = Q1; Q1 = Q2; Q2 = tempq; // Exchange the queues names Πολυπλοκότητα της push: O(n). Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 5 / 50
Συνδεδεµένες Λίστες Linked Lists Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 6 / 50
Συνδεδεµένες Λίστες: Εισαγωγή (1/2) Είδαµε δοµές υλοποιηµένες µε στατική δέσµευση της µνήµης: Πίνακες, Στοίβες, Ουρές. Στατική δέσµευση πινακα προσφέρει τυχαία προσπέλαση σε O(1) χρόνο. Οµως: Η τυχαία προσπέλαση απουσιάζει εξ ορισµού, από στοίβες και ουρές. Η στατική δέσµευση έχει µειονεκτήµατα (που έχουµε ξαναδεί): Πρέπει να γνωρίζουµε άνω ϕράγµα πλήθους των δεδοµένων µας. Μπορεί σηµαντικό ποσό δεσµευµένης µνήµης να µένει αχρησιµοποίητο. Στο εξής: δοµές δεδοµένων µε δυναµική διαχείριση µνήµης. Και ϑα µελετήσουµε δοµές που ϐελτιστοποιούν το χρόνο της αναζήτησης. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 7 / 50
Συνδεδεµένες λίστες: Εισαγωγή (2/2) Μία συνδεδεµένη λίστα αποτελείται από µία συλλογή δυναµικά δεσµευµένων κόµβων µε συνδέσεις µεταξύ τους. Ευµετάβλητη δοµή δεδοµένων που µπορεί να χρησιµοποιηθεί σε πολλές περιπτώσεις αποθήκευσης δεδοµένων. Επιδέχεται διαφορετικές υλοποιήσεις που εξυπηρετούν διαφορετικές εκδοχές ϐασικών πράξεων. Μπορεί να αντικαταστήσει έναν πίνακα ως ϐάση για άλλες δοµές αποθήκευσης, όπως στοίβες και ουρές. Εκτός αν απαιτείται τυχαία προσπέλαση σε µεµονωµένα στοιχεία µε τη χρήση δείκτη, π.χ., A[2]. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 8 / 50
Απλά Συνδεδεµένη Λίστα Απλά Συνδεδεµένη Λίστα: Σύνολο κόµβων που αποθηκεύουν αντικείµενα (δεδοµένα). Κάθε κόµβος στη λίστα «δείχνει» τον επόµενο, εκτός από τον τελευταίο. Κόµβος = αντικείµενο + αναφορά στον επόµενο κόµβο. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 9 / 50
Βασικές Πράξεις Λίστας Εισαγωγή ιαφορετικές Εκδοχές: 1. στην αρχή της λίστας, στο τέλος της λίστας, χρόνου O(1) 2. µετά από κόµβο µε δεδοµένο κλειδί, χρόνου O(n) ιαγραφή ιαφορετικές Εκδοχές: 1. πρώτου / τελευταίου κόµβου της λίστας, χρόνου O(1) 2. ενός κόµβου µε δεδοµένο κλειδί, χρόνου O(n) Αναζήτηση κόµβου µε δεδοµένο κλειδί. χρόνου O(n) Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 10 / 50
Κόµβος Λίστας class Node { public int idata; public Object ddata; public Node next; // data item (key) // data item public Node(int id, Object dd) { idata = id; ddata = dd; public void display() { System.out.println("{ " + idata + ", " + ddata.tostring () + " "); // End of class Node Σηµείωση: Αυτή η κλάση είναι αυτο-αναφερόµενη (self-referencing). Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 11 / 50
Εισαγωγή σε Απλά Συνδεδεµένη Λίστα Πρέπει να οριστεί η ϑέση που ϑα γίνει η εισαγωγή. Εστω current η ϑέση µετά την οποία ϑα γίνει η εισαγωγή. tmp.next = current.next; current.next = tmp; // next of node x is node b // next of node a is node x Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 12 / 50
ιαγραφή από Απλά Συνδεδεµένη Λίστα (1/2) Βασική Περίπτωση ιαγραφή του στοιχείου x από τη λίστα. Εστω current η ϑέση του κόµβου πριν το x. Ο δείκτης προς τον επόµενο του current ϑα πρέπει να παρακάµψει τον x. current.next = (current.next).next; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 13 / 50
Βασική Υλοποίηση Απλά Συνδεδεµένη Λίστα Εισαγωγή: στην αρχή της λίστας, µετά από κόµβο µε δεδοµένο κλειδί. ιαγραφή: από την αρχή της λίστας, κόµβου µε δεδοµένο κλειδί. Αναζήτηση: κόµβου µε δεδοµένο κλειδί. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 14 / 50
Υλοποίηση (1/4): Κλάση LinkedList class LinkedList { private Node first; // ref to first node on list // ------------------------------------------------------------ public LinkedList() { first = null; // empty list // ------------------------------------------------------------ public boolean isempty() { return (first == null); // Returns true if empty. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 15 / 50
Υλοποίηση: Εισαγωγή στην + ιαγραφή από την Αρχή public void insertfirst(int id, Object dd) { Node newnode = new Node(id, dd); newnode.next = first; first = newnode; // make new node // newnode --> old first // first --> newnode public Object deletefirst() { // delete first item if (isempty()) return(null); Node tmp = first; first = first.next; return(tmp.ddata); // nothing to delete // save reference to "old" first // "delete" it: first-->old next // return data of deleted node Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 16 / 50
Υλοποίηση (2/5): Κλάση LinkedList // ------------------------------------------------------------ public void displaylist() { System.out.print("List (first-->last): "); Node current = first; // start at beginning of list while(current!= null) { // until end of list, current.display(); // print data current = current.next; // move to next link System.out.println(""); // ------------------------------------------------------------ Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 17 / 50
Υλοποίηση: Αναζήτηση Κόµβου private Node findnode(int key) { // returns node with given key if (isempty()) return(null); // nothing to find Node current = first; // start at first while(current.idata!= key) { // while no match, if(current.next == null) // if end of list, return null; // didn t find it else // not end of list, current = current.next; // go to next node return(current); // found it Σχόλιο: Αυτή η µέθοδος είναι private διότι: επιστρέφει αντικείµενο τύπου Node «εσωτερικό» της λίστας, δε ϑέλουµε ο χρήστης να µπορεί να «πειράζει» τέτοια αντικείµενα, εξυπηρετεί άλλες (public) µεθόδους: find, insertafter, delete Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 18 / 50
Υλοποίηση: Αναζήτηση ( εδοµένων) public Object find(int key) { // returns data for a given key Node somenode = findnode(key); if (somenode == null) return(null); else return(somenode.ddata); Σχόλιο: Αυτή η µέθοδος είναι public: διαθέσιµη στον τελικό χρήστη, για την ανάκτηση των δεδοµένων του, χρησιµοποιεί (εσωτερικά) την findnode για ανάκτηση του σχετικού κόµβου. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 19 / 50
Υλοποίηση: «Εισαγωγή µετά από» public boolean insertafter(int key, int id, Object dd) { Node previous = findnode(key); if (previous == null) return(false); else { // find node // no previous found // no insertion // insert after Node newnode = new Node(id, dd); // make new node newnode.next = previous.next; previous.next = newnode; return(true); // success Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 20 / 50
Υλοποίηση: ιαγραφή µε Κλειδί public Object delete(int key) { if (isempty()) return(null); Node current = first; Node previous = first; // current node // previous of current while(current.idata!= key) { // search for node if(current.next == null) // not found: end of list return(null); else { // go to next node previous = current; current = current.next; // found node with key if(current == first) first = first.next; // delete first else previous.next = current.next; // delete current return(current.ddata); // return deleted node s data Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 21 / 50
class LinkedListApp { public static void main(string[] args) { LinkedList alist = new LinkedList(); alist.insertfirst(22, 2.99); alist.insertfirst(44, 4.99); alist.insertfirst(66, 6.99); alist.insertfirst(88, 8.99); alist.displaylist(); Node f = alist.find(44); if (f!= null) System.out.println("Found Node with key " + f.idata "!!! "); else System.out.println("Can t find node."); Node d = alist.delete(66); if (d!= null) System.out.println("Deleted node with key " + d.idata); else System.out.println("Can t delete node."); alist.displaylist(); Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 22 / 50
Παράδειγµα: Υλοποίηση Στοίβας class Stack { private LinkedList list; public Stack() { list = new LinkedList(); public isempty() { return(list.isempty()); public void push(object dd) { list.insertfirst(0, dd); public Object pop() { return(list.deletefirst()); Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 23 / 50
Παράδειγµα: Υλοποίηση Ουράς µε Λίστα Η ουρά χρειάζεται εισαγωγή στο ένα άκρο, αποµάκρυνση από το άλλο. Απαιτείται η συντήρηση επιπλέον αναφοράς στο τέλος της λίστας: class List { private Node first; private Node last; //.................. Υλοποίηση των επιπλέον µεθόδων: public void insertlast(int id, Object dd); Προσοχή στην ενηµέρωση και της αναφοράς first, αν χρειάζεται. public Object deletelast(); Προσοχή στην ενηµέρωση και της αναφοράς first, αν χρειάζεται. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 24 / 50
Παράδειγµα: Υλοποίηση Ουράς class Queue { private LinkedList list; public Queue() { list = new LinkedList(); public isempty() { return(list.isempty()); public void insert(int id, Object dd) { list.insertlast(id, dd); public Object remove() { return(list.deletelast()); Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 25 / 50
Απλοποίηση Υλοποίησης ιαχείριση Ειδικών Περιπτώσεων Προβλήµατα µε τη ϐασική περιγραφή λειτουργιών απλά συνδεδεµένης λίστας. ιαγραφή: Κάθε ϕορά που διαγράφεται ένας κόµβος, πρέπει να ϐρίσκουµε τον προηγούµενο του. Ειδική περίπτωση: διαγραφή πρώτου κόµβου. Εισαγωγή: Ο κόµβος που εισάγουµε πρέπει να ακολουθεί κάποιον κόµβο. Ειδική περίπτωση: εκτός κι αν είναι ο πρώτος. Μπορούµε να απλοποιήσουµε την υλοποίηση (τουλάχιστον εννοιολογικά) εξασφαλίζοντας τη διατήρηση µιας αναλλοίωτης ιδιότητας: Σε µια απλά συνδεδεµένη λίστα, κάθε κόµβος έχει έναν προηγούµενο. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 26 / 50
Κόµβος κεφαλής (Head Node) Κόµβος κεφαλή (Head) της λίστας: επιπλέον κόµβος που δεν διατηρεί δεδοµένα. εξυπηρετεί στο να ικανοποιηθεί η απαίτηση κάθε κόµβος να έχει έναν προηγούµενο κόµβο στη λίστα. Με χρήση του κόµβου κεφαλής µπορούµε να διαχειριστούµε εύκολα τις ειδικές περιπτώσεις εισαγωγής και διαγραφής στην αρχή της λίστας. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 27 / 50
Κόµβος κεφαλής (Head Node) head.ddata = null; Χρήση κόµβου κεφαλής για συνδεδεµένη λίστα. head.next = null; Κενή λίστα όταν χρησιµοποιούµε κόµβο κεφαλής. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 28 / 50
Πλεονεκτήµατα Χρήσης Κόµβου Κεφαλής Ενοποίηση των 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 στο τέλος). Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 29 / 50
ιαγραφή / Εισαγωγή στο Τέλος Με την έως τώρα υλοποίηση απαιτούν O(n) χρόνο. ιάσχιση όλης της λίστας µέχρι εύρεσης του τελευταίου κόµβου. ιαγραφή του τελευταίου κόµβου / Εισαγωγή µετά από τον τελευταίο κόµβο. Μπορεί να γίνει σε O(1) χρόνο, αν συντηρούµε αναφορά last, επιπλέον της αναφοράς first. Αν έχουµε άδεια λίστα µε κόµβο κεφαλή, τότε last=null. Η Εισαγωγή µετά από τον τελευταίο κόµβο ελέγχει αν last==null και εισάγει µετά από την κεφαλή, αν αυτό είναι αληθές. Η ιαγραφή του τελευταίου κόµβου ελέγχει αν last==null και επιστρέφει null, αν αυτό είναι αληθές. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 30 / 50
ιπλά Συνδεδεµένες Λίστες Doubly Linked Lists Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 31 / 50
ιπλά Συνδεδεµένες Λίστες Απλά Συνδεδεµένη Λίστα: υνατότητα αποδοτικής διάσχισης της λίστας προς µία κατεύθυνση. εν υπάρχει τρόπος να γνωρίζουµε τον προηγούµενο δεδοµένου κόµβου. ιπλά Συνδεδεµένη Λίστα: Κάθε κόµβος έχει επόµενο (next) και προηγούµενο (previous). υνατότητα διάσχισης διπλής κατεύθυνσης (π.χ., εκτύπωση σε ανάποδη σειρά), εφόσον διατηρούµε και µια αναφορά last. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 32 / 50
ιπλά Συνδ/νες Λίστες: Πλεονεκτήµατα Υλοποίηση Εισαγωγής και ιαγραφής ιαγραφή: απλοποιείται, γιατί δε χρειάζεται να κρατάµε τον προηγούµενο: είναι διαθέσιµος σαν current.previous. Εισαγωγή: µετά ή πριν από κόµβο µε δεδοµένο κλειδί. Μπορούµε να έχουµε κόµβο κεφαλή και τελείως ανάλογα κόµβο ουρά (tail node). Συντηρούν την αναλλοίωτη ιδιότητα ενός προηγούµενου και ενός επόµενου για κάθε κόµβο δεδοµένων. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 33 / 50
ιπλά Συνδεδεµένη Λίστα Κάθε κόµβος έχει δύο αναφορές σε άλλους κόµβους. Μία προς τον επόµενο και µια προς τον προηγούµενο κόµβο. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 34 / 50
Ορισµός Κόµβου ιπλά Συνδεδεµένης Λίστας class DoublyLinkedListNode { public int idata; public Object ddata; public DoublyLinkedListNode next; public DoublyLinkedListNode previous; // data key // data item // next node // previous node // --------------------------------------------------------- public DoublyLinkedListNode(int id, Object dd) { // constructor idata = id; ddata = dd; // end class DoublyLinkedListNode Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 35 / 50
Κενή ιπλά Συνδεδεµένη Λίστα µε Κεφαλή & Ουρά public DoublyLinkedList() { // Constructor head = new DoublyLinkedListNode(0,null); tail = new DoublyLinkedListNode(0,null); head.next = tail; tail.previous = head; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 36 / 50
ιπλά Συνδ/νη Λίστα: Εισαγωγή // insertafter current when current is a referece to node "a" newnode = new DoublyLinkedListNode(id, dd); 1. newnode.previous = current; 2. newnode.next = current.next; 3. newnode.previous.next = newnode; 4. newnode.next.previous = newnode; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 37 / 50
ιπλά Συνδ/νη Λίστα: ιαγραφή //delete(x) -- current is a reference to node with key "x" current.previous.next = current.next; current.next.previous = current.previous; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 38 / 50
Ορισµός ιπλά Συνδ/νης Λίστας χωρίς Κεφαλή και Ουρά class DoublyLinkedList { private DoublyLinkedListNode first; //ref to first item private DoublyLinkedListNode last; // ref to last item // ----------------------------------------------------- public DoublyLinkedList() { // constructor first = null; // no items on list yet last = null; Θα εξετάσουµε Εισαγωγή στην αρχή της λίστας: insertfirst() στο τέλος της λίστας: insertlast() µετά από κόµβο µε συγκεκριµένο κλειδί: insertafter(int key) Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 39 / 50
Εισαγωγή στην Αρχή ιπλά Συνδ/νης Λίστας DoublyLinkedListNode newnode=new DoublyLinkedListNode(id, dd); if (isempty()) last = newnode; else{ first.previous = newnode; newnode.next = first; // if empty list, // last --> newnode // newnode <-- old first // newnode --> old first first = newnode; // first --> newnode Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 40 / 50
Εισαγωγή στο Τέλος ιπλά Συνδ/νης Λίστας DoublyLinkedListNode newnode=new DoublyLinkedListNode(id, dd); if (isempty()) first = newnode; // if empty list, else { last.next = newnode; newnode.previous = last; last = newnode; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 41 / 50
Εισαγωγή µετά από κόµβο σε ιπλά Συνδ/νη Λίστα if(current==last) { // if last node, newnode.next = null; last = newnode; else { // not last node, newnode.next = current.next; current.next.previous = newnode; newnode.previous = current; // old current <-- newnode current.next = newnode; // old current --> newnode Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 42 / 50
// (assumes non-empty list) public boolean insertafter(int key, int id, Object dd) { DoublyLinkedListNode current = first; // start at beginning while(current.idata!= key) { // until match is found current = current.next; // move to next node if(current == null) return(false); // didn t find it DoublyLinkedListNode newnode = new DoublyLinkedListNode(id,dd); if(current==last) { // if last node, newnode.next = null; // newnode --> null last = newnode; // newnode <-- last else { // not last node, newnode.next = current.next;// newnode --> old next current.next.previous = newnode; newnode.previous = current; current.next = newnode; return true; // old current <-- newnode // old current --> newnode // found it, did insertion Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 43 / 50
ιαγραφή από την Αρχή ιπλά Συνδ/νης Λίστας if (first.next == null) last = null; else { first.next.previous = null; first = first.next; // if only one item // null <-- old next // first --> old next Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 44 / 50
ιαγραφή από το Τέλος ιπλά Συνδ/νης Λίστας // delete last node (assumes non-empty list) public Node deletelast() { Node temp = last; if(first.next == null) first=null;// if only one item else last.previous.next = null; // old previous --> null last = last.previous; return temp; // old previous <-- last Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 45 / 50
ιαγραφή Τυχαίου Κόµβου σε ιπλά Συνδ/νη Λίστα current.previous.next = current.next; current.next.previous = current.previous; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 46 / 50
// delete item with given key (assumes non-empty list) public Object delete(int key) { Node current = first; // start at beginning while(current.idata!= key) { // until match is found, current = current.next; // move to next node if(current == null) return(null); // didn t find it if(current==first) // found it; first item? first = current.next; else // old previous --> old next current.previous.next = current.next; if(current==last) // last item? last = current.previous; else // old previous <-- old next current.next.previous = current.previous; return(current.ddata); // return value Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 47 / 50
Κυκλικά Συνδεδεµένες Λίστες Ο τελευταίος κόµβος έχει ως επόµενο κόµβο τον πρώτο κόµβο. Εστω: h πρώτος κόµβος στη λίστα. t τελευταίος κόµβος στη λίστα. t.next = h; h.previous = t; Εξ ορισµού, στην κυκλικά συνδεδεµένη λίστα κάθε κόµβος έχει προηγούµενο και επόµενο. Μπορούµε να αγνοήσουµε τον κόµβο κεφαλής (head) (εξυπηρετούσε: κάθε κόµβος να έχει έναν προηγούµενο). Μπορούµε να αγνοήσουµε τον κόµβο ουρά (tail) (εξυπηρετούσε: κάθε κόµβος να έχει έναν επόµενο). Σε λίστα µε µόνο 1 κόµβο, ο προηγούµενος και επόµενός του είναι ο ίδιος. Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 48 / 50
Κυκλική ιπλά Συνδεδεµένη Λίστα first.previous = last; last.next = first; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 49 / 50
Σύνοψη Οι λίστες σαν δοµή µοιάζουν στις ϐασικές πράξεις µε τους πίνακες. Υποστηρίζουν δυναµική δέσµευση µνήµης (αντίθετα µε τους πίνακες). εν υποστηρίζουν τυχαία προσπέλαση. Υποστηρίζουν κάποιες διαγραφές σε O(1) χρόνο (αντίθετα µε πίνακες). Εισαγωγή / ιαγραφή: Από αρχή / τέλος σε O(1) χρόνο. Ενδιαµέσως (µετά / πριν από κόµβο) σε O(n) χρόνο (λόγω αναζήτησης). Αναζήτηση: σε O(n) χρόνο. Ερώτηση: µπορούµε να έχουµε τόσο καλή αναζήτηση σε µια ταξινοµηµένη λίστα (απλά / διπλά συνδεδεµένη / κυκλική) όσο σε έναν ταξινοµηµένο πίνακα; Πώς / Γιατί; Ο. Τελέλης Πανεπιστήµιο Πειραιώς οµές εδοµένων 50 / 50