Professional Documents
Culture Documents
Σχολή Μηχανικών
Τμήμα Ηλεκτρονικών Μηχανικών
ΠΜΣ: Ηλεκτρονικά Συστήματα Τηλεπικοινωνιών & Αυτοματισμών
Τεχνικές Προγραμματισμού
και Αλγόριθμοι
(ΠΜΣ 03 )
Δρ. Μηχ. Νικόλαος Πετράκης,
Λέκτορας
nik.s.petrakis@hmu.gr
Διάλεξη 3ης εβδομάδας.
Ιστοσελίδα Μαθήματος:
https://eclass.chania.teicrete.gr/courses/EL342/
va_start
Μια μακροεντολή που αρχικοποιεί το αντικείμενο
που δηλώθηκε με την va_list
va_arg
Μια μακροεντολή που επεκτείνεται σε μια έκφραση
της τιμής και του τύπου του επόμενου ορίσματος
Μια μακροεντολή που διευκολύνει την κανονική
va_end επιστροφή από μια συνάρτηση που προσπελάστηκε
με την va_start
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 12
Παράδειγμα: Υπολογισμός μέσης τιμής με …
#include <stdio.h>
#include <stdlib.h>
#include <greek.h>
#include <stdarg.h> // Variable Argument Header
double average (int, ...); // ... ellipsis
int main(int argc, char *argv[])
{ double x=3.5, y=5.3, z= 13.7, v=17.548;
SetGreek();
printf("%s%8.3f\n%s%8.3f\n%s%8.3f\n%s%8.3f\n\n",
"x =",x,"y =",y,"z =",z,"v =",v);
printf("%s%8.3f\n%s%8.3f\n%s%8.3f\n%s%8.3f\n\n",
"(x)/1 =", average (1,x),
"(x+y)/2 =", average (2,x,y),
"(x+y+z)/3 =", average (3,x,y,z),
"(x+y+z+v)/4 =", average (4,x,y,z,v));
system("PAUSE");
return 0;
} 08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 13
… με απροσδιόριστο πλήθος ορισμάτων.
double average (int n, ...)
{ double total=0.0;
int i;
va_list ap;
va_start(ap,n);
for (i=1; i<=n; i++)
total = total + va_arg(ap, double);
va_end(ap); x = 3.500
return total/n; y = 5.300
} z = 13.700
v = 17.548
(x)/1 = 3.500
(x+y)/2 = 4.400
(x+y+z)/3 = 7.500
(x+y+z+v)/4 = 10.012
Press any key to continue . . .
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 14
Δομές Δεδομένων
Η στοίβα (stack)
Στοίβα είναι μια αριθμημένη
συλλογή από θέματα (αντικείμενα, E top
στοίβας. STACK
Όπως η απόσυρση έτσι και η stacktop δεν ορίζεται για μια κενή
στοίβα. Το αποτέλεσμα μιας παράνομης προσπάθειας για
απόσυρση ή ανάγνωση στοιχείου από κενή στοίβα ονομάζεται
underflow (υποχείλιση ή ανεπάρκεια) η οποία όμως μπορεί να
αποφευχθεί ελέγχοντας με την εντολή empty(s).
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 17
Υλοποίηση στοίβας
Υπάρχουν πολλοί τρόποι αναπαράστασης ή υλοποίησης μιας
στοίβας.
• Ο ευκολότερος είναι με την βοήθεια ενός πίνακα.
• Παρότι ένας πίνακας δεν μπορεί να γίνει στοίβα μπορεί να
φιλοξενήσει μια στοίβα.
• Ο πίνακας πρέπει να δηλωθεί αρκετά μεγάλος ώστε να
υπερκαλύπτει το μέγιστο αναμενόμενο μέγεθος της στοίβας.
• Στην διάρκεια της εκτέλεσης του προγράμματος η στοίβα
μπορεί να αυξάνει ή να συρρικνώνεται στον χώρο που της
έχει αφιερωθεί. Το ένα άκρο του πίνακα είναι η σταθερή
βάση της στοίβας (πυθμένας) ενώ η κορυφή μετακινείται
συνεχώς καθώς στοιχεία ωθούνται ή αποσύρονται.
• Είναι προφανής η ανάγκη ύπαρξης ενός άλλου πεδίου το
οποίο θα διατηρεί την τρέχουσα θέση της κορυφής της
στοίβας.
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 18
Υλοποίηση στοίβας (2)
Σύμφωνα με τα παραπάνω λοιπόν μια στοίβα μπορεί να δηλωθεί
σαν μια δομή με δυο μέλη: έναν πίνακα για να διατηρεί τα
στοιχεία της στοίβας και έναν ακέραιο για να δεικνύει την
τρέχουσα θέση της κορυφής της στοίβας μέσα στον πίνακα. Για
μια στοίβα ακεραίων θα είχαμε τις εξής δηλώσεις:
#define STACKSIZE 100
struct stack {
int top;
int items[STACKSIZE];
};
struct stack s;
Φυσικά δεν υπάρχει λόγος να περιοριστεί μια στοίβα στο να
περιέχει μόνο ακέραιους αριθμούς. Θα μπορούσε το ίδιο εύκολα
να είχε δηλωθεί για στοιχεία τύπου πραγματικού (float) ή
χαρακτήρα (char) ή ό,τι άλλο τύπο επιθυμούμε να δώσουμε στα
στοιχεία της στοίβας. Για παράδειγμα:
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 19
Υλοποίηση στοίβας (3)
#define STACKSIZE 100
#define INTGR 1 Αρκετές φορές εμφανίζεται η ανάγκη μια
#define FLT 2 στοίβα να περιέχει αντικείμενα διαφορετικού
#define STRING 3 τύπου χρησιμοποιώντας ενώσεις (unions).
struct stackelement {
struct stack s; Οπότε, για την
int etype;
union { εμφάνιση του
struct stackelement se; κορυφαίου στοιχείου
int ival;
float fval; της στοίβας θα
se =s.items[s.top]; είχαμε:
char sval[10];
switch (se.etype) {
} element;
case INTGR :printf("%d\n",se.ival); break;
};
case FLT :printf("%f\n",se.fval); break;
case STRING:printf("%s\n",se.sval); break;
struct stack{
}
int top;
struct stackelement items[STACKSIZE];
}; Στην συνέχεια, για λόγους απλότητας, θα θεωρήσουμε ότι η
στοίβα μας μπορεί να αποθηκεύσει στοιχεία ενός μόνο τύπου,
έτσι ώστε να μην είναι απαραίτητη η ένωση (union).
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 20
Υλοποίηση στοίβας (4)
Υλοποίηση της πράξης ελέγχου για κενή λίστα (empty):
int empty(struct stack *ps ) struct stack s;
{ if (ps -> top == -1)
return(TRUE); if (empty(&s))
else /* empty stack */
return(FALSE); else
} /* not empty stack */
Υλοποίηση της πράξης απόσυρσης ή εξώθησης (pop) στοιχείου:
int pop(struct stack *ps )
{ if (empty(ps))
{ ptintf("stack underflow"); exit(1); }
return (ps->items[ps->top--]);
}
Υλοποίηση της πράξης ώθησης (push) στοιχείου:
void push(struct stack *ps, int x)
{ ps->top +=1; // ή πιο περιεκτικά
ps->items[ps->top]=x; // ps->items[++(ps->top)]=x;
return ;
} 08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 21
Υλοποίηση στοίβας (5)
Επειδή, στην πράξη η στοίβα είναι πεπερασμένη πρέπει να
συμπληρώσουμε την προηγούμενη συνάρτηση με μια εντολή
ελέγχου για την παγίδευση της περίπτωσης της υπερχείλισης
(overflow), ως εξής:
void push(struct stack *ps, int x)
{ if (ps -> top ==STACKSIZE-1)
{ printf("stack overflow"); exit(1); }
else
ps->items[++(ps->top)]=x;
return ;
}
Η τελευταία λειτουργία είναι η stacktop(s) η οποία εμφανίζει το
κορυφαίο στοιχείο της στοίβας χωρίς την εξαγωγή του:
int stacktop (struct stack *ps)
{ if (empty(ps))
{ printf("stack underflow"); exit(1); }
else
return (ps->items[ps->top]);
}08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 22
Παράδειγμα – Εφαρμογή (1)
Τώρα που έχουμε ορίσει μια στοίβα και τις πράξεις που μπορούν
να πραγματοποιηθούν σ’ αυτή έφτασε η στιγμή να δείξουμε πως
μπορούμε να χρησιμοποιήσουμε τη στοίβα στην επίλυση
προβλημάτων. Ένα από τα κλασικά παραδείγματα είναι η
εξακρίβωση του αν είναι σωστά φωλιασμένες οι παρενθέσεις σε
μια μαθηματική έκφραση με κάμποσα ζεύγη από φωλιασμένες
παρενθέσεις, όπως η παρακάτω:
5 + (( a * (( b - c ) / ( 3 + a )) – d ) / ( c – 3.14 + a ))
Για να γίνει αυτό πρέπει να ελεγχθεί ότι υπάρχει ίσος αριθμός
δεξιών και αριστερών παρενθέσεων και ότι πριν από κάθε δεξιά
παρένθεση έχει προηγηθεί μια αριστερή, δηλαδή το ζευγάρι της.
Το πρόβλημα θα μπορούσε να λυθεί με την χρήση ενός απλού
μετρητή (αρχικοποιημένου στο 0) ο οποίος θα αυξανόταν όποτε
συναντούσαμε αριστερή παρένθεση και θα μειωνόταν όποτε
συναντούσαμε δεξιά παρένθεση.
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 23
Παράδειγμα – Εφαρμογή (2)
Μια μαθηματική έκφραση είναι έγκυρη από πλευράς
παρενθέσεων όταν μετά τον έλεγχο ο μετρητής έχει τιμή μηδέν,
ενώ κατά την διάρκεια του ελέγχου δεν έλαβε ποτέ αρνητική
τιμή.
Αν αλλάξουμε όμως λίγο το πρόβλημα υποθέτοντας ότι
υπάρχουν τρία διαφορετικά είδη διαχωριστικών παρενθέσεων
(π.χ. παρενθέσεις ( ) , αγκύλες [ ] και άγκιστρα { } ) θα πρέπει όχι
μόνο να παρακολουθούμε πόσες έχουν ανοίξει αλλά και το είδος
τους. Σ’ αυτήν τη περίπτωση η χρήση της στοίβας θα ήταν
περισσότερο αναγκαία.
Άσκηση 2 (για το σπίτι): Να γίνει πρόγραμμα που να δέχεται
μαθηματικές εκφράσεις από το πληκτρολόγιο με παρενθέσεις ( ),
αγκύλες [ ] και άγκιστρα { } και να επιστρέφει το κατάλληλο
μήνυμα ανάλογα με το αν είναι έγκυρες ή όχι. Η εισαγωγή της
έκφρασης θα τερματίζεται με CTRL + Z.
08/04/2020 "Τεχνικές Προγραμματισμού και Αλγόριθμοι", Ν. Πετράκης, ΕΛ.ΜΕ.ΠΑ. 24