ΑΝΑ ΡΟΜΙΚΗ ΤΑΞΙΝΟΜΗΣΗ- ΑΣΚΗΣΕΙΣ Οι μέθοδοι ταξινόμησης QUICK SORT και MERGE SORT κωδικοποιούνται εύκολα αναδρομικά Oι δυο αναδροµικοί µέθοδοι δέχονται 1ο όρισµα τον πίνακα, και δεν επιστρέφουν τίποτα. 4. Quick Sort γρήγορη ταξινόµηση Η quick ταξινόµηση βασίζεται στη παρακάτω ιδέα : να βρεθεί µια τιµή pivot του πίνακα ώστε, όλα τα στοιχεία αριστερά του να έχουν τιµή µικρότερη από την τιµή αυτή, και όλα τα στοιχεία δεξιά του να έχουν τιµή µεγαλύτερη l=0 1 2 3 4 r=5 150 100 120 90 160 220 p Ο δείκτης p θα χωρίσει τον πίνακα σε δύο υποπίνακες, ο ένας θα περιέχει όλα τα στοιχεία τα οποία είναι µικρότερα από το pivot A[p], ενώ ο άλλος όλα τα µεγαλύτερα από το pivot. Ο αλγόριθµος καλείται κατόπιν αναδροµικά στους 2 υπο-πίνακες. Aν ο πίνακας έχει 0 ή 1 στοιχεία δεν κάνουµε τίποτα (είναι ήδη ταξινοµηµένος). Ο αλγόριθµος δεν απαιτεί να υπάρχει αρχικά ένας τέτοιος διαχωρισµός. Σαν pivot/"άξονας" µπορεί να χρησιµοποιηθεί µια τιµή του πίνακα σε οποιαδήποτε θέση µπορεί π.χ. να είναι η τιµή στην 1η θέση ή στην µεσαία και µε διαδοχικά swapping η κατάλληλη τιµή να πάει στην θέση p. Παράδειγµα 1: ΕΣΤΩ ο πίνακας Α[] = {1, 12, 5, 26, 7, 14, 3, 7, 2 Η τιµή στο p είναι A[p]=160 p=4 Α[l]<A[p] l={0,1,2,3 Α[r]>A[p] r={5 l= 7 r=8 Στο παράδειγµα αυτό ο δείκτης p δείχνει στην µεσαία θέση (p=4) (στον αλγόριθµο partition πιο κάτω δείχνει στην 1 η θέση) ΑΡΙΣΤΕΡΑ ΕΞΙΑ 7>1 οκ 7<2 7>12 Swap 12, 2 7>2 οκ 7<12 οκ 7>5 οκ 7 7 οκ 7>26 7<3 Swap 26, 3 7 7 7<14 οκ 7 7 οκ Ετσι στην θέση p=4 µε τιµή 7 έχω χωρίσει τον πίνακα σε 2 υποπίνακες 1 2 5 3 7 4 26 7 12 που ικανοποιούν την ιδέα. Θα συνεχίσει αναδροµικά για τον πίνακα 1 2 5 3 κτλ [1] ΕΑΡ 2015
Άλλο παράδειγµα, αυτή τη φορά µε pivot στην 1 η θέση: Παράδειγµα 2: ΕΣΤΩ ο πίνακας Α[] = {18, 16, 22, 12, 9, 15, 10 Ο χωρισµός σε δυο υποπίνακες είναι εικονικός και γίνεται µε την χρήση δεικτών που µετακινούνται και τιµών που ανταλλάσουν τις θέσεις τους. Ξεκινώντας µε pivot=18 στην 1 η θέση του 7θεσιου πίνακα ( A[0]=18) θέτω 3 δείκτες: l=1, r=6 και LL=0 και Α[LL]=18 Οσο l<r p=0 l l r 18 16 22 12 9 15 10 pivot >=Α[l] l++ pivot <=Α[r] r-- Αυτοί οι 2 δείκτες θα µετακινούνται το µεν l++ και το r--, δηλ l : προς τα δεξιά όσο 18 >=Α[l] r : προς τα αριστερά όσο 18 <=Α[r] Aν l<r swap A[l] µε Α[r] swap 22,10 p=0 l l l l r l r 18 16 10 12 9 15 22 pivot >=Α[l] l++ pivot <=Α[r] r-- Οι 2 δείκτες συνεχίζουν να µετακινούνται το µεν l++ και το r-- αλλαγή του 18 ή µε 15 µε 22 Βγαίνει τώρα µε l<r αλλά l=6 και r=5, και θα αλλάξει ο δείκτης p Συγκρίνεται το pivot µε τις τιµές των A[l] και Α[r]=15 και αφού 18>=Α[r] τότε swap A[r] µε Α[LL], p=r p=5 15 16 10 12 9 18 22 pivot > A[l]) swap Α[l] µε A[LL] και p=l pivot >= A[r]) swap Α[r] µε A[LL] και p=r swap 15,18 Ετσι µε κάποιες ανταλλαγές τιµών κατάφερα να χωρίσω τον αρχικό πίνακα στην θέση p=5 σε δυο υποπίνακες και θα επαναλάβω την διαδικασία για τους υποπίνακες. Ο νέος πίνακας για να χωρίσω θα είναι ο {15, 16, 10, 12, 9 που θα χωριστεί σε 12,9,10,15, 16 και µετά ο πίνακας {12, 9, 10 θα χωριστεί 10 9 12 κτλ. [2] ΕΑΡ 2015
Παράδειγµα 3: ΕΣΤΩ ένας ΑΛΛΟΣ παρόµοιος πίνακας Α[] = {4, 16, 22, 12, 9, 15, 10 public static void QuickSort (int[] A, int left, int right) { τα διαδοχικά p είναι: if (right-left>=1) { int p = partition (A, left, right); QuickSort (A, left, p-1); QuickSort (A, p+1, right); public static int partition (int[] A, int l, int r) { int p=0; int lowerlimit = l; int pivot =A[l]; l++; while (l<r) { while (A[l] <= pivot && l< r) l++; while (A[r] >= pivot && l<= r) r--; if (l<r) swap (A,l,r); Προσδιορισµός των θέσεων l και r ανταλλάξουν τιµές και swap.. 4 15 10 12 9 16 22 1 ος διαχωρισµός µε p=0 και Α[0]=4 2 ος διαχωρισµός µε p=5 και Α[5]=16 3 ος διαχωρισµός µε p=4 και Α[4]=15 4 ος διαχωρισµός µε p=1 και Α[1]=9 του πίνακα που θα if (pivot > A[l]) { swap (A,l,lowerLimit); p=l; else { if (pivot >= A[r]) { swap (A,r,lowerLimit); p=r; return p; Επαναπροσδιορισµός του p και swap.. public static void swap (int[] A, int x, int y) { int temp = A[x]; A[x] = A[y]; A[y] = temp; // Sort.java [3] ΕΑΡ 2015
2. Merge Sort - ταξινόµηση µε συγχώνευση Η ταξινόµηση αυτή υλοποιείται χρησιµοποιώντας επαναλαµβανόµενες συγχωνεύσεις µε αναδροµική κλήση µε βάση την ιδέα: «Χωρίζουµε τον πίνακα σε δύο µέρη και ταξινοµούµε πρώτα το αριστερό µισό µέρος του πίνακα και κατόπιν το δεξιό. Ακολουθεί η συγχώνευση των δύο πινάκων». Επαναλαµβάνουµε την διαδικασία αναδροµικά για τα δύο µέρη του πίνακα µέχρι το µήκος των υποπινάκων οι οποίοι προκύπτουν να είναι µικρότερο ή ίσο του ένα. i1 i2 7 public static void MergeSort (int[] A, int left, int right) { 0 1 mid mid+1 r 7 if (left==right) return; 1.ΤαχινοµηµένοςΠίνακας 2.ΤαχινοµηµένοςΠίνακας int mid=(left+right)/2; MergeSort (A, left, mid); -Από το 0 έως την µέση ο 1 ος πίνακας MergeSort (A, mid+1, right); -Από την µέση και µετά µέχρι το τέλος ο 2 ος πίνακας merge(a,left,right,mid); Θα τους συγχωνεύσουµε (merge) public static void merge (int[] A, int l, int r, int mid) { merge int n = r-l+1; // size of the range to be merged Χρησιµοποιώ ένα νέο πίνακα b για βάλω µέσα, // merge both halves into a temporary array b σωστά ταξινοµηµένους, τους αριθµούς. int[] b = new int[n]; int i1=l ; int i2=mid+1; int j=0; // next open position in b while (i1 <= mid && i2 <= r) { if (A[i1]<A[i2]) { b[j]=a[i1]; i1++; else {b[j]=a[i2]; i2++; while (i1<=mid) { b[j]=a[i1]; i1++; while (i2<=r) { b[j]=a[i2]; i2++; // copy back from the temporary array for (j=0; j<n; j++) A[l+j]=b[j]; // sort.java public class Main { public static void main (String[] args) { int numbers[] = {7, -3, 7, 2, 8, -1, 3, 2, 5, 6; showpinaka(numbers) ; ταξινοµηµένοι sort.mergesort(numbers, 0, numbers.length-1); showpinaka(numbers) ; // [4] ΕΑΡ 2015 Χρησιµοποιώ 2 δείκτες i1 για τον 1 ο πίνακα i2 για τον 2 ο πίνακα Συγκρίνω τις τιµές 1[i1]<2[i2]), αντιγράφω την µικρότερη στην πρώτη ελεύθερη θέση του b και προχωρώ τους δείκτες ανάλογα (ή τον i1 ή τον i2). Ο δείκτης j του b προχωρά πάντα. Αν ξέµειναν στοιχεία στον 1 ο τα αντιγράφω στο b Αν ξέµειναν στοιχεία στον 2 ο τα αντιγράφω στο b Αντιγράφω τον ταξ/νο πίνακα b στον αρχικό µου. Αναδροµικά - δεν απαιτείται ταξινόµηση των 2 αρχικών υπο-πινάκων: 4 16 12 22 9 15 10 4 12 16 22 9 10 15
Εφαρµογή για ταξινόµηση φοιτητή µε ΑΜ και Επώνυµο public class MyUtils { //public static void QuickSort (int[] A, int left, int right) { public static void quicksortam (int[] A,int left, int right) { // //public static void MergeSort (int[] A, int left, int right) { public static void mergesorteponymo (int[] A,int left, int right) { // //ΜyUtils.java Θα πρέπει να βάλετε τις επιθυµητές παραµέτρους και να συµπληρώσετε αναλόγως την µέθοδο public class UserInput {// η κλάση που σας δίνεται public static String getstring(){ // public static int getshort() { // //UserInput.java public class foititis { private String name; private String surname; private int am; private int registyear; public foititis(string name, String surname){ //δοµητής public void setarmitroou(short x){ public void setetoseisagwgis(short x){ //..και ότι άλλο χρειάζεται //foititis.java public class TestMyUtils { public static void main (String[] args) { foititis[] f = new foititis[7]; f[0]=new foititis("vassi","koubi",(short)5,(short)2010); // MyUtils.quickSortAM // MyUtils mergesorteponymo.. // TestMyUtils.java Θα χρειαστείτε και την compareto π.χ. if (f[i1].getsurname().compareto(f[i2].getsurname())<0) [5] ΕΑΡ 2015