ΠΛΗ111 ∆οµηµένος...

45
ΠΛΗ111 ∆ομημένος Προγραμματισμός Ανοιξη 2005 Μάθημα 3 ο Συνδεδεμένες Λίστες Τμήμα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης

Transcript of ΠΛΗ111 ∆οµηµένος...

Page 1: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

ΠΛΗ111∆οµηµένος Προγραµµατισµός

‘Ανοιξη 2005

Μάθηµα 3ο

Συνδεδεµένες Λίστες

Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών ΥπολογιστώνΠολυτεχνείο Κρήτης

Page 2: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 2

Ανασκόπηση

• Ο ΑΤ∆ λίστα• Ακολουθιακή λίστα• Συνδεδεµένη λίστα• Υλοποίηση συνδεδεµένης λίστας µε πίνακα• Υλοποίηση συνδεδεµένης λίστας µε δείκτες• Παραδείγµατα• Λίστα µε header• Λίστα µε sentinel• Κυκλική λίστα• ∆ιπλά συνδεδεµένη λίστα

Page 3: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 3

ΑΤ∆ Λίστα

• Γραµµική συλλογή στοιχείων ίδιου τύπου– Έχει πρώτο και τελευταίο στοιχείο– Κάθε στοιχείο εκτός του πρώτου έχει ένα προηγούµενο– Κάθε στοιχείο εκτός του τελευταίου έχει ένα επόµενο

• Εφαρµογές: γραµµική διαχείριση πληροφοριών

στοιχείο1

πρώτο τελευταίο

στοιχείον-1 στοιχείον

Page 4: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 4

ΑΤ∆ Λίστα (2)

• Υποστηρίζει τις πράξεις:– ∆ηµιουργία κενής λίστας– Εισαγωγή, διαγραφή και αναζήτηση συγκεκριµενου στοιχείου– Μήκος λίστας– Έλεγχος αν η λίστα είναι κενή– ...

στοιχείο1

πρώτο τελευταίο

στοιχείον-1 στοιχείον

στοιχείον+1 Π.χ. εισαγωγή στοιχείου

Page 5: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 5

Ακολουθιακή Λίστα

• Υλοποίηση λίστας – Αποθηκεύει διαδοχικά στοιχεία σε γειτονικές θέσεις µνήµης– Βασίζεται σε πίνακα– ∆ιατηρεί το πλήθος των στοιχείων σε βοηθητική µεταβλητή

typedef struct { seqList_t list; int number; void init(seqList *list) {

element_t records[MaxElements]; list->number = 0; } seqList_t; }

a1 an

0 number-1 MaxElements-1

records

Page 6: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 6

Εισαγωγή Στοιχείου O(n)

void insertAfter(seqList_t *listPtr, element_t elem, int pos) { /* number < MaxElements &&

pos >= 0 && pos <= number –1 */ …

/* µετακίνηση στοιχείων δεξιά κατά 1 θέση*/ for (int i = listPtr->number – 1; i >= pos + 1; i--) listPtr->records[i+1] = listPtr->records[i]; listPtr->records[pos+1] = elem; listPtr->number++; }

number-1

MaxElements-1

pos

Page 7: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 7

∆ιαγραφή Στοιχείου Ο(n)

void delete(seqList_t *listPtr, int pos) { /* pos >= 0 && pos <= number –1 */

… /* µετακίνηση στοιχείων αριστερά κατά 1 θέση*/ for (int i = pos; i <= listPtr->number – 1; i++) listPtr->records[i] = listPtr->records[i+1]; listPtr->number--; }

number-1

MaxElements-1

pos

Page 8: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 8

Μειονεκτήµατα Πίνακα

• Σταθερό µέγεθος που καθορίζεται κατά τη δήλωση ή τη δηµιουργία του πίνακα

• Συνήθως ο προγραµµατιστής δηλώνει «αρκετά µεγάλο» πίνακα που οδηγεί σε– Αχρησιµοποίητη µνήµη– Τερµατισµό προγράµµατος αν η πρόβλεψη έγινε λάθος

• Εισαγωγή στοιχείων στην αρχή του πίνακα ακριβή• Προσπέλαση στοιχείων απαιτεί υπολογισµό διεύθυνσης• Αλλά το κόστος διαχείρισης µνήµης χαµηλό

Page 9: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 9

Απλή Συνδεδεµένη Λίστα

• Κάθε στοιχείο της λίστας καλείται κόµβος και περιέχει– ∆εδοµένα– ∆είκτη στον επόµενο κόµβο της λίστας

