Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

ΗΜΜΥ 111 ΔΟΜΗΜΕΝΟΣΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΚΩΣΤΑΣ ΚΟΝΤΟΓΙΑΝΝΗΣ Αναπληρωτής Καθηγητής Τμήμα ΗΜΜΥ Πολυτεχνείο Κρήτης.

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "ΗΜΜΥ 111 ΔΟΜΗΜΕΝΟΣΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΚΩΣΤΑΣ ΚΟΝΤΟΓΙΑΝΝΗΣ Αναπληρωτής Καθηγητής Τμήμα ΗΜΜΥ Πολυτεχνείο Κρήτης."— Μεταγράφημα παρουσίασης:

1 ΗΜΜΥ 111 ΔΟΜΗΜΕΝΟΣΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΚΩΣΤΑΣ ΚΟΝΤΟΓΙΑΝΝΗΣ Αναπληρωτής Καθηγητής Τμήμα ΗΜΜΥ Πολυτεχνείο Κρήτης

2 ΚΑΛΩΣ ΗΡΘΑΤΕ ! Καλώς ήρθατε στο Μάθημα «Δομημένος Προγραμματισμός». Αυτό το Μάθημα ουσιαστικά εισάγει έννοιες σχετικές με την σχεδίαση και την κατασκευή λογισμικού. Σας εύχομαι ολόψυχα καλή επιτυχία.

3 ΛΙΓΑ ΛΟΓΙΑ ΓΙΑ ΕΜΕΝΑ Πτυχίο στά Εφαρμοσμένα Μαθηματικά απο το Παν/μιο Πατρών. Μεταπτυχιακό από το Πανεπιστήμιο Leuven στό Βέλγιο Διδακτορικό από το Πανεπιστήμιο McGill στόν Καναδά. Μεταδιδακτορικό από το Πανεπιστήμιο του Toronto στόν Καναδά. Επίκουρος και Αναπληρωτής Καθηγητής στο Πανεπιστήμιο Waterloo στον Καναδά. Σύμβουλος στο Κέντρο Ανωτάτων Σπουδών της ΙΒΜ Επιστημονικός υπεύθυνος σε Ερευνητικά Προγράμματα με την IBM, Bell, Nortel. Βραβείο του Ιδρύματος Ανάπτυξης και Τεχνολογίας της Ομοσπονδιακής Κυβέρνησης του Καναδά.

4 ΑΝΤΙΚΕΙΜΕΝΟ ΤΟΥ ΜΑΘΗΜΑΤΟΣ (1) Καλύτερη γνώση και χρήση της γλώσσας C Εισαγωγή στόν Δομημένο Προγραμματισμό –Έννοιες που χρησιμοποιούνται για τη σχεδίαση αλγόριθμων και προγραμμάτων –Βασικές δομές (κατασκευές) για την υλοποίηση προγραμμάτων –Απόκτηση εμπειρίας στο προγραμματισμό απλών εφαρμογών

5 ΑΝΤΙΚΕΙΜΕΝΟ ΤΟΥ ΜΑΘΗΜΑΤΟΣ (2) Εβδομάδα 1Ανασκόπηση της C - Δομή Προγράμματος – Εντολές Εβδομάδα 2Διατάξεις (με χρήση αρχείων) και πολυδιάστατοι πίνακες Εβδομάδα 3Δομές (με διαχείρηση μνήμης) Εβδομάδα 4Αλγόριθμοι Εβδομάδα 5Διασυνδεμένες Λίστες Εβδομάδα 6Ταξινόμηση Εβδομάδα 7Αφηρημένοι Τύποι Δεδομένων - Εισαγωγή σε Οντοκεντρικό Προγραμματισμό Εβδομάδα 8Στοίβες (με υλοποίηση διάταξης και διασυνδεμένης λίστας) Εβδομάδα 9Ουρές (με υλοποίηση διάταξης και δισυνδεμένης λίστας) Εβδομάδα 10Δυαδικά Δένδρα Εβδομάδα 11Πολυπλοκότητα Εβδομάδα 12Ανασκόπηση

6 ΣΤΟΙΧΕΙΑ ΓΙΑ ΤΟ ΜΑΘΗΜΑ (1) Το πρόγραμμα: –Διαλέξεις (Στό Ξύλινο) Πέμπτη 10:00 – 12:00 Παρασκευή 15:00 – 16:00 Πέμπτη 12:00 – 13:00 (Ώρα γραφείου) –Φροντιστήριο (Στό Ξύλινο) Παρασκευή 16:00 – 17:00 –Εργαστήρια (Στό Μηχανογραφικό Κέντρο) Τρίτη 17:00 – 19:00 Τετάρτη 17:00 – 19:00

7 ΣΤΟΙΧΕΙΑ ΓΙΑ ΤΟ ΜΑΘΗΜΑ (2) Βοηθοί Όνομ/πώνυμο Τηλέφωνο κος. Γ. Μαραγκουδάκης κος. Γ. Ανέστης κος. Χ. Σμαραγδάκης κα. Γ. Αδαμοπούλου

8 ΣΤΟΙΧΕΙΑ ΓΙΑ ΤΟ ΜΑΘΗΜΑ (3) Βιβλία –«Εγχειρίδιο της C» Το βιβλίο που χρησιμοποιήσαμε στο ΗΜΜΥ 101. –«Δομές Δεδομένων με C» Το βιβλίο έχει παραγγελθεί και ανατυπώνεται. Η παράδοση του βιβλίου θα γίνεται μόνον από τη Γραμματεία του ΗΜΜΥ και θα πρέπει 1. Να έχετε εισαχθεί το Να έχετε αριθμό μητρώου ΗΜΜΥ, καί 3. Να υπογράψετε τη σχετική φόρμα-λίστα πού υπάρχει στη Γραμματεία του ΗΜΜΥ Σημειώσεις και άλλο υλικό γιά το μάθημα –Σημειώσεις θα παρουσιάζονται σταδιακά στην Ιστοσελίδα του μαθήματος –Ασκήσεις, Φροντηστηριακό υλικό, καί Ανακοινώσεις θα παρουσιάζονται επίσης στην παραπάνω ιστοσελίδα Λογαριασμοί για το υπολογιστικό σύστημα (για όσους δεν έχουν) –Από το Υπολογιστικό Κέντρο με την ταυτότητά σας και τον αριθμό Μητρώου του ΗΜΜΥ –Υπεύθυνοι για την έκδοση των λογαριασμών στό Υπολογιστικό Κέντρο είναι οι Κα. Κυρούση (εσωτ. 7571) Κος. Μαραγκουδάκης (εσωτ. 7352) –Δήλωση γιά την τήρηση της υπεύθυνης λειτουργίας και χρήσης των υπολογιστών και χώρων του Κέντρου

9 ΣΤΟΙΧΕΙΑ ΓΙΑ ΤΟ ΜΑΘΗΜΑ (4) Η βαθμολογία θα υπολογίζεται ως εξής: –Τελικό διαγώνισμα (50%) –Πρόοδος (20%) –Τρεις ασκήσεις (30%) Άσκηση 1 Άσκηση 2 Άσκηση 3 Εναλλακτικό σχήμα βαθμολογίας: –Τελικό διαγώνισμα (70%) –Ασκήσεις (30%) Η Πρόοδος είναι προαιρετική καί γιά την τελική βαθμολογία θα υπολογίζεται ο μεγαλύτερος βαθμός ανάμεσα στα παραπάνω σχήματα βαθμολογίας. Η Πρόοδος είναι προαιρετική καί γιά την τελική βαθμολογία θα υπολογίζεται ο μεγαλύτερος βαθμός ανάμεσα στα παραπάνω σχήματα βαθμολογίας.

10 ΕΠΙΚΟΙΝΩΝΙΑ Κώστας Κοντογιάννης Ας Αρχίσουμε λοιπόν......

11 Διαφάνειες παρουσιάσεων Η γλώσσα προγραμματισμού C Προγραμματιστικές τεχνικές Δομές δεδομένων

12 Η ιστορία της C AT&T Bell Labs, Dennis Ritchie 1978“The C Programming Language” K&R: Kernighan & Ritchie 1983Σύσταση ANSI Standardization Committee X3J Αποδοχή ANSI/ISO Standard  ANSI C Αναθεώρηση του standard υπό εξέλιξη — C9X  C99

13 Χαρακτηριστικά της C(i) Γλώσσα προστακτικού προγραμματισμού Γλώσσα μετρίου επιπέδου Οικονομία στην έκφραση (λιτή και περιεκτική) Σχετικά χαλαρό σύστημα τύπων Φιλοσοφία: ο προγραμματιστής έχει πλήρη έλεγχο και ευθύνεται για τα σφάλματά του

14 Χαρακτηριστικά της C(ii) Ιδιαίτερα δημοφιλής στην πράξη Έχει χρησιμοποιηθεί για τον προγραμματισμό ευρέως φάσματος συστημάτων και εφαρμογών Έχει χρησιμοποιηθεί ως βάση για πληθώρα άλλων γλωσσών: C++, Java

15 Hello world! #include #include void main () { printf("Hello world!\n"); printf("Hello world!\n");}Παρατηρήσεις –Η επικοινωνία με τον «έξω» κόσμο γίνεται μέσω της βιβλιοθήκης συναρτήσεων –Το σημείο έναρξης του προγράμματος είναι η «κύρια» συνάρτηση main.

16 Εκτέλεση προγραμμάτων Πηγαίος κώδικας (source) Μεταγλωττιστής C (compiler) Συνδέτης (linker) Βιβλιοθήκη (library) Αρχεία επικεφαλίδας (header files) Object code Εκτελέσιμο πρόγραμμα (executable) hello.c hello.o hello printf stdio.h

17 Τύποι δεδομένων (απλοί) Ακέραιοι αριθμοί intchar Καθορισμός προσήμανσης signedunsigned Καθορισμός μεγέθους shortlong Αριθμοί κινητής υποδιαστολής floatdouble

18 Πίνακας απλών τύπων δεδομένων char, signed char, unsigned char signed short int, unsigned short int signed int, unsigned int signed long int, unsigned long int floatdouble long double Με κόκκινο χρώμα όσα μπορούν να παραλειφθούν.

19 Ορισμός μεταβλητών int x; int x, y, z; double r; unsigned long abc; Αρχικοποίηση int x = 1; int x, y = 0, z = 2; double r = 1.87; unsigned long abc = ;

20 Σταθερές(i) Ακέραιες δεκαδικές 037 οκταδικές 0x1f δεκαεξαδικές 42U42L42UL unsigned & long Κινητής υποδιαστολής δεκαδικές 2.99e8 με δύναμη του F42.0L float & long double

21 Σταθερές(ii) Χαρακτήρα 'a''0''$' Ειδικοί χαρακτήρες \n αλλαγή γραμμής \' απόστροφος \\ χαρακτήρας \ (backslash) \t αλλαγή στήλης (tab) \" εισαγωγικό \0 χαρακτήρας με ASCII = 0 (null) \037 » με ASCII = 37 (οκταδικό) \x1f » με ASCII = 1f (δεκαεξαδικό)

22 Σταθερές(iii) Συμβολοσειρές "abc""Hello world!\n""a\"51\"" Δηλώσεις σταθερών const int size = 10, num = 5; const double pi = ; const char newline = '\n';

23 Σχόλια Μεταξύ /* και */ #include #include /* This simple program greets the world by saying "hello" */ world by saying "hello" */ void main () { printf( /* eh? */ "Hello world!\n"); printf( /* eh? */ "Hello world!\n");} Το παρακάτω είναι λάθος /* Nested /* comments */ are wrong! */

24 Εκτύπωση με την printf Απλοί τύποι δεδομένων –int %d –char %c –double %lf –string %s Παράδειγμα printf("%d %lf %c %s\n", 42, 1.2, 'a', "hello"); Αποτέλεσμα a hello

25 Εισαγωγή με την scanf Ίδιοι κωδικοί για τους απλούς τύπους Παράδειγμα int n; double d; char c; scanf("%d", &n); scanf("%lf", &d); scanf("%c", &c);

