ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΕΙΡΑΙΩΣ ΣΧΟΛΗ ΤΕΧΝΟΛΟΓΙΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΕΠΙΚΟΙΝΩΝΙΩΝ ΤΜΗΜΑ ΨΗΦΙΑΚΩΝ ΣΥΣΤΗΜΑΤΩΝ «ΔΟΜΕΣ ΔΕΔΟΜΕΝΩΝ» ΗΜΕΡ.ΑΝΑΘΕΣΗΣ: Δευτέρα 21 Δεκεμβρίου 2015 ΗΜΕΡ.ΠΑΡΑΔΟΣΗΣ: Δευτέρα 25 Ιανουαρίου 2016 Διδάσκοντες: Χ.Δουλκερίδης, Ο.Τελέλης ΕΡΓΑΣΙΑ 2 η : Υλοποίηση αλγόριθμου εύρεσης κορυφαίων-κ (tp-k) στοιχείων σε λίστες και πειραματική αξιολόγηση. 1) ΠΕΡΙΓΡΑΦΗ Δίνονται δύο λίστες L1 και L2 που περιέχουν στοιχεία που αποτελούνται από ένα ζεύγος τιμών (Id, Scre): ένα μοναδικό κλειδί (Id) και κάποιο αριθμητικό σκορ (Scre). Σε οποιαδήποτε λίστα δεν μπορεί να υπάρχουν δύο στοιχεία με το ίδιο κλειδί. Επιπλέον, η κάθε λίστα είναι ταξινομημένη σε φθίνουσα διάταξη ως προς το αριθμητικό σκορ. Δίνεται ένα παράδειγμα στο ακόλουθο σχήμα (τονίζεται ότι γενικά δεν είναι απαραίτητο οι δύο λίστες να περιέχουν ακριβώς τα ίδια κλειδιά, και φυσικά τα σκορ μπορούν να παίρνουν οποιαδήποτε τιμή, στο παράδειγμα τυχαίνει να είναι ίσα σε κάθε γραμμή). Λίστα 1 Λίστα 2 Id Scre1 Id Scre2 5 50 3 50 1 40 2 40 3 30 1 30 2 20 4 20 4 10 5 10 Το πρόβλημα που ζητείται να λυθεί είναι το εξής: δεδομένης ακέραιας τιμής K και της αθροιστικής συνάρτησης Scre1+Scre2, που εφαρμόζεται στα δύο σκορ, να βρεθούν τα tp- Κ κλειδιά, που ορίζονται ως εκείνα με τις Κ μεγαλύτερες τιμές αθροίσματος Scre1+Scre2. Υποθέτουμε ότι επιτρέπεται μόνο σειριακή πρόσβαση σε κάθε λίστα, δεν είναι δυνατό δηλαδή να έχουμε πρόσβαση στο 4 ο στοιχείο χωρίς να έχουμε διαβάσει τα τρία προηγούμενα στοιχεία. Στο παραπάνω παράδειγμα, για Κ=1 η λύση του προβλήματος είναι το στοιχείο με κλειδί Id=3 που επιτυγχάνει σκορ Scre1+Scre2=30+50=80, διότι δεν υπάρχει άλλο κλειδί με μεγαλύτερο αθροιστικό σκορ. Το πρόβλημα λύνεται με απλούστατο τρόπο, εάν διατρέξουμε τις δύο λίστες πλήρως, δημιουργήσουμε όλους τους συνδυασμούς στοιχείων με ίδιο κλειδί, υπολογίσουμε τις αθροιστικές τιμές που παίρνουν, και κρατήσουμε τα Κ στοιχεία με μεγαλύτερες αθροιστικές τιμές. Υπάρχει όμως αλγόριθμος που είναι δυνατό να διατρέξει μόνο ένα πρόθεμα 1 (prefix) της κάθε λίστας, και να τερματίσει τη λειτουργία του έχοντας παράξει τη σωστή λύση του προβλήματος, χωρίς να διαβάσει εξαντλητικά τις δύο λίστες. Μας ενδιαφέρει να υλοποιήσουμε έναν τέτοιο αλγόριθμο που παράγει το ορθό αποτέλεσμα και τερματίζει όσο το 1 Για τη Λίστα 1 στο παράδειγμα, δυνατά προθέματα (prefixes) αποτελούν τα: {5}, {5,1}, {5,1,3}, {5,1,3,2}, {5,1,3,2,4}. 1
δυνατόν νωρίτερα, δηλαδή έχοντας διαβάσει συνολικά όσο το δυνατόν λιγότερα στοιχεία από τις δύο λίστες. Παρουσιάζεται και ο τρόπος λειτουργίας (βλέπε Σχήμα 1) του αλγόριθμου στο δοθέν παράδειγμα. Στο πρώτο βήμα, διαβάζονται τα στοιχεία με κλειδί 5 (5,50) από την L1 και κλειδί 3 (3,50) από την L2. Καθώς αυτά δεν έχουν κοινό κλειδί, και δεν υπάρχουν άλλα στοιχεία που να έχουν διαβαστεί, τοποθετούνται στο Buffer. Το εύρος δυνατών τιμών για το άθροισμα των σκορ του κλειδού 5 είναι μεταξύ min=50 (διότι μπορεί να μη βρεθεί ποτέ στη λίστα L2) και max=100 (διότι μπορεί να βρεθεί στην αμέσως επόμενη θέση στη λίστα L2). Το ίδιο εύρος ισχύει για το κλειδί 3. Οπότε εισάγονται στον Buffer οι εγγραφές: 5:(50-100) και 3:(50-100). Επίσης, το στοιχείο με κλειδί 5 τοποθετείται στη μνήμη Μ1, ενώ το στοιχείο με κλειδί 3 τοποθετείται στη μνήμη Μ2. Ο έλεγχος τερματισμού ελέγχει εάν υπάρχουν Κ (στο παράδειγμα Κ=1) εγγραφές στον Buffer B των οποίων το ελάχιστο άθροισμα σκορ είναι εγγραφών του Buffer B. Ο έλεγχος αποτυγχάνει και ο αλγόριθμος συνεχίζει. Στο δεύτερο βήμα, διαβάζονται τα στοιχεία με κλειδί 1 (1,40) από την L1 και κλειδί 2 (2,40) από την L2. Αυτά δεν έχουν κοινό κλειδί μεταξύ τους. Επίσης, το (1,40) δεν έχει κοινό κλειδί με στοιχείο στη μνήμη Μ2 και το (2,40) δεν έχει κοινό κλειδί με στοιχείο στη μνήμη Μ1. Συνεπώς, εισάγονται στον Buffer οι εγγραφές εύρους τιμών 1:(40-80) και 2:(40-80). Όμως, ενημερώνονται οι δυνατές τιμές αθροίσματος σκορ και των υπόλοιπων κλειδιών σε εγγραφές του Buffer, αφού πλέον το κλειδί 5 που είχε διαβαστεί με σκορ 50 προηγουμένως μπορεί να φτάσει σε άθροισμα σκορ το πολύ 90 (εφόσον διαβαστεί στοιχείο με κλειδί 5 στην επόμενη θέση της λίστας L2). Έτσι, οι προϋπάρχουσες εγγραφές ενημερώνονται σε: 5:(50-90) και 3:(50-90). Επίσης, το στοιχείο με κλειδί 1 τοποθετείται στη μνήμη Μ1, ενώ το στοιχείο με κλειδί 2 τοποθετείται στη μνήμη Μ2. Ο έλεγχος τερματισμού ελέγχει εάν υπάρχουν Κ (στο παράδειγμα Κ=1) εγγραφές στον Buffer B των οποίων το ελάχιστο άθροισμα σκορ είναι εγγραφών του Buffer B. Ο έλεγχος αποτυγχάνει και ο αλγόριθμος συνεχίζει. Στο τρίτο βήμα, διαβάζονται τα στοιχεία με κλειδί 3 (3,30) από την L1 και κλειδί 1 (1,30) από την L2. Αυτά δεν έχουν κοινό κλειδί μεταξύ τους. Το (3,30) έχει κοινό κλειδί με το στοιχείο (3,50) στη Μ2 οπότε ενημερώνεται η αντίστοιχη εγγραφή του Buffer σε 3:(80-80). Το (1,30) συνδυάζεται με το στοιχείο (1,40) στη Μ1 οπότε ενημερώνεται η αντίστοιχη εγγραφή του Buffer σε 1:(70-70). Ενημερώνονται οι δυνατές τιμές αθροίσματος σκορ και των υπόλοιπων κλειδιών σε εγγραφές του Buffer: συγκεκριμένα, 5:(50-80) και 2:(40-70). Επίσης, το στοιχείο με κλειδί 3 τοποθετείται στη μνήμη Μ1, ενώ το στοιχείο με κλειδί 1 τοποθετείται στη μνήμη Μ2. Ο έλεγχος τερματισμού ελέγχει εάν υπάρχουν Κ (στο παράδειγμα Κ=1) εγγραφές στον Buffer B, των οποίων το ελάχιστο άθροισμα σκορ είναι εγγραφών του Buffer B. Όντως υπάρχει η 3:(80-80) ενώ η μέγιστη δυνατή τιμή αθροίσματος σκορ για οποιοδήποτε άλλο κλειδί (σε έγγραφή του Buffer) είναι 80. Ο αλγόριθμος τερματίζει και επιστρέφει την εγγραφή του Buffer με κλειδί 3 ως tp-1 αποτέλεσμα. 2
Σχήμα 1: Παράδειγμα εκτέλεσης του αλγόριθμου. Επιπλέον, δίνεται ο ψευδοκώδικας του παραπάνω αλγόριθμου. B // Buffer με στοιχεία που έχουν βρεθεί και εύρος δυνατού σκορ (min-max) while (true) { p1 πάρε το επόμενο στοιχείο από τη λίστα L1 p2 πάρε το επόμενο στοιχείο από τη λίστα L2 curscre1 p.scre1 curscre2 p.scre2 if p1.id == p2.id then ενημέρωσε τον Β με την εγγραφή p1.id με min=max=p1.scre+p2.scre else { if το p1.id βρίσκεται στη μνήμη Μ2 (έστω p) then ενημέρωσε το p1.id στον B με min=max=p1.scre+p.scre else πρόσθεσε το p1.id στον B με min=p1.scre και max=p1.scre+curscre2 if το p2.id βρίσκεται στη μνήμη Μ1 (έστω p) then ενημέρωσε το p2.id στον B με min=max=p2.scre+p.scre else πρόσθεσε το p2.id στον B με min=p2.scre και max=p2.scre+curscre1 } ενημέρωσε τα δυνατά σκορ (min-max) στις εγγραφές του Buffer Β πρόσθεσε το p1 στη μνήμη M1 (με τα στοιχεία που διαβάστηκαν από τη λίστα L1) πρόσθεσε το p2 στη μνήμη M2 (με τα στοιχεία που διαβάστηκαν από τη λίστα L2) } if υπάρχουν Κ εγγραφές στον Buffer B με ελάχιστο άθροισμα σκορ μεγαλύτερο ή ίσο από το μέγιστο άθροισμα σκορ των υπόλοιπων εγγραφών του Buffer B then επίστρεψε τις K εγγραφές και τερμάτισε 3
2) ΖΗΤΟΥΜΕΝΑ 1) Ζητείται να υλοποιήσετε τον παραπάνω αλγόριθμο σαν μια συνάρτηση tpk(int k, Lista L1, Lista L2) που θα υλοποιεί τον αλγόριθμο εντός μιας κλάσης: class MyAlgrithm. 2) Να συντάξετε τεχνική αναφορά που θα περιλαμβάνει: Πειραματική μελέτη: Να προσθέσετε μετρητές στον κώδικά σας που να μετρούν (α) το συνολικό χρόνο εκτέλεσης του αλγόριθμου, και (β) το συνολικό πλήθος των στοιχείων που διάβασε από τις δύο λίστες. Στη συνέχεια να διεξάγετε πειραματική μελέτη κατά την οποία θα εκτελέσετε τον αλγόριθμό σας για Κ=100 και λίστες L1 και L2 με αυξανόμενο πλήθος N στοιχείων και θα συμπληρώσετε τον πίνακα: Tpk() Ν Χρόνος Συνολικό πλήθος στοιχείων 2.000 4.000 6.000 8.000 10.000 Επίσης, για Ν=10.000 να εκτελέσετε τον αλγόριθμό σας για αυξανόμενες τιμές Κ και να συμπληρώσετε τον πίνακα: Tpk() Κ Χρόνος Συνολικό πλήθος στοιχείων 100 200 300 400 500 Να σχεδιάσετε 4 γραφικές παραστάσεις (Χρόνος-Ν, Πλήθος-Ν, Χρόνος-Κ, Πληθος-Κ) με βάση τις τιμές των δύο πινάκων και να σχολιάσετε τα αποτελέσματα. Ανάλυση πολυπλοκότητας: Να αναλύσετε την πολυπλοκότητα του αλγόριθμου που υλοποιήσατε ως προς το μέγεθος των λιστών (Ν) και την τιμή K. Να τεκμηριώσετε επαρκώς πώς προκύπτει το αποτέλεσμα. 3) ΔΕΔΟΜΕΝΑ Κλάση Tuple που αναπαριστά ένα στοιχείο λίστας ή εγγραφή του Buffer. Προσφέρει μεθόδους get και set για τα ακόλουθα πεδία: private int id; Το κλειδί του στοιχείου που αναπαρίσταται. private duble value; Η τιμή (σκορ) του στοιχείου μιας λίστας. private duble min; Το ελάχιστο άθροισμα σκορ για κάποιο κλειδί (σε εγγραφή του Buffer). private duble max; Το μέγιστο άθροισμα σκορ για κάποιο κλειδί (σε εγγραφή του Buffer). private int type; Είδος στοιχείου λίστας, που δηλώνει π.χ. τη λίστα (1 για L1, 2 για L2) από την οποία προέρχεται το στοιχείο (ώστε να διακρίνεται η λίστα από την οποία προέρχονται δύο αντικείμενα τύπου Tuple με το ίδιο κλειδί). 4
Η κλάση επίσης προσφέρει δύο cnstructrs εκ των οποίων ο ένας αρχικοποιεί όλα τα πεδία με δεδομένες τιμές, ενώ ο άλλος δεν εκτελεί καμία αρχικοποίηση. Κλάση Lista που αναπαριστά μια Λίστα από αντικείμενα τύπου Tuple. Έχει έναν cnstructr Lista(int size, int type) που αρχικοποιεί τη Λίστα με ένα πλήθος size τυχαίων αντικειμένων τύπου Tuple και είδους type. H κλάση Lista επίσης προσφέρει τις μεθόδους: public Tuple getnext() που επιστρέφει το επόμενο στοιχείο της λίστας, τύπου Tuple, public int size() που επιστρέφει το πλήθος των στοιχείων της λίστας που δεν έχουν διαβαστεί ακόμα. Κλάση MyCmparatr που αποτελεί βοηθητική κλάση. Κλάση MyAlgrithmApp που περιέχει μια main() συνάρτηση με δείγμα κλήσης του κώδικα που πρέπει να αναπτύξετε. 4) ΔΙΑΔΙΚΑΣΤΙΚΑ ΘΕΜΑΤΑ ΠΑΡΑΔΟΤΕΑ: Θα πρέπει να παραδώσετε ένα αρχείο ΑΜ_Επώνυμο_Όνομα.zip (όπου ΑΜ ο αριθμός μητρώου) που θα περιλαμβάνει 2 αρχεία μόνο: 1. Το αρχείο πηγαίου κώδικα MyAlgrithm.java επαρκώς σχολιασμένο. Προσοχή: σχόλια στα ελληνικά μόνο σε κωδικοποίηση UTF-8. Άλλες κωδικοποιήσεις (ISO-8859-7, Windws 1253) απορρίπτονται από τον Java Cmpiler. Eclipse / Netbeans: δεξί click στο Prject, επιλογή Prperties και, στην ιδιότητα «Encding», επιλέγετε UTF-8. 2. Την τεχνική αναφορά σας σε μορφή pdf. ΘΑ ΑΓΝΟΗΘΕΙ κάθε άλλη μορφή εγγράφου. ΠΑΡΑΔΟΣΗ: αποκλειστικά μέσω της πλατφόρμας «Εύδοξος» του τμήματος, έως και την 25 Ιανουαρίου 2016, 23:59. Ανεβάστε το ΑΜ_Επώνυμο_Όνομα.zip στην περιοχή ΕΡΓΑΣΙΑ2. ΕΡΩΤΗΣΕΙΣ/ΑΠΟΡΙΕΣ/ΔΙΕΥΚΡΙΝΙΣΕΙΣ: αποκλειστικά μέσα από την περιοχή συζήτησης «ΕΡΓΑΣΙΑ 2» της πλατφόρμας «Εύδοξος». Δε θα απαντηθούν email με απορίες. ΕΡΓΑΣΙΕΣ ΠΟΥ ΘΑ ΠΑΡΑΔΟΘΟΥΝ ΕΚΠΡΟΘΕΣΜΑ Η ΜΕ ΑΛΛΟ ΤΡΟΠΟ (Email, CD κ.λ.π.) ΔΕ ΘΑ ΑΞΙΟΛΟΓΗΘΟΥΝ. ΒΑΘΜΟΛΟΓΗΣΗ: Η εργασία μετρά 20% στον τελικό βαθμό (εφόσον το γραπτό σας βαθμολογηθεί με τουλάχιστον 4). Φτωχή / Δυσανάγνωστη τεκμηρώση ή έλλειψη αυτής στην αναφορά σε σχέση με οποιοδήποτε από τα ζητούμενα της εργασίας επιφέρει άμεση απώλεια 50% του μέγιστου δυνατού βαθμού για το ζητούμενο αυτό. Η τεχνική αναφορά ή τμήματα αυτής δε θα ληφθούν υπόψην στη βαθμολόγηση αν δε συνοδεύονται από κώδικα που μεταγλωττίζεται και εκτελείται. Η εργασία είναι αυστηρά ατομική. Αντιγραφή στον κώδικα και / η στην τεχνική αναφορά επιφέρει άμεσο μηδενισμό της εργασίας. Οι εργασίες θα ελεγχθούν (όλες ανά ζεύγη). ΚΑΛΗ ΕΠΙΤΥΧΙΑ!!! 5