• Μια µεταβλητή δείχνει στον πρώτο κόµβο της λίστας

δεδοµένα

λίστα

κενή λίστα

Page 10: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 10

Εισαγωγή Στοιχείου O(1)

• Τέσσερις δείκτες– head δείχνει στον πρώτο κόµβο– newNode δείχνει στο νέο κόµβο– current διατρέχει τους κόµβους– beforeCurrent δείχνει τον κόµβο αµέσως πριν τον current

head

current beforeCurrent

newNode

Page 11: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 11

∆ιαγραφή Στοιχείου O(1)

• Τρεις δείκτες– headδείχνει στον πρώτο κόµβο– current διατρέχει τους κόµβους– beforeCurrent δείχνει τον κόµβο αµέσως πριν τον current

head

current beforeCurrent

Page 12: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 12

Σύγκριση Κόστους Πράξεων

• Συνδεδεµένη λίστα– Εισαγωγή και διαγραφή κόµβου κοστίζει σταθερό χρόνο Ο(1)– Αναζήτηση στοιχείου κοστίζει γραµµικό χρόνο Ο(n)

• Ακολουθιακή λίστα– Εισαγωγή και διαγραφή κόµβου κοστίζει γραµµικό χρόνο Ο(n)– Αναζήτηση i-στού στοιχείου κοστίζει σταθερό χρόνο Ο(1)– Αναζήτηση µε βάση το περιέχοµενο κοστίζει γραµµικό χρόνο

O(n)

Page 13: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 13

Στατική Συνδεδεµένη Λίστα

• Πίνακας σταθερού αριθµού δοµών typedef struct {

data_t data; /* δεδοµένα */int next; /* δείκτης στοιχείου πίνακα */

} node_t;node_t nodes[MaxNodes];

• Μειονεκτήµατα– Ανάγκη πρόβλεψης του αριθµού κόµβων πριν την εκτέλεση– ∆έσµευση µνήµης για όλους τους κόµβους κατά την εκτέλεση– ...

Page 14: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 14

Αρχικοποίηση Πίνακα

/* λίστα διαθέσιµων κόµβων */ for (int i = 0; i < MaxNodes –1 ; i++ ) nodes[i].next = i + 1; nodes[MaxNodes-1].next = -1; /* πρώτος διαθέσιµος κόµβος */ freeNode= 0; /* κενή λίστα */ int head = -1;

data next

1

2

3

4

5

6

-1

1

2

3

4

5

6

0

freeNode

Page 15: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 15

∆έσµευση & Αποδέσµευση Κόµβου

int getNode() { int c; If (freeNode == -1) return (-1) /* υπερχείλιση */ c = freeNode; freeNode = nodes[freeNode].next; return (c); } void relNode(int c) { nodes[c].next = freeNode; freeNode = c; }

data next

1

2

3

4

5

6

-1

1

2

3

4

5

6

0

freeNode

Page 16: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 16

Εισαγωγή Κόµβου void insAfter(int *headPtr, int b, data_t d) { int n; if ((n = getNode()) < 0) printf(“υπερχείλιση”); else { nodes[n].data = d; if (b < 0) { /* αρχή λίστας */ nodes[n].next = *headPtr; *headPtr = n; } else { /* ενδιάµεσα */ nodes[n].next = nodes[b].next; nodes[b].next = n; } } }

1

-1

3

4

5

6

-1

1

2

3

4

5

6

0

freeNode headPtr

current

newNode

d

Page 17: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 17

∆ιαγραφή Κόµβου void delAfter(int *headPtr, int b, data_t *d) { int c; if (b < 0) { /*διαγραφή πρώτου κόµβου*/

if (*headPtr >= 0) { c = *headPtr; *headPtr = nodes[c].next; *d = nodes[c].data; relNode(c); } else printf(“κενή λίστα”);

} else if (nodes[b].next < 0) printf(“άκυρη διαγραφή”);

else { /* διαγραφή ενδιάµεσου κόµβου */ c = nodes[b].next; *d = nodes[c].data; nodes[b].next = nodes[c].next; relNode(c); } }

2

-1

1

4

5

6

-1

1

2

3

4

5

6

0 freeNode

headPtr

current

beforeCurrent

Page 18: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 18

Αναζήτηση Κόµβου