26 Ένα πιο σύνθετο παράδειγμα #include #include void main () { int celcius; double farenheit; printf("Give the temperature (C): "); scanf("%d", &celcius); farenheit = 9.0 * celcius / ; printf("%d degrees Celcius " "is %lf degrees Farenheit\n", "is %lf degrees Farenheit\n", celcius, farenheit); celcius, farenheit);}

27 Τελεστές και εκφράσεις(i) Αριθμητικοί τελεστές +-*/%+-*/%+-*/%+-*/% Σχεσιακοί τελεστές ==!=<> = Λογικοί τελεστές && λογική σύζευξη(και) || λογική διάζευξη(ή) ! λογική άρνηση(όχι) π.χ. (x % 3 != 0) && !finished

28 Τελεστές και εκφράσεις(ii) Τελεστές bit προς bit (bitwise) & σύζευξη bit(AND) | διάζευξη bit(OR) ^ αποκλειστική διάζευξη bit(XOR) ~ άρνηση(NOT) << ολίσθηση bit αριστερά >> ολίσθηση bit δεξιά Παράδειγμα (0x0101 & 0xfff0) << 2  0x0400

29 Τελεστές και εκφράσεις(iii) Τελεστής συνθήκης (a >= b) ? a : b Τελεστής παράθεσης a-1, b+5 Τελεστές ανάθεσης a = b+1 a += x ισοδύναμο με a = a + x Τελεστές αύξησης και μείωσης a++a-- τιμή πριν τη μεταβολή ++a--a τιμή μετά τη μεταβολή

30 Eντολές και έλεγχος ροής(i) Κενή εντολή ; Εντολή έκφρασης a = b+5; a++; Εντολή if if (a >= b) max = a; else max = b;

31 Eντολές και έλεγχος ροής(ii) Σύνθετη εντολή if (a >= b) { min = b; max = a; } else { max = b; min = a; } Ορίζει νέα εμβέλεια if (x < y) { int temp = x; x = y; y = temp; }

32 Eντολές και έλεγχος ροής(iii) Εντολή while int i = 1, s = 0; while (i <= 10) { s += i; i++;} συνθήκη εντολή αληθής ψευδής while ( συνθήκη ) εντολή

33 Eντολές και έλεγχος ροής(iv) Εντολή do-while int i = 1, s = 0; do s += i++; while (i <= 10); συνθήκη εντολή ψευδής αληθής do εντολή while ( συνθήκη );

34 Eντολές και έλεγχος ροής(v) Εντολή for int i, s; for (i=1, s=0; i <= 10; i++) s += i; for ( αρχικοποίηση ; συνθήκη ; βήμα ) εντολή συνθήκη εντολή αληθής ψευδής βήμα αρχικοποίηση

35 Εντολή break int s; for (i=0, s=0; i < 10; i++) { int x; int x; scanf("%d", &x); scanf("%d", &x); s += x; s += x;} printf("Sum is: %d\n", s); Eντολές και έλεγχος ροής(vi) if (x < 0) if (x < 0) break; break;

36 Eντολές και έλεγχος ροής(vii) Εντολή continue int s; for (i=0, s=0; i < 10; i++) { int x; int x; scanf("%d", &x); scanf("%d", &x); s += x; s += x;} printf("Sum is: %d\n", s); if (x < 0) if (x < 0) continue; continue;

37 Eντολές και έλεγχος ροής(viii) Εντολή switch switch (ch) { case 'a': case 'a': printf("alpha\n"); printf("alpha\n"); break; break; case 'b': case 'b': case 'c': case 'c': printf("beta or c\n"); printf("beta or c\n"); break; break; default: default: printf("other\n"); printf("other\n");}

38 Eντολές και έλεγχος ροής(ix) Ετικέτες και εντολή goto int i = 1, s = 0; loop: s += i++; s += i++; if (i < 10) if (i < 10) goto loop; goto loop; printf("The sum is %d\n", s); Όχι goto: δομημένος προγραμματισμός!

39 Δομή του προγράμματος Το πρόγραμμα αποτελείται από: –συναρτήσεις –καθολικές μεταβλητές Διαφορές από την Pascal: –κύριο πρόγραμμα, διαδικασίες και συναρτήσεις δε διαφοροποιούνται –το κύριο πρόγραμμα ονομάζεται main –οι διαδικασίες έχουν αποτέλεσμα void –όλες οι συναρτήσεις στο ίδιο επίπεδο –δεν επιτρέπονται φωλιασμένες συναρτήσεις –μόνο πέρασμα κατά τιμή (call by value)

40 Παράδειγμα int f (int x, int y) { return x * y; return x * y;} int a; void p (int x) { a = f(x, x+1); a = f(x, x+1);} void main () { p(6); p(6);}

41 Πίνακες (arrays)(i) Ακολουθία μεταβλητών –με το ίδιο όνομα, –με τον ίδιο τύπο δεδομένων, –σε συνεχόμενες θέσεις μνήμης. Παράδειγμα int a[50]; double d1[5], d2[10]; Η αρίθμηση αρχίζει από το 0 ! for (i = 0; i < 50; i++) a[i] = i; a[i] = i;

42 Πίνακες (arrays)(ii) Αρχικοποίηση πινάκων int a[3] = {6, 7, 42}; char c[] = {'a', 'b', 'c', 'd', 'e'}; Συμβολοσειρές –Είναι πίνακες χαρακτήρων char s[6] = "abcde"; –Τερματίζονται με τον κενό χαρακτήρα '\0' char s[6] = {'a', 'b', 'c', 'd', 'e', '\0'}; 'd', 'e', '\0'};

43 Πίνακες (arrays)(iii) Παράδειγμα int a[3] = {5, 6, 7}; int b[3] = {2, 3, 1}; int i; for (i = 0; i < 3; i++) printf("%d times %d is %d\n", printf("%d times %d is %d\n", a[i], b[i], a[i]*b[i]); a[i], b[i], a[i]*b[i]); 5 times 2 is 10 6 times 3 is 18 7 times 1 is 7 5 times 2 is 10 6 times 3 is 18 7 times 1 is 7

44 Πολυδιάστατοι πίνακες(i) Παράδειγμα int a[3][5]; char c[5][10][4]; Αρχικοποίηση int i[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 1} }; {0, 0, 1} }; char s[][10] = { "my", "name", "is", "joe" "my", "name", "is", "joe"};

