Professional Documents
Culture Documents
Ανάλυση Αλγορίθμων - Διάλεξη 6
Ανάλυση Αλγορίθμων - Διάλεξη 6
Ανάλυση Αλγορίθμων 2
Οι αποτελεσματικότεροι αναδρομικοί αλγόριθμοι υλοποιούν την αρχή
του διαίρει και βασίλευε
• Διαιρούμε το πρόβλημα σε υποπροβλήματα που είναι μικρότερα
στιγμιότυπα του ίδιου προβλήματος
• Κυριεύουμε τα υποπροβλήματα, επιλύοντάς τα αναδρομικά
• Συνδυάζουμε τις λύσεις των υποπροβλημάτων για να συνθέσουμε μια λύση
του αρχικού προβλήματος
Ανάλυση Αλγορίθμων 4
Γενικός κανόνας: Η διατήρηση μιας ισορροπίας, ή και ισότητας, μεταξύ
των μεγεθών 𝑛1 , 𝑛2 , … , 𝑛𝑘 των υποπροβλημάτων Π1 , Π2 , … , Π𝑘 που
προκύπτουν από τη διάσπαση ενός προβλήματος Π μεγέθους n.
𝑇(𝑛) Π
𝑛 𝑇 𝑇′
𝑛1 , 𝑛2 Π1
Π2 Π 𝑛 = 𝑛1 + 𝑛2
Π1 Π2
𝑛
𝑛1 = 𝑛2 =
2
Ανάλυση Αλγορίθμων 5
Π 𝑘 𝑘=
2 Π1 , Π2 , … , Π𝑘
Π
Π1 , Π2 , … , Π𝑘
Π1 , Π2 , … , Π𝑘 Π
Ανάλυση Αλγορίθμων 6
• 𝑘 Π1 , Π2 , … , Π𝑘
𝑛
𝐷(𝑛) το πλήθος βημάτων της divide
𝑆(𝑛) το πλήθος βημάτων της conquer
𝐶(𝑛) το πλήθος βημάτων της combine
Τότε
𝑘
𝑇 𝑛 = 𝐷 𝑛 + 𝑆(𝑛𝑖 ) + 𝐶(𝑛)
𝑖=1
Ανάλυση Αλγορίθμων 7
Διάσπαση
Πρόβλημα μεγέθους 𝑛 προβλήματος
Ανάλυση Αλγορίθμων 8
Διάσπαση
Πρόβλημα μεγέθους 𝑛 προβλήματος
Ανάλυση Αλγορίθμων 9
Συνδυασμός
Πρόβλημα μεγέθους 𝑛 λύσεων
Ανάλυση Αλγορίθμων 10
Πρόβλημα μεγέθους 𝑛
Χρόνος Εκτέλεσης
𝑇 𝑛 = 𝑇 𝑘 + 𝑇 𝑛 − 𝑘 + 𝐷 𝑛 + 𝐶(𝑛)
𝒪(1), 𝛼𝜈 𝑛 = 0
𝑇 𝑛 =ቊ
𝑇 𝑛 − 1 + 𝒪(1), 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
𝒪(𝑛)
Ανάλυση Αλγορίθμων 14
int power(int base, int n)
{
if (n == 0)
return 1;
else if (n%2 == 0)
return power(base, n/2)*power(base, n/2);
else
return base*power(base, n/2)*power(base, n/2);
}
𝒪(1), 𝛼𝜈 𝑛 = 0
𝑇 𝑛 =ቐ 𝑛
2𝑇 + 𝒪(1), 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
2
𝒪(𝑛)
Ανάλυση Αλγορίθμων 15
int power(int base, int n)
{ 𝒪(1), 𝛼𝜈 𝑛 = 0
int temp; 𝑇 𝑛 =ቐ 𝑛
𝑇 + 𝒪(1), 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
if(n == 0) 2
return 1;
temp = power(base, n/2); 𝒪(lg 𝑛)
if (n%2 == 0)
return temp*temp;
else
return base*temp*temp;
}
Ανάλυση Αλγορίθμων 16
17
την ακολουθία n στοιχείων σε δύο υπακολουθίες 𝒏/𝟐
στοιχείων
τις δύο υπακολουθίες αναδρομικά
τις δύο ταξινομημένες υπακολουθίες
ώστε να σχηματιστεί η τελική ταξινομημένη ακολουθία
9 4 5 1 0 7 3 2
9 4 5 1 0 7 3 2
9 4 5 1 0 7 3 2
4 9 1 5 0 7 3 2
1 4 5 9 0 2 3 7
0 1 2 3 4 5 7 9
Ανάλυση Αλγορίθμων 19
else {
// Συγχώνευση δυο υποπινάκων του arr[]: arr[k] = R[j];
// arr[l..m] και arr[m+1..r] j++;
void merge(int arr[], int l, int m, int r) }
{ k++;
int i, j, k; }
int n1 = m - l + 1;
int n2 = r - m; // Αντιγραφή των στοιχείων του L[] που περίσσεψαν
while (i < n1) {
/* Βοηθητικοί πίνακες */ arr[k] = L[i];
int L[n1], R[n2]; i++;
k++;
/* Αντιγραφή τιμών στους L[] και R[] */ }
for (i = 0; i < n1; i++)
L[i] = arr[l + i]; // Αντιγραφή των στοιχείων του R[] που περίσσεψαν
for (j = 0; j < n2; j++) while (j < n2) {
R[j] = arr[m + 1 + j]; arr[k] = R[j];
j++;
/* Συγχώνευση των L και M στον[l..r]*/ k++;
i = 0; // Δείκτης για τον πίνακα L }
j = 0; // Δείκτης για τον πίνακα R }
k = l; // Δείκτης για τον πίνακα arr
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++; Πολυπλοκότητα
}
Ανάλυση Αλγορίθμων 20
else {
// Συγχώνευση δυο υποπινάκων του arr[]: arr[k] = R[j];
// arr[l..m] και arr[m+1..r] j++;
void merge(int arr[], int l, int m, int r) }
{ k++;
int i, j, k; }
int n1 = m - l + 1;
int n2 = r - m; // Αντιγραφή των στοιχείων του L[] που περίσσεψαν
while (i < n1) { n1 επαναλήψεις
/* Βοηθητικοί πίνακες */ arr[k] = L[i];
int L[n1], R[n2]; i++;
k++;
/* Αντιγραφή τιμών στους L[] και R[] */ }
for (i = 0; i < n1; i++)
L[i] = arr[l + i]; // Αντιγραφή των στοιχείων του R[] που περίσσεψαν
for (j = 0; j < n2; j++) while (j < n2) { n2 επαναλήψεις
R[j] = arr[m + 1 + j]; arr[k] = R[j];
j++;
/* Συγχώνευση των L και M στον[l..r]*/ k++;
i = 0; // Δείκτης για τον πίνακα L }
j = 0; // Δείκτης για τον πίνακα R }
k = l; // Δείκτης για τον πίνακα arr
while (i < n1 && j < n2) { n1 ή n2 επαναλήψεις
if (L[i] <= R[j]) {
arr[k] = L[i];
1 σύγκριση
i++;
𝓞 𝒏𝟏 + 𝒏𝟐 = 𝓞(𝒏)
}
Ανάλυση Αλγορίθμων 21
/* l είναι ο αριστερός δείκτης και r ο δεξιός δείκτης του υποπίνακα του arr */
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
int m = (r + l) / 2;
merge(arr, l, m, r);
}
}
Πολυπλοκότητα
Ανάλυση Αλγορίθμων 22
/* l είναι ο αριστερός δείκτης και r ο δεξιός δείκτης του υποπίνακα του arr */
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
int m = (r + l) / 2;
merge(arr, l, m, r);
}
}
1, 𝛼𝜈 𝑛 = 1
𝑇 𝑛 =ቐ 𝑛
2𝑇 + 𝑛, 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
2
𝒪(𝑛lg𝑛)
Ανάλυση Αλγορίθμων 23
• 𝒪(𝑛lg𝑛)
•
• 𝒪(𝑛)
Ανάλυση Αλγορίθμων 24
25
1. Διαίρει (divide): Διάλεξε ένα στοιχείο pivot (άξονα) του
πίνακα. Με βάση αυτό, χώρισε στα δύο τον πίνακα:
στον αριστερό υποπίνακα βάλε όλα τα μικρότερα
στοιχεία και στο δεξιό όλα τα μεγαλύτερα στοιχεία από
το pivot. S
Ανάλυση Αλγορίθμων 27
int partition(int a[], int left, int right)
{
int pivot, i, j, t;
pivot = a[left];
i = left; j = right+1;
while (1){
do ++i;
while (a[i]<=pivot && i<j);
do --j;
while (a[j] > pivot);
if(i >= j) break;
t=a[i]; a[i]=a[j]; a[j]=t;
}
t=a[left]; a[left]=a[j]; a[j]=t;
return j;
}
Ανάλυση Αλγορίθμων 28
23 42 10 100 8 4 12 56 57 50
pivot i j
Ανάλυση Αλγορίθμων 29
23 12 10 4 8 100 42 56 57 50
int partition(int a[], int left, int right)
{
int pivot, i, j, t; pivot i j
pivot = a[left];
i = left; j = right+1;
23 12 10 4 8 100 42 56 57 50
while (1){
do ++i;
while (a[i]<=pivot && i<j); pivot j i
do --j;
while (a[j] > pivot);
8 12 10 4 23 100 42 56 57 50
if(i >= j) break;
t=a[i]; a[i]=a[j]; a[j]=t;
}
t=a[left]; a[left]=a[j]; a[j]=t; quickSort(a, left, j-1); quickSort(a, j+1, right);
return j;
}
Ανάλυση Αλγορίθμων 30
8 12 10 4
Ανάλυση Αλγορίθμων 31
int partition(int a[], int left, int right)
• διαδικασία partition {
int pivot, i, j, t;
pivot pivot = a[left];
i = left; j = right+1;
while (1){
do ++i;
• 𝑛+1 while (a[i]<=pivot && i<j);
do --j;
while (a[j] > pivot);
if(i >= j) break;
t=a[i]; a[i]=a[j]; a[j]=t;
}
t=a[left]; a[left]=a[j]; a[j]=t;
return j;
}
Ανάλυση Αλγορίθμων 32
•
• Εάν το pivot=a[left] είναι το μικρότερο στοιχείο, τότε η λίστα θα
διαχωριστεί στο 1ο της στοιχείο (η 1η αναδρομή δεν θα εκτελεστεί)
void quickSort(int a[], int left, int right)
1 2 3 4 8 9
{
int j;
1 2 3 4 8 9 if (left < right) {
// divide and conquer
j = partition(a, left, right);
2 3 4 8 9 quickSort(a, left, j-1);
quickSort(a, j+1, right);
}
3 4 8 9
}
…
Ανάλυση Αλγορίθμων 33
•
• Εάν το pivot=a[left] είναι το μεγαλύτερο στοιχείο, τότε η λίστα θα
διαχωριστεί στο 1ο της στοιχείο (η 2η αναδρομή δεν θα εκτελεστεί)
void quickSort(int a[], int left, int right)
9 8 4 3 2 1
{
int j;
8 4 3 2 1 9 if (left < right) {
// divide and conquer
j = partition(a, left, right);
4 3 2 1 8 quickSort(a, left, j-1);
quickSort(a, j+1, right);
}
3 2 1 4 }
…
Ανάλυση Αλγορίθμων 34
•
1, 𝛼𝜈 𝑛 = 2
𝑇 𝑛 =ቊ
𝑇 𝑛 − 1 + (𝑛 + 1), 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
• 𝓞 𝒏𝟐
Ανάλυση Αλγορίθμων 35
•
• Συμβαίνει όταν ως pivot επιλέγεται το στοιχείο που υποδιαιρεί
𝑛 𝑛
τη λίστα σε δύο λίστες μεγέθους (έστω η πρώτη λίστα έχει
2 2
𝑛
στοιχεία και η δεύτερη − 1 στοιχεία).
2
• Τότε 1, 𝛼𝜈 𝑛 = 2
𝑇 𝑛 =ቐ 𝑛
2𝑇 + 𝒪(𝑛), 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
2
• Από κύριο θεώρημα, έχουμε 𝑎 = 2, 𝑏 = 2 και 𝑓 𝑛 = 𝑛.
Έχουμε 𝑛𝑙𝑜𝑔𝑏 𝛼 = 𝑛𝑙𝑜𝑔2 2 = 𝑛, άρα είμαστε στη 2η περίπτωση
με 𝑻 𝒏 = 𝚯(𝒏 𝐥𝐠 𝒏)
Ανάλυση Αλγορίθμων 36
38
𝓞 𝒏𝟐
𝑥𝑚𝑖𝑑
𝑥𝑚𝑖𝑑 𝑥𝑚𝑖𝑑 𝑑
𝑑𝐿𝑅𝑚𝑖𝑛
𝑥𝑚𝑖𝑑
𝑑𝐿𝑚𝑖𝑛 , 𝑑𝑅𝑚𝑖𝑛 𝑑𝐿𝑅𝑚𝑖𝑛
Ανάλυση Αλγορίθμων 40
0 0 0
3 3 3
2 2 2
1 1 1
5 8 8 8
4 4 5 4 5
6 7 7 6 7
6
9 10 12 10 12 9 10 12
11 9 11 11
13 13 13
𝑥𝑚𝑖𝑑 𝑥𝑚𝑖𝑑
arr[]={1,9,6,4,11,0,5,2,10,7,3,8,12,13}
PL[]={1,9,6,4,11,0,5} PL[]={1,9,6}
PR[]={2,10,7,3,8,12,13} PR[]={4,11,0,5}
0 0 0
2 3 2 3 2 3
1 1 1
5 8 8 5 8
4 4 5 4
6 7 6 7 6 7
10 12 10 12 10 12
9 d 11 9 dL 11 dR 9 d 11
13 13 13
𝑥𝑚𝑖𝑑 𝑥𝑚𝑖𝑑
arr[]={1,9,6}
Ανάλυση Αλγορίθμων 41
d d
0 0
2 3 3
1 2
8 1
4 5 5 8
dLRmin 7 4
6 6 7
10 12 10 12
9 d 11 9 11
d
13 13
𝑥𝑚𝑖𝑑 𝑥𝑚𝑖𝑑
Ανάλυση Αλγορίθμων 42
float nearestFunc(Point arr[], int n) {// Έστω ότι ο arr είναι ταξινομημένος ως προς x
if (n <= 3) // Εάν έχουμε μόνο 2 ή 3 σημεία χρησιμοποίησε τη μέθοδο ωμής βίας
return bruteForce(arr, n);
int mid = n/2; // Εύρεση μεσαίου σημείου Xmid
Point midPoint = arr[mid];
// Υπολογισμός του dl στην αριστερή πλευρά του μεσαίου σημείου και του dr στη δεξιά
float dl = nearestFunc(arr, mid); // Αναδρομική κλήση της nearestFunc
float dr = nearestFunc(arr + mid, n - mid); // Αναδρομική κλήση της nearestFunc
float d = min(dl, dr); // Εύρεση της μικρότερης απόστασης μεταξύ των 2 (dl, dr)
// Δημιουργία ενός πίνακα που περιέχει τα σημεία που απέχουν λιγότερο από d από τη γραμμή
// που διέρχεται από το Xmid
Point strip[n]; int j = 0;
for (int i = 0; i < n; i++)
Η stripNearest υπολογίζει την
if (abs(arr[i].x - midPoint.x) < d) { ελάχιστη απόσταση μεταξύ των
strip[j] = arr[i]; j++; στοιχείων των δύο λωρίδων
} πλάτους d. Με αλγόριθμο ωμής
return min(d, stripNearest(strip, j, d) );
βίας αυτό θα απαιτούσε 𝓞 𝒏𝟐
}
συγκρίσεις.
Ανάλυση Αλγορίθμων 43
d d
• Ταξινομούμε όλα τα στοιχεία ως προς y.
• Τα πιθανά σημεία που μπορούν να έχουν από το σημείο p
μικρότερη απόσταση από d, βρίσκονται μέσα στο
παραλληλόγραμμο. d/2
• Το κάθε τετράγωνο μπορεί να έχει το πολύ 1 σημείο (γιατί?).
• Επομένως, θα πρέπει να ελέγξουμε το πολύ 7 σημεία. p
p
• Συνεχίζουμε την ίδια διαδικασία για τα επόμενα σημεία.
Γιατί το κάθε τετράγωνο μπορεί να περιέχει το πολύ 1 σημείο?
d/2 Έστω ότι περιέχει 2 σημεία. Η μέγιστη απόσταση που μπορούν να
έχουν αυτά τα σημεία, είναι η απόσταση της διαγωνίου του
d
τετραγώνου, δηλαδή . Αυτό είναι άτοπο, διότι το κάθε τετράγωνο
d/ 2 2
βρίσκεται σε μία μόνο λωρίδα, το οποίο σημαίνει ότι η μέγιστη
d
απόσταση μεταξύ δύο σημείων είναι d και προφανώς d> .
2
Ανάλυση Αλγορίθμων 44
d d d d d d
… 6 = 6𝑚 = 𝓞 𝒏
𝑖=1
συγκρίσεις και
𝑚
7 = 7𝑚 = 𝓞 𝒏
𝑖=1
υπολογισμούς απόστασης
Ανάλυση Αλγορίθμων 45
float nearestFunc(Point arr[], int n) {// Έστω ότι ο arr είναι ταξινομημένος ως προς x
if (n <= 3) // Εάν έχουμε μόνο 2 ή 3 σημεία χρησιμοποίησε τη μέθοδο ωμής βίας
1 σύγκρισηreturn bruteForce(arr, n); 9 πολλαπλασιασμοί και 2 συγκρίσεις
int mid = n/2; // Εύρεση μεσαίου σημείου Xmid
Point midPoint = arr[mid];
// Υπολογισμός του dl στην αριστερή πλευρά του μεσαίου σημείου και του dr στη δεξιά
float dl = nearestFunc(arr, mid); // Αναδρομική κλήση της nearestFunc
float dr = nearestFunc(arr + mid, n - mid); // Αναδρομική κλήση της nearestFunc
float d = min(dl, dr); // Εύρεση της μικρότερης απόστασης μεταξύ των 2 (dl, dr)
// Δημιουργία ενός πίνακα που περιέχει τα σημεία που απέχουν λιγότερο από d από τη γραμμή
// που διέρχεται από το Xmid
Point strip[n]; int j = 0;
for (int i = 0; i < n; i++) Χρόνος εκτέλεσης (συγκρίσεις)
if (abs(arr[i].x - midPoint.x) < d) { 1 σύγκριση 𝑇 𝑛 =ቐ 𝑛
3, 𝛼𝜈 𝑛 = 3
strip[j] = arr[i]; j++; 2𝑇 + 𝒪(𝑛), 𝛿𝜄𝛼𝜑𝜊𝜌𝜀𝜏𝜄𝜅𝛼
} 2
Από το κύριο θεώρημα, προκύπτει εύκολα ότι η
return min(d, stripNearest(strip, j, d) );
πολυπλοκότητα είναι
} 𝓞(𝒏)+1 συγκρίσεις 𝓞(𝒏 𝐥𝐠𝒏)
Ανάλυση Αλγορίθμων 46
𝒏 𝐥𝐠 𝒏 𝒏𝟐 𝒏 𝐥𝐠𝒏
16 4 256 64
1,024 10 1,048,576 10,240
2,048 11 4,194,304 22,528
4,096 12 16,777,216 49,152
1,048,576 20 1,099,511,627,776 20,971,520
33,554,432 25 1,125,899,906,842,624 838,860,800
Ανάλυση Αλγορίθμων 47