int find(int head, data_t d) { while (head > -1 && nodes[head].data != d) head = nodes[head].next; return (head); } int findi(int head, int i) { if (i < 1) return (-1); while (head > -1 && --i) head = nodes[head].next; return (head); }

2

-1

1

4

5

6

-1

1

2

3

4

5

6

0

head

freeNodes

Page 19: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 19

∆υναµική Συνδεδεµένη Λίστα

• ∆υναµική καταχώρηση µνήµης για δηµιουργία κόµβων• Ορίζεται µε αυτοαναφορική (ή αναδροµική) δοµή

/* δήλωση τύπου */typedef struct node {

data_t data;struct node *next;

} node_t, *nodePtr_t;

/* ορισµός λίστας */nodePtr_t head = NULL;

Page 20: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 20

∆έσµευση και Αποδέσµευση Κόµβου

/* δέσµευση µνήµης κόµβου */ nodePtr_t getNode(data_t d) {

nodePtr_t newNode; newNode = (nodePtr_t)

malloc(sizeof(node_t)); newNode->data = d; return (newNode);

}

/* αποδέσµευση µνήµης κόµβου */ void relNode(nodePtr_t oldNode) {

free(oldNode); }

newNode data

next

Heap

Page 21: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 21

Εισαγωγή Κόµβου

void insAfter(nodePtr_t *headPtr, nodePtr_t b, data_t d) {

nodePtr_t n;

if ((n=getNode(d)) == NULL) printf(“κενός κόµβος”);

else if (b == NULL) { /* πριν τον πρώτο κόµβο */

n->next = *headPtr; *headPtr = n;

} else { /* ενδιάµεσα */ n->next = b->next; b->next = n;

} }

headPtr

newNode

beforeCurrent

Page 22: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 22

∆ιαγραφή Κόµβουvoid delAfter(nodePtr_t *headPtr, nodePtr_t b, data_t *d) { nodePtr_t c; if (b == NULL) { /* διαγραφή πρώτου κόµβου */ if (*headPtr == NULL) printf(“κενή λίστα”); else { c = *headPtr; *headPtr = c->next; *d = c->data; relNode(c); } } else if (b->next == NULL) printf(“άκυρη διαγραφή”); else { c = b->next; *d = c->data; b->next = c->next; relNode(c); } }

headPtr

beforeCurrent

Page 23: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 23

Μήκος Λίστας

head

current

• ∆ίνεται δείκτης στον πρώτο κόµβο της συνδεδεµένης λίστας (head)

• Να υπολογιστεί το µήκος της λίστας (length)

Page 24: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 24

Λύση

int length(nodePtr_t head) {

nodePtr_t current = head; int count = 0; while (current != NULL) {

count++; current = current->next;

} return count;

}

head

current

Page 25: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 25

Αντιγραφή Λίστας

• ∆ίνεται δείκτης σε συνδεδεµένη λίστα

• Να δηµιουργηθεί ένα νέο πλήρες αντίγραφο της λίστας

head head

Page 26: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 26

ΛύσηnodePtr_t CopyList(nodePtr_t head) {

/* αρχική λίστα */ nodePtr_t current = head; /* νέα λίστα */ nodePtr_t newList = NULL; nodePtr_t tail = NULL;

while (current != NULL) {

if (newList == NULL) { newList = getNode(current->data); newList->next = NULL; tail = newList;

} else { tail->next = getNode(current->data); tail = tail->next; tail->next = NULL;

} current = current->next;

} return(newList);

}

headnewList

tail

current

Page 27: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 27

∆ιαγραφή Λίστας

• ∆ίνεται δείκτης στον πρώτο κόµβο µίας συνδεδεµένης λίστας

• Να διαγραφούν όλοι οι κόµβοι από την λίστα και να αποδεσµευτεί η µνήµη που καταλαµβάνουν

headcurrent

head

Page 28: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 28

Λύση

void deleteList(nodePtr_t *headRef) {

nodePtr_t current = *headRef; nodePtr_t next; while (current != NULL) {

next = current->next; relNode(current); current = next;

} *headRef = NULL;

}

headcurrent

next

Page 29: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 29

Συνδεδεµένη Λίστα µε Header

• Η υλοποίηση πράξεων της απλής συνδεδεµένης λίστας – Συχνά απαιτεί τροποποίηση του δείκτη στον πρώτο κόµβο– Εισάγει επιπλέον ειδικές περιπτώσεις στις συναρτήσεις– Αυξάνει το επίπεδο έµµεσης αναφοράς σε δύο επίπεδα

head

Page 30: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 30