45 Πολυδιάστατοι πίνακες(ii) Παράδειγμα: πολλαπλασιασμός πινάκων double a[3][4] =..., b[4][5] =..., b[4][5] =..., c[3][5]; c[3][5]; int i, j, k; for (i=0; i<3; i++) for (j=0; j<5; j++) { for (j=0; j<5; j++) { c[i][j] = 0.0; c[i][j] = 0.0; for (k=0; k<4; k++) for (k=0; k<4; k++) c[i][j] += a[i][k] * b[k][j]; c[i][j] += a[i][k] * b[k][j]; }

46 Εισαγωγή στις δομές δεδομένων(i) Αλγόριθμος Πεπερασμένο σύνολο εντολών που, όταν εκτελεστούν, επιτυγχάνουν κάποιο επιθυμητό αποτέλεσμα –Δεδομένα εισόδου και εξόδου –Κάθε εντολή πρέπει να είναι: καλά ορισμένη απλή –Η εκτέλεση πρέπει να σταματά

47 Εισαγωγή στις δομές δεδομένων(ii) Πολυπλοκότητα Μέτρο εκτίμησης της απόδοσης αλγορίθμων ως συνάρτηση του μεγέθους του προβλήματος που επιλύουν –Χρόνος εκτέλεσης –Χωρητικότητα μνήμης που απαιτείται Ακριβής μέτρηση πολυπλοκότητας t = f(n) Τάξη μεγέθους, συμβολισμοί Ο, Ω, Θ t = O(f(n))

48 Εισαγωγή στις δομές δεδομένων(iii) Ορισμός των κλάσεων Ο, Ω, Θ –Άνω όριο g = O(f)  c.  n 0.  n > n 0. g(n) n 0. g(n) < c f(n) –Κάτω όριο g = Ω(f)  c.  n 0.  n > n 0. g(n) > c f(n) –Τάξη μεγέθους g = Θ(f)  c 1, c 2.  n 0.  n > n 0. c 1 f(n) n 0. c 1 f(n) < g(n) < c 2 f(n) Διάταξη μερικών κλάσεων πολυπλοκότητας O(1) < O(logn) < O(  n) < O(n) < O(nlogn) < O(n 2 ) < O(n 3 ) < O(2 n ) < O(n!) < O(n n )

49 Εισαγωγή στις δομές δεδομένων(iv) Αφαίρεση δεδομένων (data abstraction) –Διαχωρισμός ιδιοτήτων και υλοποίησης –Ιδιότητες ενός τύπου δεδομένων: ο τρόπος με τον οποίο δημιουργεί κανείς και χρησιμοποιεί δεδομένα αυτού του τύπου –Υλοποίηση ενός τύπου δεδομένων: ο τρόπος με τον οποίο αναπαρίστανται τα δεδομένα στη μνήμη του υπολογιστή και προγραμματίζονται οι διαθέσιμες πράξεις

50 Εισαγωγή στις δομές δεδομένων(v) Οι λεπτομέρειες υλοποίησης επηρεάζουν την πολυπλοκότητα των αλγορίθμων Είναι συχνή επομένως η αλλαγή τρόπου υλοποίησης κάποιου τύπου δεδομένων Η αφαίρεση δεδομένων ελαχιστοποιεί τις αλλαγές που απαιτούνται στο πρόγραμμα που χρησιμοποιεί έναν τύπο δεδομένων, όταν αλλάξει ο τρόπος υλοποίησης

51 Αφηρημένοι τύποι δεδομένων Αφηρημένος τύπος δεδομένων – ΑΤΔ (abstract data type) –καθορίζει τις ιδιότητες του τύπου δεδομένων –δεν καθορίζει την υλοποίησή του Αλγεβρικός ορισμός ΑΤΔ –σύνταξη: όνομα του τύπου και επικεφαλίδες των πράξεων –σημασιολογία: κανόνες που περιγράφουν τη λειτουργία των πράξεων

52 Παράδειγμα ΑΤΔ: Σύνολα(i) Σύνταξη –Όνομα τύπου: set (σύνολα ακεραίων) –Επικεφαλίδες πράξεων: const set empty; set add (int x, set s); boolean member (int x, set s); set union (set s1, set s2); boolean subset (set s1, set s2); boolean equal (set s1, set s2); Σημείωση: θεωρούμε ότι έχει οριστεί κατάλληλα ο τύπος boolean.

53 Παράδειγμα ΑΤΔ: Σύνολα(ii) Σημασιολογία –Αξιωματικός ορισμός member : member(x, empty) = false member(x, add(x, s)) = true member(x, add(y, s)) = member(x, s) αν x != y –Αξιωματικός ορισμός union : union(empty, s) = s union(add(x, s1), s2) = add(x, union(s1, s2))

54 Παράδειγμα ΑΤΔ: Σύνολα(iii) Σημασιολογία –Αξιωματικός ορισμός subset : subset(empty, s) = true subset(add(x, s1), s2) = band(member(x, s2), subset(s1, s2)) –Αξιωματικός ορισμός equal : equal(s1, s2) = band(subset(s1, s2), subset(s2, s1))

55 Συγκεκριμένοι τύποι δεδομένων Συγκεκριμένος τύπος δεδομένων – ΣΤΔ (concrete data type) –καθορίζει τις ιδιότητες του τύπου δεδομένων –καθορίζει επακριβώς την υλοποίησή του Κάθε γλώσσα προγραμματισμού υποστηρίζει ορισμένους ΣΤΔ, π.χ. –απλοί τύποι: ακέραιοι αριθμοί, πραγματικοί αριθμοί, χαρακτήρες, λογικές τιμές –σύνθετοι τύποι: πίνακες (arrays), εγγραφές (records), δείκτες (pointers), σύνολα (sets)

56 Σχέση ΑΤΔ και ΣΤΔ(i) ΑΤΔ set: σύνολα ακεραίων s = { 1, 3, 7, 9 } Υλοποίηση 1: πίνακας από boolean falsetruefalsetrue false s[2]s[1]s[8]s[3]s[7]s[9]s[0] s[4] s[5]s[6]s[10] Υλοποίηση 2: bits ενός πίνακα από int 0 s[1]s[3] s[7] s[9] –Στατικός τρόπος υλοποίησης ΣΤΔ

57 Σχέση ΑΤΔ και ΣΤΔ(ii) Υλοποίηση 3: απλά συνδεδεμένη λίστα –Δυναμικός τρόπος υλοποίησης ΣΤΔ Υλοποίηση 4: συμβολοσειρά που περιέχει το μαθηματικό ορισμό του συνόλου "{x | x=1 \/ x=3 \/ x=7 \/ x=9}" "{x | 1 5}" –Δύσκολη η υλοποίηση των πράξεων –Απειροσύνολα: "{x | x > 100}" 1379

58 Πίνακες ως ΑΤΔ(i) Βασική πράξη: προσπέλαση στοιχείου a[i] Συνήθως υλοποιούνται με κάποιο ΣΤΔ πινάκων (arrays) –Κόστος προσπέλασης: O(1) Ο ΣΤΔ του μονοδιάστατου πίνακα επαρκεί για την υλοποίηση κάθε ΑΤΔ πίνακα –Συνάρτηση loc υπολογίζει τη θέση ενός στοιχείου του ΑΤΔ πίνακα στο μονοδιάστατο ΣΤΔ πίνακα της υλοποίησης

59 Πίνακες ως ΑΤΔ(ii) ΑΤΔ πίνακα δύο διαστάσεων n  m loc (n, m, i, j) = m (i – 1) + j – 1 Αρίθμηση κατά στήλες loc (n, m, i, j) = n (j – 1) + i – i = 1 i = 2 i = 3 j = n = 3 m = 6

60 Πίνακες ως ΑΤΔ(iii) ΑΤΔ κάτω τριγωνικού πίνακα n  n loc (n, i, j) = i (i – 1) / 2 + j – 1 Ομοίως για συμμετρικούς πίνακες i = 1 i = 2 i = 3 j = n = i = 4 i = 5

61 Πίνακες ως ΑΤΔ(iv) ΑΤΔ τριδιαγώνιου πίνακα n  n loc (n, i, j) = 2 i + j – i = 1 i = 2 i = 3 j = n = i = 4 i = 5

62 Πίνακες ως ΑΤΔ(v) ΑΤΔ αραιού πίνακα n  m –Υλοποίηση με δυαδικό πίνακα –Υλοποίηση με τρεις πίνακες row = [ 1, 2, 3, 3, 4 ]col = [ 1, 3, 2, 3, 5 ] val = [ a 1, a 2, a 3, a 4, a 5 ] a1a1 a2a2 a3a3 a4a4 i = 1 i = 2 i = 3 j = n = 4 a5a5 i = 4 m = 5

63 Αναζήτηση σε πίνακες(i) Σειριακή αναζήτηση –Τα στοιχεία διατρέχονται κατά σειρά –Κόστος: O(n) n = 8 x = 42 (1)(3)(2)(4)(5) –Βελτίωση: στοιχείο “φρουρός” (sentinel) n = 8 x = 7 7

64 Αναζήτηση σε πίνακες(ii) Υλοποίηση σε C int ssearch (int a[], int n, int x) { int i; int i; for (i = 0; i < n; i++) for (i = 0; i < n; i++) if (a[i] == x) if (a[i] == x) return i; return i; return -1; return -1;}

65 Αναζήτηση σε πίνακες(iii) Υλοποίηση σε C με φρουρό int ssearch_s (int a[], int n, int x) { int i; int i; a[n] = x; a[n] = x; for (i = 0; a[i] != x; i++); for (i = 0; a[i] != x; i++); return (i < n) ? i : -1; return (i < n) ? i : -1;}

66 Αναζήτηση σε πίνακες(iv) Δυαδική αναζήτηση –Ο πίνακας πρέπει να είναι ταξινομημένος –Κόστος: O(logn) n = 8 x = 42 (1)(3)(2) Άλλες μέθοδοι αναζήτησης –Μικρότερο κόστος  περισσότερος χώρος –Πίνακες κατακερματισμού (hash tables)

67 Ταξινόμηση πινάκων(i) Ταξινόμηση επιλογής (selection sort) –Ιδέα: για κάθε i κατ’ αύξουσα σειρά βρες το μικρότερο των στοιχείων μετά το a[i] αντιμετάθεσέ το με το a[i] –Κόστος: Ο(n 2 ) –Βελτίωση: στοιχείο φρουρός

68 Ταξινόμηση πινάκων(ii) Ταξινόμηση επιλογής, υλοποίηση σε C void ssort (int a[], int n) { int i, j; int i, j; for (i = 0; i < n-1; i++) { for (i = 0; i < n-1; i++) { int min = a[i], minj = i; int min = a[i], minj = i; for (j = i+1; j < n; j++) for (j = i+1; j < n; j++) if (a[j] < min) if (a[j] < min) min = a[minj = j]; min = a[minj = j]; a[minj] = a[i]; a[minj] = a[i]; a[i] = min; a[i] = min; }}

69 Ταξινόμηση πινάκων(iii) Ταξινόμηση εισαγωγής (insertion sort) –Χρησιμοποιούμε αυτό τον τρόπο όταν ταξινομούμε τα χαρτιά μιας τράπουλας –Ιδέα: για κάθε i από το δεύτερο και κατ’ αύξουσα σειρά τοποθέτησε το a[i] στη σωστή του θέση μεταξύ των στοιχείων που είναι πριν από αυτό –Κόστος: Ο(n 2 ) –Βελτιώσεις: στοιχείο φρουρός δυαδική εισαγωγή

70 Ταξινόμηση πινάκων(iv) Ταξινόμηση εισαγωγής, υλοποίηση σε C void isort (int a[], int n) { int i, j; int i, j; for (i = 1; i < n; i++) { for (i = 1; i < n; i++) { int x = a[i]; int x = a[i]; for (j = i-1; j >= 0; j--) for (j = i-1; j >= 0; j--) if (x < a[j]) if (x < a[j]) a[j+1] = a[j]; a[j+1] = a[j]; else else break; break; a[j+1] = x; a[j+1] = x; }}

71 Ταξινόμηση πινάκων(v) Ταξινόμηση φυσαλίδας (bubble sort) –Ιδέα: για κάθε i κατ’ αύξουσα σειρά για κάθε j > i κατά φθίνουσα σειρά αν a[j-1] > a[j] αντιμετάθεσε τα a[j-1] και a[j] –Κόστος: Ο(n 2 ) –Βελτιώσεις: σταματά αν σε ένα πέρασμα δεν γίνει αντιμετάθεση σε ποιο σημείο έγινε η τελευταία αντιμετάθεση αλλαγή κατεύθυνσης μεταξύ διαδοχικών περασμάτων (shake sort)

72 Ταξινόμηση πινάκων(vi) Ταξινόμηση φυσαλίδας, υλοποίηση σε C void bsort (int a[], int n) { int i, j; int i, j; for (i = 0; i < n; i++) for (i = 0; i < n; i++) for (j = n-1; j > i; j--) for (j = n-1; j > i; j--) if (a[j-1] > a[j]) { if (a[j-1] > a[j]) { int temp = a[j-1]; int temp = a[j-1]; a[j-1] = a[j]; a[j-1] = a[j]; a[j] = temp; a[j] = temp; }}

73 Ταξινόμηση πινάκων(vii) Ταξινόμηση με διαμέριση (quick sort) –Ιδέα: διάλεξε ένα τυχαίο στοιχείο x του πίνακα διαμέρισε τον πίνακα, μεταφέροντας: –τα στοιχεία μικρότερα του x στην αρχή –τα στοιχεία μεγαλύτερα του x στο τέλος αναδρομικά, ταξινόμησε τα δύο μέρη –Κόστος:Ο(n 2 ) στη χειρότερη περίπτωση Ο(n logn) κατά μέσο όρο

74 Ταξινόμηση πινάκων(viii) Quick sort, υλοποίηση σε C void qsort (int a[], int n) { qsort_auxil(a, 0, n-1); qsort_auxil(a, 0, n-1);} void qsort_auxil (int a[], int lower, int upper) int upper){ if (lower < upper) { if (lower < upper) { int x = a[(lower + upper) / 2]; int x = a[(lower + upper) / 2]; int i, j; int i, j; for (i = lower, j = upper; for (i = lower, j = upper; i <= j; i++, j--) { i <= j; i++, j--) { while (a[i] < x) i++; while (a[i] < x) i++; while (a[j] > x) j--; while (a[j] > x) j--;

75 Ταξινόμηση πινάκων(ix) Quick sort, υλοποίηση σε C(συνέχεια) if (i <= j) { if (i <= j) { int temp = a[i]; int temp = a[i]; a[i] = a[j]; a[i] = a[j]; a[j] = temp; a[j] = temp; } } qsort_auxil(a, lower, j); qsort_auxil(a, lower, j); qsort_auxil(a, i, upper); qsort_auxil(a, i, upper); }}

76 Ταξινόμηση πινάκων(x) Άλλοι τρόποι ταξινόμησης –Ταξινόμηση του Shell (shell sort), κόστος: Ο(n 2 ) –Ταξινόμηση σε σωρό (heap sort), κόστος: Ο(n logn) –Ταξινόμηση με συγχώνευση (merge sort), κόστος: Ο(n logn)

77 Ορισμοί τύπων Συνώνυμα απλών τύπων typedef double real; real x, y; Συνώνυμα σύνθετων τύπων typedef double vector [10]; vector v; for (i = 0; i < 10; i++) v[i] = i; v[i] = i;

78 Απαριθμήσεις (enumerations) Ο τύπος enum enum color_tag { GREEN, RED, BLUE, WHITE, BLACK GREEN, RED, BLUE, WHITE, BLACK}; enum color_tag c; c = GREEN; typedef enum { GREEN, RED, BLUE, WHITE, BLACK GREEN, RED, BLUE, WHITE, BLACK } color; color c = WHITE;

79 Δομές (structures)(i) Ο τύπος struct struct complex_tag { double re, im; double re, im;}; struct complex_tag z; z.re = 1.0; z.im = -1.0; typedef struct complex_tag complex; complex z; complex zs [100]; re im z

80 Δομές (structures)(ii) Παράδειγμα complex complement (complex z) { complex result; complex result; result.re = z.re; result.re = z.re; result.im = -z.im result.im = -z.im return result; return result;}

81 Δομές (structures)(iii) Παράδειγμα typedef struct { char firstName [30]; char firstName [30]; char lastName [50]; char lastName [50]; char phone [10]; char phone [10]; int age; int age; double salary; double salary; } record; record r [1000]; r[423].age = 32;

82 Ενώσεις (unions) Ο τύπος union union number_tag { int i; int i; double d; double d;}; union number_tag n; d i n n.d = 1.2; printf("%lf\n", n.d); n.i = 42; printf("%d\n", n.i); printf("%lf\n", n.d); /* wrong! */

84 Δείκτες (pointers)(ii) Δεικτοδότηση: & –η διεύθυνση μιας μεταβλητής p = &x; Αποδεικτοδότηση: * –το περιεχόμενο μιας διεύθυνσης printf("%d", *p); *p = 7; x δ124 p δ δ124

86 Πίνακες και δείκτες(ii) Ισοδυναμία πινάκων και δεικτών –Ένας πίνακας είναι ένας δείκτης στο πρώτο στοιχείο. –a[i] ισοδύναμο με *(a+i) –Οι πίνακες όμως είναι σταθεροί δείκτες, δηλαδή δεν μπορούν να αλλάξουν τιμή int a[3] = {7, 6, 42}; int *p = &a; p++; /* correct */ a++; /* wrong! */

87 Πίνακες και δείκτες(iii) Παράδειγμα: αντιγραφή πινάκων int a[10], b[10]; int *p = a, *q = b, i; /* assume b initialized */ for (i=0; i<10; i++) *p++ = *q++; *p++ = *q++;

88 Πίνακες και δείκτες(iv) Παράδειγμα: εκτύπωση συμβολοσειράς void putchar (char c); char s[] = "Hello world!\n"; char *p; for (p = s; *p != '\0'; p++) putchar(*p); putchar(*p);

89 Κενός δείκτης και δείκτης σε κενό Ο κενός δείκτης: NULL –Απαγορεύεται να αποδεικτοδοτηθεί! int *p = NULL; *p = 42; /* wrong! */ –Ο μόνος δείκτης που αντιστοιχεί στην ψευδή λογική τιμή, όταν χρησιμοποιείται σε συνθήκη Ο δείκτης σε κενό: void * –Γενική μορφή δείκτη –Απαγορεύεται να αποδεικτοδοτηθεί! –Απαγορεύεται η αριθμητική δεικτών!

90 Δείκτες αντί περάσματος με αναφορά Κώδικας Pascal procedure inc (var x : integer); begin x := x+1 x := x+1end;... inc(a)... Ισοδύναμος κώδικας C void inc (int * px) { (*px)++; (*px)++;}... inc(&a)...

91 Δείκτες σε εγγραφές Συντομογραφία p->x είναι ισοδύναμο με (*p).x Παράδειγμα struct { int x, y; int x, y; } coordinates, *p; coordinates.x = 1; coordinates.y = 3; p = &coordinates; printf("%d\n", p->x); printf("%d\n", p->y);

92 Μετατροπές τύπων(i) Έμμεσες (coercions) double d = 3; (με ανάθεση) int x = 3.14; int f (int x); (με πέρασμα παραμέτρου) f(3.14); Άμεσες (type casting) ( τύπος ) έκφραση (double) 3 (int) 3.14 (int *) NULL

93 Μετατροπές τύπων(ii) Πρόβλημα: πώς μπορώ να τυπώσω το αποτέλεσμα της πραγματικής διαίρεσης δυο ακεραίων αριθμών, χωρίς νέες μεταβλητές; int x = 5, y = 3; Λάθος λύση #1: printf("%d", x/y); Λάθος λύση #2: printf("%lf", x/y); Σωστές λύσεις: printf("%lf", 1.0 * x / y); printf("%lf", (double) x / (double) y); printf("%lf", (double) x / y);

94 Δυναμική παραχώρηση μνήμης (i) Συναρτήσεις βιβλιοθήκης Συναρτήσεις βιβλιοθήκης –void * malloc (size_t n); Δυναμική παραχώρηση μνήμης μήκους n bytes. Το αποτέλεσμα πρέπει να μετατραπεί στο σωστό τύπο. Επιστρέφεται NULL αν εξαντληθεί η μνήμη. –void free (void * p); Αποδέσμευση της μνήμης στην οποία δείχνει το p. Το p πρέπει να έχει δημιουργηθεί με προηγούμενη κλήση στη malloc. Πόσα bytes χρειάζονται; –sizeof( type ) π.χ. sizeof(int) –sizeof( variable ) π.χ. sizeof(x)

95 Δυναμική παραχώρηση μνήμης (ii) Παράδειγμα int *p; int i; p = (int *) malloc(sizeof(int)); *p = 42; free(p); p = (int *) malloc(10 * sizeof(int)); for (i = 0; i < 10; i++) p[i] = 42; p[i] = 42;free(p); Το αποτέλεσμα της malloc πρέπει να ελεγχθεί ότι δεν είναι NULL !

96 Δυναμικοί ΣΤΔ(i) Χρησιμοποιούνται για την υλοποίηση ΑΤΔ Παραδείγματα –συνδεδεμένες λίστες –δέντρα –γράφοι Πώς υλοποιούνται στη C; –με κατάλληλο συνδυασμό δομών ( struct ) και δεικτών (pointers), και –με δυναμική παραχώρηση μνήμης

97 Δυναμικοί ΣΤΔ(ii) Πλεονεκτήματα έναντι στατικών ΣΤΔ –Δεν επιβάλλουν περιορισμούς στο μέγιστο πλήθος των δεδομένων –Η μνήμη που χρησιμοποιείται είναι ανάλογη του πραγματικού πλήθους των δεδομένων –Κάποιες πράξεις υλοποιούνται αποδοτικότερα Μειονεκτήματα έναντι στατικών ΣΤΔ –Για σταθερό και γνωστό πλήθος δεδομένων, χρησιμοποιούν συνήθως περισσότερη μνήμη –Κάποιες πράξεις υλοποιούνται λιγότερο αποδοτικά

98 Δυναμικοί ΣΤΔ(iii) Ιδέα –Κατασκευάζεται ένα σύνολο κόμβων –Κάθε κόμβος περιέχει πληροφορίες και συνδέσμους προς άλλους κόμβους ΠΣΠΣ

99 Απλά συνδεδεμένες λίστες(i) Είναι γραμμικές διατάξεις Κάθε κόμβος περιέχει ένα σύνδεσμο στον επόμενο κόμβο Ο τελευταίος κόμβος έχει κενό σύνδεσμο

100 Απλά συνδεδεμένες λίστες(ii) Παράδειγμα: λίστα ακεραίων struct node_tag { int data; int data; struct node_tag * next; struct node_tag * next;}; typedef struct node_tag Node, * LinkedList; Κενή λίστα

101 Απλά συνδεδεμένες λίστες (iii) Προσθήκη στοιχείων –απόφαση πού θα προστεθεί –δημιουργία νέου κόμβου –αντιγραφή πληροφορίας –σύνδεση νέου κόμβου i i εδώ

102 Απλά συνδεδεμένες λίστες (iv) Αφαίρεση στοιχείων –απόφαση ποιο στοιχείο θα αφαιρεθεί –καταστροφή κόμβου –σύνδεση υπόλοιπων κόμβων αυτό

103 Ουρές(i) First In First Out (FIFO) ό,τι μπαίνει πρώτο, βγαίνει πρώτο Ουρά ακεραίων –ΑΤΔ: queue –const queue queueEmpty; –void queueInsert (queue * qp, int t); –int queueRemove (queue * qp); –int queueHead (queue q);

104 Ουρές(ii) Υλοποίηση με απλά συνδεδεμένη λίστα firstlast

105 Υλοποίηση ουράς σε C(i) Υλοποίηση με απλά συνδεδεμένη λίστα typedef struct list_tag { int data; int data; struct list_tag * next; struct list_tag * next; } ListNode; Τύπος queue typedef struct { ListNode * first; ListNode * first; ListNode * last; ListNode * last; } queue;

106 Υλοποίηση ουράς σε C(ii) Άδεια ουρά const queue queueEmpty = { NULL, NULL }; Εισαγωγή στοιχείου void queueInsert (queue * qp, int t) { ListNode * n = (ListNode *) malloc(sizeof(ListNode)); ListNode * n = (ListNode *) malloc(sizeof(ListNode)); if (n == NULL) { if (n == NULL) { printf("Out of memory\n"); printf("Out of memory\n"); exit(1); exit(1); }

107 Υλοποίηση ουράς σε C(iii) Εισαγωγή στοιχείου (συνέχεια) n->data = t; n->data = t; n->next = NULL; n->next = NULL; if (qp->last == NULL) if (qp->last == NULL) qp->first = qp->last = n; qp->first = qp->last = n; else { else { qp->last->next = n; qp->last->next = n; qp->last = n; qp->last = n; }}

108 Υλοποίηση ουράς(iv) Αφαίρεση στοιχείου int queueRemove (queue * qp) { ListNode * n; ListNode * n; int result; int result; if (qp->first == NULL) { if (qp->first == NULL) { printf("Nothing to remove" printf("Nothing to remove" " from an empty queue\n"); " from an empty queue\n"); exit(1); exit(1); }

109 Υλοποίηση ουράς(v) Αφαίρεση στοιχείου (συνέχεια) n = qp->first; n = qp->first; result = qp->first->data; result = qp->first->data; qp->first = qp->first->next; qp->first = qp->first->next; free(n); free(n); if (qp->first == NULL) if (qp->first == NULL) qp->last = NULL; qp->last = NULL; return result; return result;}

110 Υλοποίηση ουράς(vi) Εξέταση στοιχείου int queueHead (queue q) { if (q.first == NULL) { if (q.first == NULL) { fprintf(stderr, "Nothing to see" " in an empty queue\n"); fprintf(stderr, "Nothing to see" " in an empty queue\n"); exit(1); exit(1); } return q.first->data; return q.first->data;}

111 Στοίβες(i) Last In First Out (LIFO) ό,τι μπαίνει τελευταίο, βγαίνει πρώτο Στοίβα ακεραίων –ΑΤΔ: stack –const stack stackEmpty; –void stackPush (stack * sp, int t); –int stackPop (stack * sp); –int stackTop (stack s);

112 Στοίβες(ii) Υλοποίηση με απλά συνδεδεμένη λίστα top

113 Υλοποίηση στοίβας σε C(i) Τύπος stack typedef ListNode * stack; Άδεια στοίβα const stack stackEmpty = NULL; Εισαγωγή στοιχείου void stackPush (stack * sp, int t) { ListNode * n = (ListNode *) malloc(sizeof(ListNode)); ListNode * n = (ListNode *) malloc(sizeof(ListNode)); if (n == NULL) { if (n == NULL) { printf("Out of memory\n"); printf("Out of memory\n"); exit(1); exit(1); }

114 Υλοποίηση στοίβας σε C(ii) Εισαγωγή στοιχείου (συνέχεια) n->data = t; n->data = t; n->next = *sp; n->next = *sp; *sp = n; *sp = n;} Αφαίρεση στοιχείου int stackPop (stack * sp) { ListNode * n; ListNode * n; int result; int result; if (*sp == NULL) { if (*sp == NULL) { printf("Nothing to remove" printf("Nothing to remove" " from an empty stack\n"); " from an empty stack\n"); exit(1); exit(1); }

115 Υλοποίηση στοίβας σε C(iii) Αφαίρεση στοιχείου (συνέχεια) n = *sp; n = *sp; result = (*sp)->data; result = (*sp)->data; *sp = (*sp)->next; *sp = (*sp)->next; free(n); free(n); return result; return result;}

116 Υλοποίηση στοίβας σε C(iv) Εξέταση στοιχείου int stackTop (stack s) { if (s == NULL) { if (s == NULL) { printf("Nothing to see" printf("Nothing to see" " in an empty stack\n"); " in an empty stack\n"); exit(1); exit(1); } return s->data; return s->data;}

117 Διπλά συνδεδεμένες λίστες(i) firstlast Επίσης γραμμικές διατάξεις Δυο σύνδεσμοι σε κάθε κόμβο, προς τον επόμενο και προς τον προηγούμενο Γενική μορφή, π.χ. για υλοποίηση ουράς:

118 Διπλά συνδεδεμένες λίστες(ii) Τύπος κόμβου DListNode typedef struct DListNode_tag { int data; int data; struct DListNode_tag * next; struct DListNode_tag * next; struct DListNode_tag * prev; struct DListNode_tag * prev; } DListNode; Τύπος dlist typedef struct { DListNode * first; DListNode * first; DListNode * last; DListNode * last; } dlist; Άδεια λίστα const dlist dlistEmpty = { NULL, NULL };

119 Διπλά συνδεδεμένες λίστες (iii) Τύπος κόμβου DListNode typedef struct DListNode_tag { int data; int data; struct DListNode_tag * next; struct DListNode_tag * next; struct DListNode_tag * prev; struct DListNode_tag * prev; } DListNode; Τύπος dlist typedef struct { DListNode * first; DListNode * first; DListNode * last; DListNode * last; } dlist; firstlast

120 Διπλά συνδεδεμένες λίστες (iv) Εισαγωγή στοιχείου στην αρχή firstlast

121 Διπλά συνδεδεμένες λίστες(v) Εισαγωγή στοιχείου στην αρχή void dlistInsert (dlist * lp, int t) { DListNode * n = (DListNode *) malloc(sizeof(DListNode)); DListNode * n = (DListNode *) malloc(sizeof(DListNode)); if (n == NULL) { if (n == NULL) { fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Out of memory\n"); exit(1); exit(1); } n->data = t; n->data = t;

122 Διπλά συνδεδεμένες λίστες (vi) Εισαγωγή στοιχείου στην αρχή (συνέχεια) if (lp->first == NULL) { if (lp->first == NULL) { n->prev = n->next = NULL; n->prev = n->next = NULL; lp->first = lp->last = n; lp->first = lp->last = n; } else { else { n->prev = NULL; n->prev = NULL; n->next = lp->first; n->next = lp->first; lp->first->prev = n; lp->first->prev = n; lp->first = n; lp->first = n; }}

123 Διπλά συνδεδεμένες λίστες (vii) if (lp->first == NULL) { n->prev = n->next = NULL; n->prev = n->next = NULL; lp->first = lp->last = n; lp->first = lp->last = n; } else { else { n->prev = NULL; n->prev = NULL; n->next = lp->first; n->next = lp->first; lp->first->prev = n; lp->first->prev = n; lp->first = n; lp->first = n; }} firstlast n

124 Κυκλικές λίστες(i) Τύπος clist typedef struct { ListNode * first; ListNode * first; ListNode * last; ListNode * last; } clist; Άδεια λίστα const clist clistEmpty = { NULL, NULL }; firstlast

125 Κυκλικές λίστες(ii) Εισαγωγή στοιχείου void clistInsert (clist * lp, int t) { ListNode * n = (ListNode *) malloc(sizeof(ListNode)); ListNode * n = (ListNode *) malloc(sizeof(ListNode)); if (n == NULL) { if (n == NULL) { fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Out of memory\n"); exit(1); exit(1); } n->data = t; n->data = t;

126 Κυκλικές λίστες(iii) Εισαγωγή στοιχείου (συνέχεια) if (lp->first == NULL) { if (lp->first == NULL) { lp->first = lp->last = n; lp->first = lp->last = n; n->next = n; n->next = n; } else { else { n->next = lp->first; n->next = lp->first; lp->last->next = n; lp->last->next = n; lp->last = n; lp->last = n; }}

127 Κυκλικές λίστες(iv) if (lp->first == NULL) { if (lp->first == NULL) { lp->first = lp->last = n; lp->first = lp->last = n; n->next = n; n->next = n; } else { else { n->next = lp->first; n->next = lp->first; lp->last->next = n; lp->last->next = n; lp->last = n; lp->last = n; }} firstlast n

128 Κυκλικές λίστες(v) Αφαίρεση στοιχείου int clistRemove (clist * lp) { int result; int result; if (lp->first == NULL) { if (lp->first == NULL) { fprintf(stderr, "Nothing to remove" " from empty list\n"); fprintf(stderr, "Nothing to remove" " from empty list\n"); exit(1); exit(1); } result = lp->first->data; result = lp->first->data;

129 Κυκλικές λίστες(vi) Αφαίρεση στοιχείου (συνέχεια) if (lp->first == lp->last) { if (lp->first == lp->last) { free(lp->first); free(lp->first); lp->first = lp->last = NULL; lp->first = lp->last = NULL; } else { else { lp->first = lp->first->next; lp->first = lp->first->next; free(lp->last->next); free(lp->last->next); lp->last->next = lp->first; lp->last->next = lp->first; } return result; return result;}

130 Κυκλικές λίστες(vii) if (lp->first == lp->last) { free(lp->first); free(lp->first); lp->first = lp->last = NULL; lp->first = lp->last = NULL; } else { else { lp->first = lp->first->next; lp->first = lp->first->next; free(lp->last->next); free(lp->last->next); lp->last->next = lp->first; lp->last->next = lp->first; } return result; return result;} firstlast

131 Κυκλικές λίστες(viii) Εκτύπωση στοιχείων (λάθος!) void clistPrint (clist l) { ListNode * n; ListNode * n; for (n = l.first; n != NULL; n = n->next) { for (n = l.first; n != NULL; n = n->next) { printf("%d\n", n->data); printf("%d\n", n->data); }}

132 Κυκλικές λίστες(ix) Εκτύπωση στοιχείων (σωστό!) void clistPrint (clist l) { ListNode * n; ListNode * n; for (n = l.first; n != NULL; n = n->next) { for (n = l.first; n != NULL; n = n->next) { printf("%d\n", n->data); printf("%d\n", n->data); if (n->next == l.first) if (n->next == l.first) break; break; }}

133 Ταξινομημένες λίστες(i) Τύπος slist typedef ListNode * slist; Άδεια λίστα const slist slistEmpty = NULL; Εισαγωγή στοιχείου void slistInsert (slist * lp, int t) { ListNode * n = (ListNode *) malloc(sizeof(ListNode)); ListNode * n = (ListNode *) malloc(sizeof(ListNode)); if (n == NULL) { if (n == NULL) { printf("Out of memory\n"); printf("Out of memory\n"); exit(1); exit(1); }

134 Ταξινομημένες λίστες(ii) Εισαγωγή στοιχείου (συνέχεια) n->data = t; n->data = t; while (*lp != NULL && (*lp)->data data < t) lp = &((*lp)->next); lp = &((*lp)->next); n->next = *lp; n->next = *lp; *lp = n; *lp = n;} n 20 lp

135 Ταξινομημένες λίστες (iii) Αφαίρεση στοιχείου void slistRemove (slist * lp, int t) { ListNode * n; ListNode * n; while (*lp != NULL && (*lp)->data data < t) lp = &((*lp)->next); lp = &((*lp)->next); if (*lp == NULL) { if (*lp == NULL) { printf(”%d was not found\n”, t); printf(”%d was not found\n”, t); exit(1); exit(1); } n = *lp; n = *lp; *lp = (*lp)->next; *lp = (*lp)->next; free(n); free(n);}

136 lp Ταξινομημένες λίστες (iv) void slistRemove (slist * lp, int t) { ListNode * n; ListNode * n; while (*lp != NULL && (*lp)->data data < t) lp = &((*lp)->next); lp = &((*lp)->next); if (*lp == NULL) { if (*lp == NULL) { printf(”%d was not found\n”, t); printf(”%d was not found\n”, t); exit(1); exit(1); } n = *lp; n = *lp; *lp = (*lp)->next; *lp = (*lp)->next; free(n); free(n);} t=24 n

137 Παράμετροι του προγράμματος (i) Επικεφαλίδα του προγράμματος int main (int argc, char * argv[]); Παράμετροι –argc ο αριθμός των παραμέτρων –argv[i] η i-οστή παράμετρος –argv[0] το όνομα του προγράμματος Αποτέλεσμα –ακέραιος αριθμός που επιστρέφεται στο λειτουργικό σύστημα –συνήθως 0 για επιτυχή τερματισμό

138 Παράμετροι του προγράμματος (ii) Παράδειγμα int main (int argc, char * argv[]) { int i; int i; printf("Program %s called with " printf("Program %s called with " "%d parameters:\n", argv[0], "%d parameters:\n", argv[0], argc-1); argc-1); for (i = 1; i < argc; i++) for (i = 1; i < argc; i++) printf(" %s", argv[i]); printf(" %s", argv[i]); printf("\nand will return 0\n"); printf("\nand will return 0\n"); return 0; return 0;}

139 Συναρτήσεις εισόδου-εξόδου(i) Βασικές συναρτήσεις εισόδου-εξόδου int printf (const char * format,...); int scanf (const char * format,...); Ειδικοί χαρακτήρες στο format –Ακέραιοι αριθμοί %d στο δεκαδικό σύστημα %u χωρίς πρόσημο στο δεκαδικό σύστημα %o χωρίς πρόσημο στο οκταδικό σύστημα %x χωρίς πρόσημο στο δεκαεξαδικό σύστημα

140 Συναρτήσεις εισόδου-εξόδου(ii) Ειδικοί χαρακτήρες στο format –Αριθμοί κινητής υποδιαστολής %f σε μορφή: [-]ddd.dddddd %e σε μορφή: [-]ddd.dddddd e [+/-]ddd %g σε μορφή %f ή %e –Άλλοι τύποι %c χαρακτήρες %s συμβολοσειρές %p δείκτες

141 Συναρτήσεις εισόδου-εξόδου (iii) Παραλλαγές στο format –Μέγεθος αριθμών %h αριθμοί short π.χ. %hd, %hx %l αριθμοί long ή double π.χ. %ld, %lf %L αριθμοί long double π.χ. %Lf –Μήκος αποτελέσματος %8d αριθμός σε μήκος 8 χαρακτήρων %20s συμβολοσειρά σε μήκος 20 χαρακτήρων %+8d αριθμός σε μήκος 8 χαρακτήρων με + %08d αριθμός σε μήκος 8 χαρακτήρων, τα πρώτα 0 %-8d όπως το %8d με στοίχιση αριστερά

142 Συναρτήσεις εισόδου-εξόδου (iv) Είσοδος-έξοδος χαρακτήρων int putchar (int c); int getchar (); Είσοδος-έξοδος συμβολοσειρών int puts (const char * s); char * gets (char * s); Έλεγχος τέλους δεδομένων int eof (); –Η σταθερά EOF παριστάνει το τέλος των δεδομένων και έχει τύπο int.

143 Παράδειγμα Αντιγραφή δεδομένων –οι χαρακτήρες που διαβάζονται εκτυπώνονται, μέχρι να παρουσιαστεί τέλος δεδομένων void main () { int c; int c; while ((c = getchar()) != EOF) while ((c = getchar()) != EOF) putchar(c); putchar(c);}

144 Συναρτήσεις διαχείρισης αρχείων(i) Τύπος αρχείου FILE * fp; Άνοιγμα αρχείων FILE * fopen (const char * filename, const char * mode); –Παράμετρος mode r ανάγνωση (read) w εγγραφή (write) a προσθήκη (append) t κείμενο (text) b δυαδικά δεδομένα (binary)

145 Συναρτήσεις διαχείρισης αρχείων(ii) Κλείσιμο αρχείων int fclose (FILE * fp); Είσοδος-έξοδος χαρακτήρων int fputc (int c, FILE * fp); int fgetc (FILE * fp); Είσοδος-έξοδος συμβολοσειρών int fputs (const char * s, FILE * fp); char * fgets (char * s, int n, FILE * fp);

146 Συναρτήσεις διαχείρισης αρχείων(iii) Βασικές συναρτήσεις εισόδου-εξόδου int fprintf (FILE * fp, const char * format,...); int fscanf (FILE * fp, const char * format,...); Έλεγχος τέλους αρχείου int feof (FILE * fp);

147 Συναρτήσεις διαχείρισης αρχείων(iv) Είσοδος-έξοδος πολλών δεδομένων size_t fwrite (const void * p, size_t size, size_t num, FILE * fp); size_t fread (void * p, size_t size, size_t num, FILE * fp); –Ο ακέραιος τύπος size_t χρησιμοποιείται για τη μέτρηση χώρου μνήμης σε bytes.

148 Παράδειγμα(i) Αντιγραφή δυαδικών αρχείων int main (int argc, char * argv[]) { FILE * fin, * fout; FILE * fin, * fout; unsigned char buffer[1000]; unsigned char buffer[1000]; size_t count; size_t count; fin = fopen(argv[1], "rb"); fin = fopen(argv[1], "rb"); if (fin == NULL) if (fin == NULL) return 1; return 1; fout = fopen(argv[2], "wb"); fout = fopen(argv[2], "wb"); if (fout == NULL) if (fout == NULL) return 2; return 2;

149 Παράδειγμα(ii) (συνεχίζεται) while (!feof(fin)) { while (!feof(fin)) { count = fread(buffer, 1, 1000, fin); count = fread(buffer, 1, 1000, fin); fwrite(buffer, 1, count, fout); fwrite(buffer, 1, count, fout); } fclose(fin); fclose(fin); fclose(fout); fclose(fout); return 0; return 0;}

150 Συναρτήσεις βιβλιοθήκης(i) Είσοδος και έξοδος Είσοδος και έξοδος –Περιέχει όλες τις συναρτήσεις εισόδου-εξόδου –Προκαθορισμένα αρχεία FILE * stdin; τυπική είσοδος FILE * stdout; τυπική έξοδος FILE * stderr; τυπική έξοδος σφαλμάτων –Ισοδυναμίες printf(...)  fprintf(stdout,...) scanf(...)  fscanf(stdin,...) κ.λπ. –Συναρτήσεις διαχείρισης αρχείων με τυχαία πρόσβαση (random access)

151 Συναρτήσεις βιβλιοθήκης(ii) Διαχείριση συμβολοσειρών Διαχείριση συμβολοσειρών –size_t strlen (const char * s); Μέτρηση αριθμού χαρακτήρων της συμβολοσειράς s. –char * strcpy (char * s1, const char * s2); Αντιγραφή της συμβολοσειράς s2 στην s1. –char * strcat (char * s1, const char * s2); Προσθήκη της συμβολοσειράς s2 στο τέλος της s1. –int strcmp (const char * s1, const char * s2); const char * s2); Σύγκριση των συμβολοσειρών s1 και s2.

152 Συναρτήσεις βιβλιοθήκης(iii) Μετατροπή συμβολοσειρών Μετατροπή συμβολοσειρών –int atoi (const char * s); Μετατροπή της συμβολοσειράς s σε int. –long int atol (const char * s); Μετατροπή της συμβολοσειράς s σε long int. –double atof (const char * s); Μετατροπή της συμβολοσειράς s σε double.

153 Παράδειγμα Μια δυνατή υλοποίηση της strcmp int strcmp (const char * s1, const char * s2) const char * s2){ while (*s1 == *s2 && *s1 != '\0') while (*s1 == *s2 && *s1 != '\0') { s1++; s2++; } { s1++; s2++; } return (*s1)-(*s2); return (*s1)-(*s2);} –Υπόθεση: οι τιμές του τύπου char είναι στο διάστημα (όχι αρνητικές)  while (*s1 && *s1++ == *s2++);

154 Προεπεξεργαστής (preprocessor)(i) Εντολή #include #include #include #include "myheader.h" Εντολή #define #define MAX_CHARS 1000 char s[MAX_CHARS]; #define INC(x) ((x)++) INC(a);INC(*p);

155 Προεπεξεργαστής (preprocessor)(ii) Εντολές #ifdef, #ifndef, #else και #endif #define DEBUG #ifdef DEBUG printf("debugging is on\n"); printf("debugging is on\n");#else printf("debugging is off\n") printf("debugging is off\n")#endif #ifndef DEBUG printf("optimizations allowed\n"); printf("optimizations allowed\n");#endif

156 Δυαδικά δένδρα(i) Binary trees Δυο σύνδεσμοι σε κάθε κόμβο –αριστερό και δεξί παιδί Κάθε κόμβος έχει 0, 1 ή 2 παιδιά Ρίζα: ο αρχικός κόμβος του δένδρου Φύλλα: κόμβοι χωρίς παιδιά Βάθος κόμβου: αριθμός συνδέσμων από τη ρίζα

157 Δυαδικά δένδρα(ii) Τύπος κόμβου TreeNode typedef struct TreeNode_tag { int data; int data; struct TreeNode_tag * left; struct TreeNode_tag * left; struct TreeNode_tag * right; struct TreeNode_tag * right; } TreeNode; Τύπος tree typedef TreeNode * tree; Κενό δένδρο const tree treeEmpty = NULL;

158 Δυαδικά δένδρα(iii) Εισαγωγή σε δένδρα –Καθοριστική απόφαση: σε ποιο σημείο του δένδρου θα εισαχθεί ο νέος κόμβος –Ισοζυγισμένα δένδρα (balanced trees): το βάθος δυο φύλλων διαφέρει το πολύ κατά 1 Συνάρτηση μέγιστου βάθους int treeDepth (tree t) { if (t == NULL) return 0; if (t == NULL) return 0; return 1 + max(treeDepth(t->left), return 1 + max(treeDepth(t->left), treeDepth(t->right)); treeDepth(t->right));}

159 Δυαδικά δένδρα(iv) Εισαγωγή σε ισοζυγισμένα δένδρα void treeBalancedInsert (tree * t, int d) { if (*t == NULL) { if (*t == NULL) { *t = (TreeNode *) malloc(sizeof(TreeNode)); *t = (TreeNode *) malloc(sizeof(TreeNode)); if (*t == NULL) { if (*t == NULL) { printf("Out of memory\n"); printf("Out of memory\n"); exit(1); exit(1); } (*t)->data = d; (*t)->data = d; (*t)->left = (*t)->right = NULL; (*t)->left = (*t)->right = NULL; }

160 Δυαδικά δένδρα(v) Εισαγωγή σε ισοζυγισμένα δένδρα (συνέχεια) else { else { int d1 = treeDepth((*t)->left); int d1 = treeDepth((*t)->left); int d2 = treeDepth((*t)->right); int d2 = treeDepth((*t)->right); if (d1 <= d2) if (d1 <= d2) treeBalancedInsert( &((*t)->left), d); treeBalancedInsert( &((*t)->left), d); else else treeBalancedInsert( &((*t)->right), d); treeBalancedInsert( &((*t)->right), d); }}

161 Δένδρα γενικής μορφής Κάθε κόμβος k έχει n k απογόνους, όπου n k  Ν Κωδικοποίηση με δυαδικά δένδρα

162 Σειρά με την οποία διασχίζονται οι κόμβοι –κατά βάθος (depth first) –κατά πλάτος (breadth first) Διάσχιση δυαδικών δένδρων(i) Κατά βάθος 42, 10, 7, 14, 12, 30, 50, 55, 52 Κατά πλάτος 42, 10, 50, 7, 14, 55, 12, 30, 52

163 Διάσχιση δυαδικών δένδρων(ii) Εκτύπωση κατά βάθος –πολύ απλά, με χρήση αναδρομής Υλοποίηση void treePrintDF (tree t) { if (t != NULL) { if (t != NULL) { printf("%d ", t->data); printf("%d ", t->data); treePrintDF(t->left); treePrintDF(t->left); treePrintDF(t->right); treePrintDF(t->right); }}

164 Διάσχιση δυαδικών δένδρων (iii) Εκτύπωση κατά πλάτος –με τη βοήθεια ουράς για την αποθήκευση δεικτών προς τους κόμβους που δεν έχουμε επισκεφθεί Υλοποίηση void treePrintBF (tree t) { queue q = queueEmpty; queue q = queueEmpty; if (t != NULL) if (t != NULL) queueInsert(&q, t); queueInsert(&q, t);

165 Διάσχιση δυαδικών δένδρων (iv) Εκτύπωση κατά πλάτος, υλοποίηση (συνέχεια) while (!queueIsEmpty(q)) { while (!queueIsEmpty(q)) { TreeNode * n = queueRemove(&q); TreeNode * n = queueRemove(&q); printf("%d ", n->data); printf("%d ", n->data); if (n->left != NULL) if (n->left != NULL) queueInsert(&q, n->left); queueInsert(&q, n->left); if (n->right != NULL) if (n->right != NULL) queueInsert(&q, n->right); queueInsert(&q, n->right); }}

166 Αριθμητικές εκφράσεις(i) Παράδειγμα 3 * (24 / 2) + (9 - 3) Παράσταση σε μορφή δυαδικού δένδρου –οι αριθμοί στα φύλλα –οι τελεστές στους υπόλοιπους κόμβους + *– / 9 Διάσχιση κατά βάθος

167 Αριθμητικές εκφράσεις(ii) Ενθεματική παράσταση –infix notation –ο τελεστής ανάμεσα στα τελούμενα –διφορούμενη: χρειάζονται παρενθέσεις –η συνήθης μορφή για τον άνθρωπο Αποτέλεσμα (3 * (24 / 2)) + (9 - 3) + *– / 9

168 Αριθμητικές εκφράσεις(iii) Προθεματική παράσταση –prefix notation –ο τελεστής πριν τα τελούμενα –όχι διφορούμενη, δε χρειάζονται παρενθέσεις –απλή μηχανική ανάγνωση Αποτέλεσμα + * 3 / *– / 9

169 Αριθμητικές εκφράσεις(iv) Επιθεματική παράσταση –postfix notation –ο τελεστής μετά τα τελούμενα –όχι διφορούμενη, δε χρειάζονται παρενθέσεις –απλή μηχανική αποτίμηση Αποτέλεσμα / * *– / 9

170 Υλοποίηση αριθμητικών εκφράσεων Έκφραση: δυαδικό δένδρο ειδικής μορφής Κόμβοι δύο ειδών: –αριθμητικές σταθερές (φύλλα) –τελεστές (με δύο τελούμενα) Πληροφορία: –τιμή σταθεράς, ή –σύμβολο τελεστή Σύνδεσμοι: –τελούμενα

171 Κόμβος δένδρου typedef struct ExprNode_tag { enum { EXP_const, EXP_binop } code; enum { EXP_const, EXP_binop } code; union { union { double constant; double constant; struct { struct { char op; char op; struct ExprNode_tag struct ExprNode_tag *arg1, *arg2; *arg1, *arg2; } binop; } binop; } data; } data; } ExprNode, *expr; code data constant ή binop op arg1 arg2

172 Κατασκευή σταθερών expr exprConst (double constant) { ExprNode * e = (ExprNode *) ExprNode * e = (ExprNode *) malloc(sizeof(ExprNode)); malloc(sizeof(ExprNode)); if (e == NULL) { if (e == NULL) { printf("Out of memory\n"); printf("Out of memory\n"); exit(1); exit(1); } e->code = EXP_const; e->code = EXP_const; e->data.constant = constant; e->data.constant = constant; return e; return e;} code data constant ή binop op arg1 arg2

173 Κατασκευή εκφράσεων με τελεστή expr exprBinop (expr arg1, char op, expr arg2) expr arg2){ ExprNode * e = (ExprNode *) ExprNode * e = (ExprNode *) malloc(sizeof(ExprNode)); malloc(sizeof(ExprNode)); if (e == NULL) { if (e == NULL) { printf("Out of memory\n"); printf("Out of memory\n"); exit(1); exit(1); } e->code = EXP_binop; e->code = EXP_binop; e->data.binop.op = op; e->data.binop.op = op; e->data.binop.arg1 = arg1; e->data.binop.arg1 = arg1; e->data.binop.arg2 = arg2; e->data.binop.arg2 = arg2; return e; return e;} code data constant ή binop op arg1 arg2

174 Παράδειγμα κατασκευής Έκφραση: 3 * (24 / 2) + (9 - 3) + *– / 9 expr e = exprBinop( exprBinop( exprConst(3),'*', exprConst(3),'*', exprBinop( exprBinop( exprConst(24), '/', exprConst(24), '/', exprConst(2) exprConst(2) ) ), '+', ), '+', exprBinop( exprBinop( exprConst(9), '-', exprConst(9), '-', exprConst(3) exprConst(3) ) ); );

175 Καταστροφή έκφρασης void exprFree (expr e) { switch (e->code) { switch (e->code) { case EXP_binop: case EXP_binop: exprFree(e->data.binop.arg1); exprFree(e->data.binop.arg1); exprFree(e->data.binop.arg2); exprFree(e->data.binop.arg2); break; break; } free(e); free(e);} code data constant ή binop op arg1 arg2

176 Εκτύπωση έκφρασης void exprPrint (expr e) { switch (e->code) { switch (e->code) { case EXP_const: case EXP_const: printf("%lg", e->data.constant); printf("%lg", e->data.constant); break; break; case EXP_binop: case EXP_binop: printf("("); printf("("); exprPrint(e->data.binop.arg1); exprPrint(e->data.binop.arg1); printf("%c", e->data.binop.op); printf("%c", e->data.binop.op); exprPrint(e->data.binop.arg2); exprPrint(e->data.binop.arg2); printf(")"); printf(")"); break; break; }} code data constant ή binop op arg1 arg2

177 Υπολογισμός έκφρασης double exprCalc (expr e) { switch (e->code) { switch (e->code) { case EXP_const: case EXP_const: return e->data.constant; return e->data.constant; case EXP_binop: case EXP_binop: switch (e->data.binop.op) { switch (e->data.binop.op) { case '+': case '+': return exprCalc(e->data. return exprCalc(e->data. binop.arg1) binop.arg1) + exprCalc(e->data. + exprCalc(e->data. binop.arg2); binop.arg2); case '-': case '-':......

178 Δυαδικά δένδρα αναζήτησης(i) Binary search trees Δυαδικά δένδρα με τις παρακάτω ιδιότητες για κάθε κόμβο: –όλοι οι κόμβοι του αριστερού παιδιού έχουν τιμές μικρότερες ή ίσες της τιμής του κόμβου –όλοι οι κόμβοι του δεξιού παιδιού έχουν τιμές μεγαλύτερες ή ίσες της τιμής του κόμβου

179 Δυαδικά δένδρα αναζήτησης(ii) Τα δυαδικά δένδρα αναζήτησης διευκολύνουν την αναζήτηση στοιχείων Αναδρομική αναζήτηση –αν η τιμή που ζητείται είναι στη ρίζα, βρέθηκε –αν είναι μικρότερη από την τιμή της ρίζας, αρκεί να αναζητηθεί στο αριστερό παιδί –αν είναι μεγαλύτερη από την τιμή της ρίζας, αρκεί να αναζητηθεί στο δεξί παιδί Κόστος αναζήτησης: O(log n) –υπό την προϋπόθεση το δένδρο να είναι ισοζυγισμένο

180 Δυαδικά δένδρα αναζήτησης (iii) Αναζήτηση TreeNode * treeSearch (tree t, int key) { if (t == NULL) if (t == NULL) return NULL; /* not found */ return NULL; /* not found */ if (t->data == key) if (t->data == key) return t; /* found */ return t; /* found */ if (t->data > key) if (t->data > key) return treeSearch(t->left, key); return treeSearch(t->left, key); else else return treeSearch(t->right, key); return treeSearch(t->right, key);}

181 Δείκτες σε συναρτήσεις Παράδειγμα 1 int f (int n); int (*p) (int n); p = &f; printf("%d", (*p)(3)); Παράδειγμα 2 double (*q) (double) = &sqrt; Δείκτες ισοδύναμοι με συναρτήσεις p = f; printf("%d", p(3));

182 Ολοκλήρωση double integral (double a, double b, double (*f) (double)) double (*f) (double)){ const double step = 1e-6; const double step = 1e-6; double result = 0.0; double result = 0.0; double x; double x; for (x=a; x<=b; x += step) for (x=a; x<=b; x += step) result += f(x) * step; result += f(x) * step; return result; return result;}... result = integral(0, , sin); κακός αλγόριθμος!

183 Ταξινόμηση φυσαλίδας(i) Τα δεδομένα: –void * a πού βρίσκονται –int n πόσα είναι –int size τί μέγεθος έχει καθένα –comparison f πώς γίνεται η σύγκριση Η σύγκριση των δεδομένων typedef int (*comparison) (void * x, void * y); void * y);

184 Ταξινόμηση φυσαλίδας(ii) void bsort (void * a, int n, comparison f, int size) comparison f, int size){ int i, j; int i, j; for (i = 0; i < n; i++) for (i = 0; i < n; i++) for (j = n-1; j > i; j--) { for (j = n-1; j > i; j--) { unsigned char * px = unsigned char * px = (unsigned char *) a + (unsigned char *) a + (j-1) * size; (j-1) * size; unsigned char * py = unsigned char * py = (unsigned char *) a + (unsigned char *) a + j * size; j * size;

185 Ταξινόμηση φυσαλίδας(iii) (συνέχεια) if (f(px, py) > 0) { if (f(px, py) > 0) { int k; int k; for (k = 0; k < size; k++) { for (k = 0; k < size; k++) { unsigned char temp = *px; unsigned char temp = *px; *px++ = *py; *px++ = *py; *py++ = temp; *py++ = temp; } } }}

186 Ταξινόμηση φυσαλίδας(iv) Συνάρτηση σύγκρισης για ακέραιους int intcompare (void * x, void * y) { return *((int *) x) - *((int *) y); return *((int *) x) - *((int *) y);} Κλήση για πίνακα ακεραίων int x[] = { 44, 55, 12, 42,... };... bsort(x, n, intcompare, sizeof(int));

187 Δέντρα δυαδικής αναζήτησης Δενδρικές δομές δεδομένων στις οποίες –Ολα τα στοιχεία στο αριστερό υποδέντρο της ρίζας είναι μικρότερα από την ρίζα –Ολα τα στοιχεία στο δεξί υποδέντρο της ρίζας είναι μεγαλύτερα ή ίσα με την ρίζα –Το αριστερό και το δεξί υποδέντρο είναι δέντρα δυαδικής αναζήτησης Binary Search Trees - BSTs

188 Δέντρα δυαδικής αναζήτησης Η γενική εικόνα ενός τέτοιου δέντρου >=

189 Παραδείγματα δέντρων BST Εγκυρα δέντρα

190 Παραδείγματα δέντρων BST Μη-έγκυρα δέντρα

191 Διάσχιση δυαδικών δέντρων –Preorder: –Postorder: –Inorder:

192 Ζύγισμα δέντρων BST Ανάλογα με τη σειρά άφιξης των στοιχείων και τον τρόπο δημιουργίας του δέντρου BST, για τα ίδια στοιχεία δεν προκύπτει πάντα το ίδιο δέντρο Το ύψος του δέντρου σχετίζεται με το χρόνο αναζήτησης ενός στοιχείου μέσα στο δέντρο

193 Ζύγισμα δέντρων BST Αναζήτηση με πολυπλοκότητα –Από Ο(Ν) [χειρότερη περίπτωση] –Μέχρι Ο(Log 2 N) [καλύτερη περίπτωση]

194 Ζύγισμα δέντρων BST Προκειμένου μια αναζήτηση να διατρέχει όσο το δυνατόν μικρότερο μέρος του δέντρου, αυτό πρέπει να είναι «ζυγισμένο» –«Ζυγισμένο»: το βάθος του αριστερού υποδέντρου δεν διαφέρει περισσότερο από 1 από αυτό του δεξιού (ιδανικά: είναι ίσα) Αν κατά την προσθήκη νέων στοιχείων στο δέντρο η ζυγαριά «γείρει» δεξιά ή αριστερά, απαιτείται διόρθωση του δέντρου

195 Παραδείγματα ζυγισμένων δέντρων

196 Ζυγισμένα δέντρα Η περίπτωση όπου το ύψος του αριστερού υποδέντρου είναι ακριβώς ίσο με το ύψος του δεξιού, δεν επιτυγχάνεται εύκολα Αν από την παραπάνω περίπτωση υπήρχαν «μικρές» αποκλίσεις, οι επιδόσεις του δέντρου στην αναζήτηση δεν θα επηρεάζονταν ιδιαίτερα

197 Δέντρα AVL Ενα δέντρο AVL (Adelson-Velskii and Landis) είναι ένα δέντρο BST του οποίου το ύψος του αριστερού υποδέντρου διαφέρει από αυτό του δεξιού το πολύ κατά 1 Το δεξί και αριστερό υποδέντρο ενός δέντρου AVL είναι επίσης δέντρα AVL Το κενό δέντρο είναι δέντρο AVL Οι ιδιότητες αυτές διατηρούνται με παρεμβάσεις (αναδιάταξη) καθώς νέα στοιχεία προστίθενται στο δέντρο

198 Δέντρα AVL

199 Ενα δέντρο AVL λέγεται «ψηλό από αριστερά» όταν το ύψος του αριστερού υποδέντρου είναι μεγαλύτερο από αυτό του δεξιού (κατά πόσο;;;) Αντίστοιχα για το «ψηλό από δεξιά» Υπάρχουν αρκετοί τρόποι με τους οποίους η προσθήκη ή η διαγραφή στοιχείων σε ένα δέντρο AVL παραβιάζει τη συνθήκη χαρακτηρισμού του

200 Αναδιάταξη δέντρων AVL Η χαρακτηριστική ιδιότητα ενός δέντρου AVL μπορεί να παύει να ισχύει με την προσθήκη νέων στοιχείων Η επαναφορά της ιδιότητας σε ισχύ, γίνεται με περιστροφή του δέντρου, ανάλογα με την περίπτωση αναδιάταξης που συντρέχει

201 Απλή περιστροφή X Y Z k2 k1 h X YZ k2 k1 New item New Item

202 Διπλή περιστροφή (α) k3 h D k2 k1 C B A k2 k1k3 C D BA

203 Διπλή περιστροφή (β) k3 k2 k1 C B A D k3 k1 k2 C BA D

204 Διπλή περιστροφή (γ) k3 k1 k2 C BA D k1 k3 C BA D

205 Αναδιάταξη δέντρων AVL Περιπτώσεις αναδιάταξης –ΑΑ: ένα αριστερό υποδέντρο ενός δέντρου AVL που είναι ψηλό από αριστερά, γίνεται επίσης ψηλό από αριστερά (left of left) –ΔΔ: τα αντίστοιχα για το δεξί υποδέντρο (right of right) –ΔΑ: ένα υποδέντρο ενός δέντρου AVL ψηλού από αριστερά, γίνεται ψηλό από δεξιά (right of left) –ΑΔ: ένα υποδέντρο ενός δέντρου AVL ψηλού από δεξιά, γίνεται ψηλό από αριστερά (left of right)

206 Περιπτώσεις αναδιάταξης (α)

207 Περιπτώσεις αναδιάταξης (β)

208 Αναδιάταξη σε περίπτωση ΑΑ

209 Αναδιάταξη σε περίπτωση ΔΔ

210 Αναδιάταξη σε περίπτωση ΔΑ

211 Αναδιάταξη σε περίπτωση ΑΔ

212 Υλοποίηση δέντρων AVL στη C Μια δομή δεδομένων Node key key data data left left right right bal bal End Node

213 Εισαγωγή σε δέντρα AVL H εισαγωγή νέων στοιχείων γίνεται στα φύλλα, όπως στα δέντρα BST Εντοπίζεται το φύλλο στο οποίο θα γίνει η εισαγωγή και δημιουργείται νέος κόμβος Γίνεται οπισθοδρόμηση μέχρι την κορυφή του δέντρου, με έλεγχο της ισχύος της συνθήκης ισορροπίας AVL σε κάθε βήμα προς τα πίσω, και επαναφορά σε ισορροπία, όπου απαιτείται

214 Εισαγωγή σε δέντρα AVL Διάγραμμα κλήσης μιας αναδρομικής συνάρτησης εισαγωγής

215 ΑΛΓΟΡΙΘΜΟΣ AVLInsert( ref root, val newPtr, ref taller ) 1 if (root null) 1 root = newPtr 1 root = newPtr 2 taller = true 2 taller = true 3 return root 3 return root 2 end if 3 if (newPtr->key key) 1 root->left = AVLInsert (root->left, newPtr, taller) 1 root->left = AVLInsert (root->left, newPtr, taller) 2 if (taller) // Left subtree is taller 2 if (taller) // Left subtree is taller 1 if (root left-high) 1 if (root left-high) 1 root = leftBalance (root, taller) 1 root = leftBalance (root, taller) 2 elseif (root even-high) 2 elseif (root even-high) 1 root->bal = left-high 1 root->bal = left-high 3 else //Was right high -- now even high 3 else //Was right high -- now even high 1 root->bal = even-high 1 root->bal = even-high 2 taller = false 2 taller = false 4 end if 4 end if 4 else// New data >= root data

216 (Συνέχεια) AVLInsert( ref root, val newPtr, ref taller )... 4 else// New data >= root data 1 root-> right = AVLInsert (root->right, newPtr, taller) 1 root-> right = AVLInsert (root->right, newPtr, taller) 2 if (taller)// Right subtree is taller 2 if (taller)// Right subtree is taller 1 if (root left-high) 1 if (root left-high) 1 root->bal = even-high 1 root->bal = even-high 2 taller = false 2 taller = false 2 elseif (root even-high)// Was balanced -- now right high 2 elseif (root even-high)// Was balanced -- now right high 1 root->bal = right-high 1 root->bal = right-high 3 else 3 else 1 root = rightBalance (root, taller) 1 root = rightBalance (root, taller) 4 end if 4 end if 3 end if 3 end if 5 end if 6 return root end AVLInsert

217 ΑΛΓΟΡΙΘΜΟΣ leftBalance (ref root, ref taller ) 1 leftTree = root-> left 2 if (leftTree left-high) // Case 1: Left of left. Single rotation right. 1 rotateRight (root) 1 rotateRight (root) 2 root->bal = even-high 2 root->bal = even-high 3 leftTree->bal = even-high 3 leftTree->bal = even-high 4 taller = false 4 taller = false 3 else // Case 2: Right of left. Double rotation required. 1 rightTree = leftTree->right 1 rightTree = leftTree->right // adjust balance factors 2 if (rightTree->bal left-high) 2 if (rightTree->bal left-high) 1 root->bal = right-high 1 root->bal = right-high 2 leftTree->bal = even-high 2 leftTree->bal = even-high 3 elseif (rightTree->bal = even-high) 3 elseif (rightTree->bal = even-high) 1 leftTree->bal = even-high 1 leftTree->bal = even-high 4 else 4 else

218 (Συνέχεια) leftBalance (ref root, ref taller ) 4 else 4 else // rightTree->bal is right-high // rightTree->bal is right-high 1 root->bal = even-high 1 root->bal = even-high 2 leftTree->bal = left-high 2 leftTree->bal = left-high 5 end if 5 end if 6 rightTree->bal = even-high 6 rightTree->bal = even-high 7 root->left = rotateLeft (leftTree) 7 root->left = rotateLeft (leftTree) 8 root = rotateRight (root) 8 root = rotateRight (root) 9 taller = false 9 taller = false 4 end if 5 return root end leftBalance

219 Περισσότερα για δέντρα AVL Διαγραφή στοιχείου –Διαβάστε αντίστοιχο download από τη σελίδα του μαθήματος Βιβλιοθήκη συναρτήσεων –Μπορείτε να κατεβάσετε ένα σύνολο έτοιμων συναρτήσεων C για το χειρισμό δέντρων AVL από τη σελίδα web του μαθήματος

220 Γράφοι(i) Ορολογία –γράφος ή γράφημα (graph) Ορισμός: G = (V, E) όπου –V:ένα σύνολο –E:μια διμελής σχέση στο V Ορολογία (συνέχεια) –κάθε v  V ονομάζεται κορυφή (vertex) ή κόμβος (node) –κάθε (v 1, v 2 )  Ε ονομάζεται ακμή (edge) ή τόξο (arrow) V = {v 1, v 2, v 3, v 4, v 5, v 6, v 7 } E = {(v 1, v 2 ),(v 1, v 3 ), (v 2, v 4 ),(v 3, v 4 ), (v 5, v 2 ),(v 5, v 3 ), (v 1, v 5 ),(v 6, v 7 ), (v 7, v 6 ), (v 7, v 7 ) } v4v4 v3v3 v5v5 v2v2 v1v1 v6v6 v7v7

221 Γράφοι(ii) Είδη γράφων –Κατευθυνόμενος (directed) γράφος, αν (v 1, v 2 )  Ε είναι διατεταγμένο ζεύγος –Μη κατευθυνόμενος (undirected) γράφος, αν (v 1, v 2 ) και (v 2, v 1 ) ταυτόσημα Ορισμοί –Δύο κορυφές v 1 και v 2 ονομάζονται γειτονικές (adjacent) αν (v 1, v 2 )  Ε μη κατευθυνόμενος w1w1 w2w2 w4w4 w3w3 κατευθυνόμενος v4v4 v3v3 v5v5 v2v2 v1v1 v6v6 v7v7

222 Γράφοι(iii) Ορισμοί (συνέχεια) –Βαθμός (degree) μιας κορυφής v  V είναι ο αριθμός των γειτονικών κορυφών της deg(w 1 )=2, deg(w 2 )=1 –Για κατευθυνόμενους γράφους: μέσα-βαθμός (in- degree) και έξω-βαθμός (out- degree) indeg(v 1 )=0, outdeg(v 1 )=3, indeg(v 2 )=2, outdeg(v 2 )=1 μη κατευθυνόμενος w1w1 w2w2 w4w4 w3w3 κατευθυνόμενος v4v4 v3v3 v5v5 v2v2 v1v1 v6v6 v7v7

223 Γράφοι(iv) Ορισμοί (συνέχεια) –Μονοπάτι (path) είναι μια ακολουθία κορυφών v 1, v 2,... v n  V τέτοια ώστε (v i, v i+1 )  Ε,  i –Μήκος μονοπατιού –Κύκλος (cycle) είναι ένα μονοπάτι με v 1 = v n –Ακυκλικός (acyclic) γράφος: δεν περιέχει κύκλους d c e b a f g Μονοπάτι: a, b, c, e, g d c e b a f g Κύκλος: b, c, e, d, b μήκος=4

224 Γράφοι(v) Ορισμοί (συνέχεια) –Υπογράφος (subgraph) του G = (V, E) είναι ένας γράφος G´ = (V´, E´) τέτοιος ώστε V´  V και E´  E G d c e b a f g G 2 υπογράφος του G d c e bf g G 1 υπογράφος του G d c e b a f

225 Γράφοι(vi) Ορισμοί (συνέχεια) –Συνδεδεμένος (connected) ή συνεκτικός γράφος: για κάθε ζεύγος κορυφών v 1, v 2  V υπάρχει μονοπάτι από την v 1 στη v 2 –Συνδεδεμένα συστατικά (connected components): συνδεδεμένοι υπογράφοι που περιέχουν όλες τις κορυφές και τις ακμές συνδεδεμένος d c e b a f g μη συνδεδεμένος d c e b a f g

226 Γράφοι(vii) Ορισμοί (συνέχεια) –Ισχυρά συνδεδεμένος (strongly connected) κατευθυνόμενος γράφος: όπως προηγουμένως –Ασθενώς συνδεδεμένος (weakly connected) κατευθυνόμενος γράφος: συνδεδεμένος, αν αγνοήσουμε τις κατευθύνσεις των ακμών ασθενώς συνδεδεμένος d c e b a f g ισχυρά συνδεδεμένος d c e b a f g ?

227 Γράφοι ως ΑΤΔ Υποθέτουμε ότι προϋπάρχει: –Τύπος κορυφής: vertex Πράξεις –ΑΤΔ: graph –void empty (graph *g, int n); –int isAdjacent (graph g, vertex v1, vertex v2); –void join (graph *g, vertex v1, vertex v2); –void remove (graph *g, vertex v1, vertex v2);

228 Αναπαράσταση γράφων με ΣΤΔ Δύο από τους κυριότερους τρόπους αναπαράστασης –Πίνακας γειτονικών κορυφών (adjacency matrix) –Λίστα γειτονικών κορυφών (adjacency list) Άλλοι τρόποι αναπαράστασης –Λίστα ακμών (edge list)

229 Πίνακας γειτονικών κορυφών(i) Τρόπος αναπαράστασης –Έστω ο γράφος G = (V, E) και n = |V| –Ο γράφος G αναπαρίσταται με έναν πίνακα a διαστάσεων n  n τα στοιχεία του οποίου είναι TRUE ή FALSE –a[i, j] = TRUE αν και μόνο αν (v i, v j )  E v0v0 v1v1 v3v3 v2v2 v0v0 v1v1 v3v3 v2v

230 Πίνακας γειτονικών κορυφών(ii) Μέγιστο πλήθος κορυφών #define MAX 10 Τύπος κορυφής typedef unsigned vertex; Τύπος για τις λογικές τιμές typedef enum { FALSE=0, TRUE=1 } bool; Ορισμός τύπου graph typedef bool graph[MAX][MAX];

231 Πίνακας γειτονικών κορυφών (iii) Κενός γράφος void empty (graph *g, int n) { vertex v1, v2; vertex v1, v2; for (v1=0; v1

232 Πίνακας γειτονικών κορυφών (iv) Προσθήκη ακμής void join (graph *g, vertex v1, vertex v2) vertex v2){ (*g)[v1][v2] = TRUE; (*g)[v1][v2] = TRUE;} Αφαίρεση ακμής void remove (graph *g, vertex v1, vertex v2) vertex v2){ (*g)[v1][v2] = FALSE; (*g)[v1][v2] = FALSE;}

233 Λίστα γειτονικών κορυφών(i) Τρόπος αναπαράστασης –Έστω ο γράφος G = (V, E) και n = |V| –Ο γράφος G αναπαρίσταται με έναν πίνακα a διάστασης n τα στοιχεία του οποίου είναι γραμμικές λίστες που περιέχουν κορυφές –η λίστα a[i] περιέχει την κορυφή j αν και μόνο αν (v i, v j )  E v0v0 v1v1 v3v3 v2v2 a[0] a[1] a[2] a[3] 2223

234 Λίστα γειτονικών κορυφών(ii) Τύπος κορυφής typedef unsigned vertex; Ορισμός τύπου graph typedef struct node_tag { vertex v; vertex v; struct node_tag * next; struct node_tag * next; } node, * graph[];

235 Λίστα γειτονικών κορυφών (iii) Κενός γράφος void empty (graph *g, int n) { vertex v; vertex v; *g = malloc(n * sizeof(node *)); *g = malloc(n * sizeof(node *)); if (*g == NULL) { if (*g == NULL) { fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Out of memory\n"); exit(1); exit(1); } for (v=0; v

236 Λίστα γειτονικών κορυφών (iv) Έλεγχος ύπαρξης ακμής bool isAdjacent (graph g, vertex v1, vertex v2) vertex v2){ node * n; node * n; for (n=g[v1]; n != NULL; n=n->next) for (n=g[v1]; n != NULL; n=n->next) if (n->v == v2) if (n->v == v2) return TRUE; return TRUE; return FALSE; return FALSE;}

237 Λίστα γειτονικών κορυφών(v) Προσθήκη ακμής void join (graph *g, vertex v1, vertex v2) vertex v2){ node * new = malloc(sizeof(node)); node * new = malloc(sizeof(node)); if (new == NULL) { if (new == NULL) { fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Out of memory\n"); exit(1); exit(1); } new->v = v2; new->v = v2; new->next = (*g)[v1]; new->next = (*g)[v1]; (*g)[v1] = new; (*g)[v1] = new;}

238 Λίστα γειτονικών κορυφών (vi) Αφαίρεση ακμής void remove (graph *g, vertex v1, vertex v2) vertex v2){ node ** temp = &((*g)[v1]); node ** temp = &((*g)[v1]); while (*temp != NULL) while (*temp != NULL) if ((*temp)->v == v2) { if ((*temp)->v == v2) { node * del = *temp; node * del = *temp; *temp = (*temp)->next; *temp = (*temp)->next; free(del); free(del); } else else temp = &((*temp)->next); temp = &((*temp)->next);}

239 Διάσχιση γράφων(i) Κατά βάθος –ξεκινώντας από την κορυφή 0: –0, 1, 2, 6, 3, 4, 5, 7 Κατά πλάτος –ξεκινώντας από την κορυφή 0: –0, 1, 4, 2, 3, 5, 7,

240 Διάσχιση γράφων(ii) Υλοποίηση διάσχισης κατά βάθος σε παράσταση λίστας γειτονικών κορυφών void traverseDFS (graph g) { bool visited[N]; bool visited[N]; vertex v; vertex v; for (v=0; v

241 Διάσχιση γράφων(iii) void traverseDFS_aux (graph g, bool visited[N], bool visited[N], vertex current) vertex current){ node * adj; node * adj; printf("Vertex %d\n", current); printf("Vertex %d\n", current); visited[current] = true; visited[current] = true; for (adj = g[current]; for (adj = g[current]; adj != NULL; adj != NULL; adj = adj->next) adj = adj->next) if (!visited[adj->vertex]) if (!visited[adj->vertex]) traverseDFS_aux(g, visited, traverseDFS_aux(g, visited, adj->vertex); adj->vertex);}

242 Διάσχιση γράφων(iv) Υλοποίηση διάσχισης κατά πλάτος σε παράσταση λίστας γειτονικών κορυφών void traverseBFS (graph g) { node * adj; node * adj; bool visited[N]; bool visited[N]; queue q; queue q; vertex v; vertex v; for (v=0; v

243 Διάσχιση γράφων(v) while (!queueIsEmpty(q)) { while (!queueIsEmpty(q)) { vertex current = queueRemove(&q); vertex current = queueRemove(&q); printf("Vertex %d\n", current); printf("Vertex %d\n", current); visited[current] = true; visited[current] = true; for (adj = g[current]; for (adj = g[current]; adj != NULL; adj != NULL; adj = adj->next) adj = adj->next) if (!visited[adj->vertex]) if (!visited[adj->vertex]) queueInsert(&q, adj->vertex); queueInsert(&q, adj->vertex); }}


Κατέβασμα ppt "ΗΜΜΥ 111 ΔΟΜΗΜΕΝΟΣΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΚΩΣΤΑΣ ΚΟΝΤΟΓΙΑΝΝΗΣ Αναπληρωτής Καθηγητής Τμήμα ΗΜΜΥ Πολυτεχνείο Κρήτης."

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google