Συνδεδεµένη Λίστα µε Header (2)

• Μια λύση είναι η χρήση κενού κόµβου (header) στην αρχή της λίστας

• Απλοποιεί επαναληπτικές διεργασίες– Αποθηκεύει επιπλέον χρήσιµες πληροφορίες όπως το µήκος της λίστας, δείκτη στον τελευταίο κόµβο, κτλ

– Αλλά ξοδεύει τη µνήµη ενός κόµβου ακόµη και για κενή λίστα

header

head

Page 31: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 31

Εισαγωγή κόµβου σε λίστα µε Header

void insertAfter(nodePtr_t b, data_t d) {

nodePtr n;

if ((n=getNode(d)) == NULL) printf(“κενός κόµβος”);

else { /* ενδιάµεσα */ n->next = b->next; b->next = n;

} }

newNode

beforeCurrent

header

Page 32: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 32

∆ιαγραφή κόµβου από λίστα µε Header

void delAfter(nodePtr_t b, data_t *d) { nodePtr_t c;

if (b->next == NULL) printf(“άκυρη διαγραφή”); else { c = b->next; *d = c->data; b->next = c->next; relNode(c); } }

header

beforeCurrent

Page 33: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 33

Συνδεδεµένη Λίστα µε Sentinel

• Η αναζήτηση σε απλή συνδεδεµένη λίστα συνήθως τερµατίζεται από δείκτη NULL

• Εναλλακτικά µπορούµε να έχουµε κάποια ειδική τιµή δεδοµένων για τερµατισµό στον τελευταίο κόµβο

• Απλοποιούµε τον βρόχο αναζήτησης µε λιγότερες συγκρίσεις

+oo

head sentinel

Page 34: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 34

Παράδειγµα

• Θεωρήστε ακολουθία αριθµών σε αύξουσα σειρά αποθηκευµένη σε συνδεδεµένη λίστα

• Εξετάζουµε εναλλακτικούς τρόπους αναζήτησης

/* απλή συνδεδεµένη λίστα /* λίστα µε sentinel +oo µε αύξουσα διάταξη */ τερµατίζει µε +oo > n */ while (p && p->data < n) while (p->data < n) p=p->next; p=p->next;

+oo

head sentinel

Page 35: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 35

Κυκλική Λίστα

• Απλή συνδεδεµένη λίστα της οποίας ο τελευταίος κόµβος δείχνει στον πρώτο

• Με δείκτη σε οποιονδήποτε κόµβο της λίστας µπορούµε να φτάσουµε σε όλους τους υπόλοιπους

• Φυσική αναπαράσταση για συγκεκριµένες εφαρµογές– Η περιφέρεια πολυγώνου µπορεί να παρασταθεί µε κυκλική λίστα των κόµβων του πολυγώνου

head

Page 36: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 36

Εισαγωγή Κόµβου σε Κυκλική Λίστα

• ∆εδοµένης της κυκλικότητας δε χρειάζεται να τροποποιήσουµε το δείκτη στον πρώτο κόµβο παρά µόνο όταν εισάγουµε κόµβο σε κενή λίστα

void insertAfter(nodePtr_t *headPtr, nodePtr_t nodePtr b,

data_t d) { nodePtr n;

if ((n=getNode(d)) == NULL) printf(“κενός κόµβος”);

else if (*headPtr == NULL) { n->next = n; /* κενή λίστα */ *headPtr = n; } else { /* ενδιάµεσα */

n->next = b->next; b->next = n;

} }

newNode

beforeCurrent

head

Page 37: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 37

∆ιαδροµή Κυκλικής Λίστας

• Αν η λίστα ενδέχεται να είναι κενή χρειάζεται ειδική αντιµετώπιση µε έλεγχο if (head == NULL)

• Αλλιώς µπορούµε να χρησιµοποιήσουµε το βρόχοop = p = headdo {

/* επεξεργασία p */…p = p->next

} while (p != op) /*συνθήκη τερµατισµού*/

Page 38: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 38

∆ιπλά Συνδεδεµένη Λίστα

• Κάθε κόµβος έχει δείκτη τόσο στον προηγούµενο όσο και στον επόµενο κόµβο– Από ένα κόµβο έχουµε άµεση πρόσβαση στους δύο γειτονικούς σε σταθερό χρόνο Ο(1)

– Εισάγουµε κόµβο πριν ή µετά από κόµβο µε ένα δείκτη– ∆ιαγράψουµε κόµβο µε ένα δείκτη– ∆ιατρέχουµε τη λίστα σε δύο κατευθύνσεις

• Μειονεκτήµατα– Χρησιµοποιεί διπλάσιο αριθµό δεικτών από την απλή– Αυξάνει την πιθανότητα σφάλµατος δεικτών

head

Page 39: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 39

∆ήλωση ∆ιπλά Συνδεδεµένης Λίστας

• Χρειαζόµαστε δύο δείκτες σε κάθε κόµβο που να δείχνουν στον προηγούµενο και τον επόµενο κόµβο

struct node {data_t data;struct node *prev, *next;

} node_t, *nodePtr_t;• Εναλλακτικά µπορούµε να χρησιµοποιήσουµε array δύο στοιχείων για εύκολη υλοποίηση αµφίδροµης διαδροµής

struct node {data_t data;struct node *link[2];

} node_t, *nodePtr_t;

Page 40: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 40

Αρχικοποίηση ∆ιπλά Συνδεδεµένης Λίστας

• Θεωρούµε διπλά συνδεδεµένη λίστα µε header

void create(nodePtr_t *headPtr) {nodePtr_t header = (nodePtr_t)

malloc(sizeof(node_t));header->prev = header->next = NULL;*headPtr = header;

}

head header

Page 41: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 41

Εισαγωγή Κόµβου

void insertAfter(nodePtr_t b, data_t d) {

nodePtr n; if ((n=getNode(d)) == NULL)

printf(“κενός κόµβος”); else { /* ενδιάµεσα */

n->prev = b; n->next = b->next; if (b->next != NULL)

b->next->prev = n; b->next = n;

} }

newNode

beforeCurrent

header

head

Page 42: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 42

Υλοποίηση Συνόλου µε Λίστα

• Χρησιµοποιούµε απλή συνδεδεµένη λίστα ταξινοµηµένων στοιχείων:

– empty(s) : ελέγχει αν το σύνολο s είναι κενό– dumpset(s) : τυπώνει τα µέλη του συνόλου– member(s, n) : ελέγχει αν το n είναι στοιχείο του s– insert(s, n) : εισάγει το στοιχείο n στο s– unite(s1, s2) : επιστρέφει την ένωση των s1 και s2

typedef struct element element;struct element {

element *next;int value;

};typedef element *set;

#define empty(s) (s == NULL)

Page 43: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 43

Υλοποίηση Πράξεων Συνόλου

/* τυπώνει τα µέλη του συνόλου */void dumpset(set s) {

while (s) {printf(“%d ”, s->value);s = s->next;

}}/* ελέγχει αν το n είναι µέλος του s */int member(set s, int n) {

while (s && s->value < n)s = s->next;

return s && s->value == n;}

Page 44: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 44

Eισαγωγή Στοιχείου σε Σύνολο/* εισάγει το στοιχείο n στο σύνολο s */set insert(set s, int n) {

element dummy, *p, *new;

p = &dummy;p->next = s;while (p->next && p->next->value < n)

p = p->next;if (!(p->next && p->next->value == n)) {/* το n δεν είναι µέλος του συνόλου */

new = (element *) malloc(sizeof(element));

new->value = n;new->next = p->next;p->next = new;

}return dummy.next;

}

new

p

dummy

Page 45: ΠΛΗ111 ∆οµηµένος Προγραµµατισµόςstergios/teaching/plh111/dbindex_files/...– ∆ιαγράψουµε κόµβο µε ένα δείκτη – ∆ιατρέχουµε

’Ανοιξη 2005 © Στέργιος Β. Αναστασιάδης 45

Ένωση Συνόλων/* εισάγει το στοιχείο n στο σύνολο s */set unite(set s1, set s2) {

element dummy, *p;

p = &dummy;while (s1 && s2) {

if (s1->value < s2->value)p->next=getNode(s1->value);s1=s1->next;

} else if (s2->value < s1->value) {p-> next = getNode(s2->value);s2 = s2->next;

} else { /* ίδια µέλη */p->next = getNote(s1->value);s1 = s1->next;s2 = s2->next;

}p = p->next;

}

/* αντιγραφή υπολοίπου συνόλου */if (!s1) s1 = s2;while (s1) {

p->next = getNode(s1->value);p = p->next;s1 = s1->next;

}

return dummy.next;}

/* δηµιουργία νέου κόµβου */element *getNode(int n) {

element *p = (element *)malloc(sizeof(element));

p->value = n;return p;

}