Anda di halaman 1dari 11

Analisis Perbandingan Algoritma Sorting Introsort dan MyIdeaExperiment

sort

Muhammad Fauzan Fikri - 1506688802

1. Pendahuluan

Hybrid algorithm adalah sebuah algoritma yang menggabungkan dua atau lebih
algoritma yang bertujuan untuk meningkatkan performa atau reliability. Hybrid algorithm
yang dibahas untuk paper ini berkaitan dengan masalah pengurutan atau sorting. Algoritma
sorting tersebut adalah Introsort (Introspective sort), Timsort, dan MyIdeaExperiment sort.
MyIdeaExperiment sort adalah algoritma sorting yang diimplementasi dengan mengambil ide
dari Introsort. Tujuan dari paper ini adalah mengetahui performa dari Hybrid algorithm baru
(MyIdeaExperiment sort) yang juga menggunakan Hybrid algorithm (Timsort) untuk
dibandingkan dengan Hybrid algorithm murni yaitu Introsort yang merupakan gabungan dari
Insertion sort, Quicksort, Heapsort.

Paper ini membahas Introsort, Timsort, dan MyIdeaExperiment sort beserta analisis
kompleksitas dan running time terhadap Array Decreasing Order, Array Acak, dan Array
dengan nilai tiap elemen sama. Paper ini dibagi menjadi tujuh bagian. Bagian 1 berisi
pendahuluan, bagian 2 berisi penjelasan dan cara kerja Introsort, bagian 3 berisi penjelasan dan
cara kerja Timsort, bagian 4 berisi penjelasan dan cara kerja MyIdeaExperiment sort, bagian 5
berisi eksperimen, bagian 6 berisi analisis, dan bagian 7 berisi kesimpulan.

2. Penjelasan dan Cara Kerja Introsort

Quicksort adalah salah satu algoritma sorting yang cukup baik dengan performa pada
kasus rata rata adalah O(n log n). Namun pada kasus terburuk performanya bisa mencapai
Θ(n2). Hal tersebut tentunya juga mempengaruhi performa dari program yang dibuat sehingga
digunakan alternatif lain yaitu Heapsort. Heapsort memiliki performa Θ(n log n) untuk kasus
terbaik, kasus rata – rata, dan kasus terburuk. Selain time complexity, Heapsort juga unggul
dari sisi space complexity yaitu hanya membutuhkan O(1) dibandingkan dengan Quicksort
yang butuh O(log(n)) dan Mergesort yang butuh O(n). Hal – hal tersebut akhirnya mendorong
dibuatnya Introsort yang menggabungkan Quicksort dan Heapsort menjadi sebuah algoritma
baru. Selain itu, Introsort juga menggunakan Insertion sort. Introsort sendiri digunakan untuk
melakukan pengurutan pada C++ Standard Template Library.
Introsort bekerja seperti Insertion sort jika jumlah input elemen sangat kecil
sedemikian hingga ukuran partisi yang dibuat kurang dari 16. Ukuran partisi tersebut
berdasarkan penelitian dilakukan oleh pembuat kode Introsort. Ini merupakan kasus pertama.

Introsort bekerja seperti Quicksort jika jumlah input elemen cukup besar sedemikian
hingga ukuran partisi yang dibuat berada di antara dengan 16 sampai 2*log N (pada kode yang
digunakan, sudah ditentukan maksimal ukuran partisi adalah 2*log N). Quicksort
menggunakan metode median-of-3 dalam menentukan pivot untuk melakukan partisi dari
jumlah input berukuran N menjadi N/2 lalu N/4 dan seterusnya. Ini merupakan kasus kedua.

Jika ukuran partisi tersebut berkembang menjadi tree dengan kedalaman lebih dari
2*log N , maka dapat menyebabkan kompleksitas menjadi O(n2). Hal tersebut menjadi
indikator yang membuat Introsort beralih menggunakan Heapsort yang mempunyai
kompleksitas O(n log n) . Ini merupakan kasus ketiga. Berikut potongan kode Introsort :

1 #include<bits/stdc++.h> 66 void IntrosortUtil(int arr[], int *


2 using namespace std; 67 begin, int * end, int depthLimit) {
3 68
4 void swapValue(int *a, int *b){ 69 int size = end - begin;
5 int *temp = a; 70
6 a = b; 71 if (size < 16) {
7 b = temp; 72 InsertionSort(arr, begin, end);
8 return; 73 return;
9 } 74 }
10 75
11 void InsertionSort(int arr[], int 76 if (depthLimit == 0) {
12 *begin, int *end) { 77 make_heap(begin, end+1);
13 78 sort_heap(begin, end+1);
14 int left = begin - arr; 79 return;
15 int right = end - arr; 80 }
16 81
17 for (int i = left+1; i <= right; i++){ 82 int * pivot = MedianOfThree(begin,
18 int key = arr[i]; 83 begin+size/2, end);
19 int j = i-1; 84
20 85 swapValue(pivot, end);
21 while (j >= left && arr[j] > key) { 86
22 arr[j+1] = arr[j]; 87 int * partitionPoint = Partition(arr,
23 j = j-1; 88 begin-arr, end-arr);
24 } 89
25 arr[j+1] = key; 90 IntrosortUtil(arr, begin,
26 } 91 partitionPoint-1, depthLimit - 1);
27 92
28 return; 93 IntrosortUtil(arr,
29 } 94 partitionPoint+1,end,depthLimit - 1);
30 95
31 int* Partition(int arr[], int low, int 96 return;
32 high){ 97 }
33 int pivot = arr[high]; 98
34 int i = (low - 1); 99 void Introsort(int arr[], int *begin,
35 100 int *end) {
36 for (int j = low; j <= high- 1; j++) 101 int depthLimit = 2 * log(end-begin);
37 { 102 IntrosortUtil(arr, begin, end,
38 if (arr[j] <= pivot) { 103 depthLimit);
39 i++; 104 return;
40 swap(arr[i], arr[j]); 105 }
41 }
42 }
43
44 swap(arr[i + 1], arr[high]);
45 return (arr + i + 1);
46 }
47
48
49
50 int *MedianOfThree(int * a, int * b,
51 int * c){
52
53 if (*a < *b && *b < *c)
54 return (b);
55 if (*a < *c && *c <= *b)
56 return (c);
57 if (*b <= *a && *a < *c)
58 return (a);
59 if (*b < *c && *c <= *a)
60 return (c);
61 if (*c <= *a && *a < *b)
62 return (a);
63 if (*c <= *b && *b <= *c)
64 return (b);
65 }

Sumber kode Introsort diperoleh dari : https://www.geeksforgeeks.org/know-your-sorting-algorithm-set-2-


Introsort-cs-sorting-weapon/

Analisis Kompleksitas Algoritma Introsort

Baris Cost Penjelasan


4-9 c1 O(1) karena tiap baris hanya melakukan swap 1 kali
11 - 26 c2 O(n2) karena merupakan Insertion sort
31 - 46 c3 O(n) karena penentuan pivot dilakukan dengan mengunjungi tiap elemen di
array yang berukuran n
50 - 65 c4 O(1) karena hanya melakukan conditional statement
66 - 97 c5 Baris ini melakukan pemanggilan fungsi fungsi yang sudah dihitung pada
baris sebelumnya sehingga kompleksitasnya :
O(n2) + O(nlogn) + O(1) + O(1) + O(n) + 2*O(n/2)
99 - 105 c6 Baris ini menghitung depth limit dan juga ini juga melakukan pemanggilan
fungsi fungsi yang sudah dihitung pada baris sebelumnya sehingga
kompleksitasnya :
2*O(log log n) + O(n2) + O(nlogn) + O(1) + O(1) + O(n) + 2*O(n/2)

Kompleksitas :

T(n) = c1*O(1) + c2*O(n2) + c3*O(n) + c4*O(1) + c5*(O(n2) + O(nlogn) + O(1) + O(1) + O(n)
+ 2*O(n/2)) + c6*(2*O(log log n) + O(n2) + O(nlogn) + O(1) + O(1) + O(n) + 2*O(n/2))

Pada penjumlahan di atas terlihat bahwa kompleksitas terbesar adalah O(n2) sehingga dapat
dikatakan bahwa secara default, kompleksitas dari Introsort adalah O(n2) walaupun dapat
berubah berubah sesuai kasus yang sudah sudah dijelaskan di atas.

T(n) = O(n2)
3. Penjelasan dan Cara Kerja TimSort

Timsort adalah algoritma sorting yang dibuat oleh Tim Peters pada 2002 dan digunakan
untuk Bahasa Python dengan kompleksitas O(n log n). Ide yang digunakan algoritma tersebut
adalah membagi sebuah array menjadi beberapa blok run. Blok run adalah beberapa elemen
array yang sudah terurut dalam urutan increasing atau decreasing. Ukuran blok run bervariasi
dari 32 sampai 64. Jika ukuran array kurang dari blok run maka akan diurutkan menggunakan
Insertion sort. Jika lebih maka dilanjutkan dengan pengurutan menggunakan Merge sort.
Penggunaan dua algoritma sorting tersebut membuat Timsort juga termasuk Hybrid algorithm.

Array berukuran 22 yang terbagi menjadi 4 blok run. Gunakan Insertion sort untuk
mengurutkan blok run menjadi increasing order.

Run 1 Run 2 Run 3 Run 4


12 10 7 5 7 10 14 25 36 3 5 11 14 15 21 22 20 15 10 8 5 1
Contoh array diambil dari paper “On the Worst-Case Complexity of TimSort”

Jika blok run sudah terurut, lakukan pengurutan dengan Merge sort.

Gambar Proses Merge sort terinspirasi dari : https://www.khanacademy.org/computing/computer-science/algorithms/merge-sort/a/overview-of-merge-sort


4. Penjelasan dan Cara Kerja MyIdeaExperiment Sort

Langkah pengerjaan dari MyIdeaExperiment sort dapat dikatakan sama seperti


Introsort dimana terbagi menjadi 3 kasus. Kasus pertama bekerja seperti Insertion sort
sedangkan kasus kedua bekerja seperti Quicksort. Perbedaannya terletak pada kasus ketiga,
pada Introsort akan beralih menggunakan Heapsort jika kompleksitasnya mencapai kuadratik
sedangkan pada MyIdeaExperiment sort akan beralih menggunakan Timsort.

1 #include<bits/stdc++.h> 86 void timSort(int arr[], int n) {


2 using namespace std; 87 for (int i = 0; i < n; i+=RUN)
3 const int RUN = 32; 88 InsertionSort(arr,arr+i,
4 89 min((arr+i+31),(arr+n-1)));
5 void insertionSort(int arr[], int left, 90
6 int right) { 91 for (int size = RUN; size <n; size=
7 92 2*size) {
8 for (int i = left + 1; i <= right; 93
9 i++) { 94 for (int left = 0; left < n;left +=
10 int temp = arr[i]; 95 2*size) {
11 int j = i - 1; 96 int mid = left + size - 1;
12 97 int right = min((left + 2*size -
13 while (arr[j] > temp && j >= left) 98 1), (n-1));
14 { 99 merge(arr, left, mid, right);
15 arr[j+1] = arr[j]; 100 }
16 j--; 101 }
17 } 102 }
18 arr[j+1] = temp; 103
19 } 104 int *MedianOfThree(int * a, int * b,
20 } 105 int * c){
21 106
22 void merge(int arr[], int l, int m, 107 if (*a < *b && *b < *c)
23 int r) { 108 return (b);
24 109 if (*a < *c && *c <= *b)
25 int len1 = m - l + 1, len2 = r - m; 110 return (c);
26 int left[len1], right[len2]; 111 if (*b <= *a && *a < *c)
27 112 return (a);
28 for (int i = 0; i < len1; i++) 113 if (*b < *c && *c <= *a)
29 left[i] = arr[l + i]; 114 return (c);
30 115 if (*c <= *a && *a < *b)
31 for (int i = 0; i < len2; i++) 116 return (a);
32 right[i] = arr[m + 1 + i]; 117 if (*c <= *b && *b <= *c)
33 118 return (b);
34 int i = 0; 119 }
35 int j = 0; 120
36 int k = l; 121 void IntrosortUtil(int arr[], int *
37 122 begin, int * end, int depthLimit, int n)
38 while (i < len1 && j < len2) { 123 {
39 if (left[i] <= right[j]){ 124 int size = end - begin;
40 arr[k] = left[i]; 125 printf("%d %d %d %d\n\n", *begin,
41 i++; 126 *end, end - begin, size);
42 } 127
43 128 if (size < RUN)
44 else { 129 {
45 arr[k] = right[j]; 130 InsertionSort(arr, begin, end);
46 j++; 131 return;
47 } 132 }
48 k++; 133
49 } 134 if (depthLimit == 0)
50 135 {
51 while (i < len1){ 136 timSort(arr, n);
52 arr[k] = left[i]; 137 printf("After tim sort");
53 k++; 138 printArray(arr, n);
54 i++; 139 return;
55 } 140 }
56 141
57 while (j < len2) { 142 int * pivot = MedianOfThree(begin,
58 arr[k] = right[j]; 143 begin+size/2, end);
59 k++; 144
60 j++; 145 swapValue(pivot, end);
61 } 146
62 } 147 int * partitionPoint =
63 148 Partition(arr, begin-arr, end-arr);
64 void swapValue(int *a, int *b){ 149
65 int *temp = a; 150 IntrosortUtil(arr, begin,
66 a = b; 151 partitionPoint-1, depthLimit-1, n);
67 b = temp; 152
68 return; 153 IntrosortUtil(arr,partitionPoint+1,
69 } 154 end,depthLimit-1,n);
70 155
71 int* Partition(int arr[], int low, int 156 return;
72 high){ 157 }
73 int pivot = arr[high]; 158
74 int i = (low - 1); 159 void Introsort(int arr[], int *begin,
75 160 int *end, int n) {
76 for (int j = low; j <= high- 1; j++) 161 int depthLimit = 2 * log(end-begin);
77 { 162
78 if (arr[j] <= pivot){ 163 IntrosortUtil(arr, begin, end,
79 i++; 164 depthLimit, n);
80 swap(arr[i], arr[j]); 165
81 } 166 return;
82 } 167 }
83 swap(arr[i + 1], arr[high]);
84 return (arr + i + 1);
85 }
Sumber kode MyIdeaExperiment sort diperoleh dari : implementasi sendiri dan mengambil ide dari :
https://www.geeksforgeeks.org/know-your-sorting-algorithm-set-2-Introsort-cs-sorting-weapon/

Analisis Kompleksitas Algoritma MyIdeaExperiment sort

Baris Cost Penjelasan


5 - 20 c1 O(n2) karena merupakan Insertion sort
22 - 62 c2 O(nlogn) karena merupakan Merge sort
64 - 69 c3 O(1) karena tiap baris hanya melakukan swap 1 kali
71 - 85 c4 O(n) karena penentuan pivot dilakukan dengan mengunjungi tiap elemen di
array yang berukuran n
86 - 102 c5 O(nlogn) karena merupakan Timsort
104 - 119 c6 O(1) karena hanya melakukan conditional statement
121 - 157 c7 Baris ini melakukan pemanggilan fungsi fungsi yang sudah dihitung pada
baris sebelumnya sehingga kompleksitasnya :
O(n2) + O(nlogn) + O(1) + O(1) + O(n) + 2*O(n/2)
159 - 167 c8 Baris ini menghitung depth limit dan juga ini juga melakukan pemanggilan
fungsi fungsi yang sudah dihitung pada baris sebelumnya sehingga
kompleksitasnya :
2*O(log log n) + O(n2) + O(nlogn) + O(1) + O(1) + O(n) + 2*O(n/2)

Kompleksitas :

T(n) = c1*O(1) + c2*O(n2) + c3*O(n) + c4*O(1) + c5*(O(n2) + O(nlogn) + O(1) + O(1) + O(n)
+ 2*O(n/2)) + c6*(2*O(log log n) + O(n2) + O(nlogn) + O(1) + O(1) + O(n) + 2*O(n/2))

Pada penjumlahan di atas terlihat bahwa kompleksitas terbesar adalah O(n2) sehingga dapat
dikatakan bahwa secara default, kompleksitas dari MyIdeaExperiment sort adalah O(n2)
walaupun dapat berubah berubah sesuai kasus seperti Introsort.

T(n) = O(n2)
5. Eksperimen

Eksperimen dilakukan dengan membandingkan running time dari kedua algoritma


sorting, yaitu Introsort dan MyIdeaExperiment sort. Kedua kode algoritma tersebut
diimpelementasikan dengan bahasa C++ sedangkan uji coba running time dilakukan dengan
menggunakan C Time Library. Pada library tersebut terdapat fungsi clock() yang
mengembalikan clock ticks sejak program dijalankan.

Fungsi clock() berada dalam fungsi main() yang merupakan fungsi utama yang
dijalankan dalam bahasa C++. Pada implementasi dengan kedua kode tersebut, dilakukan
pemanggilan fungsi clock() di dua baris berbeda yaitu sebelum dan sesudah pemanggilan
fungsi introsort(). Secara default, clock ticks yang dikembalikan dari kedua baris tersebut lalu
dibagi CLOCKS_PER_SEC menghasilkan running time dalam satuan detik. Namun, agar lebih
presisi diubah dalam milidetik sehingga dikalikan 1000.0 sebelum dibagi dengan
CLOCKS_PER_SEC. Berikut potongan kode dari fungsi main():

1 int main()
2 {
3
4 int arr[] = {};
5 int n = sizeof(arr) / sizeof(arr[0]);
6
7 clock_t start = clock();
8
9 Introsort(arr, arr, arr+n-1);
10
11 clock_t stop = clock();
12
13 double elapsed = (double)(stop - start)
14 * 1000.0 / CLOCKS_PER_SEC;
15
16 printf("Time elapsed in ms: %f",
17 elapsed);
18 printf(" ");
19 return(0);
20 }
Potongan kode fungsi main() diperoleh dari : https://www.geeksforgeeks.org/know-your-sorting-algorithm-set-
2-Introsort-cs-sorting-weapon/

Eksperimen dilakukan pada laptop dengan spesifikasi sistem operasi Ubuntu 16.04.5
LTS, processor Intel i5 – 7200U @3.1 GHz , dan RAM 8GB DDR4.

Eksperimen dilakukan dengan menggunakan 3 jenis array yaitu array dengan elemen
acak, array dengan elemen terurut dalam decreasing order, dan array dengan elemen yang
sama. Ketiga jenis array tersebut dihasilkan dengan program yang diimplementasi sendiri
dengan bahasa Python. Berikut adalah kode untuk menghasilkan array :
1 import random
2
3 list = []
4 #x= 5000
5 #x = 5
6
7 for i in range(0,10000):
8 #x = random.randint(-500000,500000)
9 #x = x - 1
10 list.append(x)
11
12 with open('out.txt', 'w') as f:
13 print(list, file=f)
14
15
Sumber kode diperoleh dari : implementasi sendiri

Hasil dari program tersebut lalu disimpan dalam file bernama “out.txt”. Untuk jumlah input
elemen, digunakan 9 jenis input yang masing – masing berjumlah 100 elemen, 500 elemen,
1000 elemen, 5000 elemen, 10000 elemen, 50000 elemen, 100000 elemen, 500000 elemen,
dan 1000000 elemen. Jumlah input elemen yang digunakan hanya sampai 1000000 elemen
karena ketika menggunakan 5000000 elemen, text editor yang digunakan tidak merespon
(crash).

Eksperimen dilakukan dalam dua tahapan. Tahapan pertama melakukan eksperimen


pada program Introsort dan tahapan kedua melakukan eksperimen pada program
MyIdeaExperiment sort. Hasil eksperimen dicatat pada file spreadsheet. Berikut dilampirkan
tabel hasil eksperimen :
Algoritma Introsort MyIdeaExperiment sort

Jumlah Array Array Array Array Array Array


input
Acak Decreasing Sama Acak Decreasing Sama
elemen
Order Order
100 0,021 0,036 0,031 0,085 0,146 0,092
500 0,065 0,129 0,114 0,375 0,481 0,653
1000 0,143 0,26 0,241 0,697 1,016 0,86
5000 0,775 1,454 1,287 12,061 5,554 4,292
10000 1,771 3,081 2,945 34,529 10,647 10,341
50000 10,226 16,875 16,303 #N/A #N/A #N/A
100000 19,329 36,341 35,845 #N/A #N/A #N/A
500000 127,653 202,018 212,181 #N/A #N/A #N/A
1000000 240,46 376,592 346,554 #N/A #N/A #N/A
Sumber tabel diperoleh dari : Grafik Perbandingan.xlsx
Kedua data pada tabel tersebut lalu diolah menjadi grafik yang merepresentasikan laju
running time dari setiap jumlah input elemen. Berikut adalah grafik dari hasil eksperimen :

Grafik Waktu Running Time Introsort dan MyIdeaExperiment sort

Sumber grafik diperoleh dari : Grafik Perbandingan.xlsx

6. Analisis

Introsort sebagai sebuah Hybrid algorithm menunjukkan performa yang cukup baik.
Dari 9 input yang dilakukan, Introsort baru mulai menunjukkan kenaikan laju yang cukup
signifikan saat jumlah input = 100000. Terlihat saat jumlah input tersebut, running time yang
dibutuhkan adalah 2 kali saat jumlah input = 50000 dan saat jumlah input = 500000 dan
1000000 sudah mencapai 6 kali. Eksperimen ini membuktikan bahwa semakin besar input yang
diberikan maka Introsort akan bekerja seperti Heapsort sesuai dengan yang dijelaskan pada
paper rujukan. Eksperimen juga menunjukkan dari tiga jenis array yang dilakukan pengurutan,
Introsort paling cepat dalam melakukan pengurutan pada array dengan elemen acak
dibandingkan dengan array lain dan hal tersebut konsisten di semua jumlah jenis input.

MyIdeaExperiment sort menunjukkan performa yang cukup buruk karena hanya


mampu melakukan pengurutan sampai jumlah input = 10000. Terlihat pada tabel untuk jumlah
input lain tidak ada data running time yang ditampilkan. Hal ini terjadi karena saat melakukan
eksperimen terjadi segmentation fault. Segmentation fault terjadi saat program mengakses
sejumlah memori yang tidak dialokasikan selama program tersebut berjalan.
MyIdeaExperiment sort yang juga menggunakan Timsort di mana Timsort sendiri sebenarnya
sudah merupakan Hybrid algorithm karena terdiri dari Insertion sort dan Merge sort sedangkan
Mergesort memiliki space complexity O(n). Sehingga, karena dua hal tersebut yaitu redundansi
penggunaan beberapa algoritma dan space complexity O(n) terjadilah segmentation fault.

7. Kesimpulan

MyIdeaExperiment sort sebagai algoritma yang diimplementasi sendiri ternyata tidak


lebih baik dari Introsort. Hasil eksperimen menunjukkan bahwa penggunaan Hybrid algorithm
untuk dijadikan Hybrid algorithm baru yang diperkirakan membuat performa semakin baik
justru sebaliknya membuat performa menjadi buruk karena adanya redundansi penggunaan
beberapa algoritma. Selain itu, jika memang dibutuhkan sebuah Hybrid algorithm baru, jangan
hanya melihat dari sisi time complexity saja namun juga space complexity untuk menghindari
segmentation fault.
Referensi :

Allain, Alex. “Debugging Segmentation Faults and Pointer Problems.” Writing Secure Code in C
- Cprogramming.com, www.cprogramming.com/debugging/segfaults.html.

Auger, Nicolas, et al. On the Worst-Case Complexity of TimSort. 2012,


drops.dagstuhl.de/opus/volltexte/2018/9467/pdf/LIPIcs-ESA-2018-4.pdf.

Belwariar, Rachit. “Know Your Sorting Algorithm | Set 2 (Introsort- C 's Sorting

Weapon).” GeeksforGeeks, www.geeksforgeeks.org/know-your-sorting-algorithm-set-2-

Introsort-cs-sorting-weapon/.

“Clock.” Cplusplus.com, www.cplusplus.com/reference/ctime/clock/.

Kumar, Aditya. “TimSort.” GeeksforGeeks, www.geeksforgeeks.org/Timsort.

Malek, Miroslaw, and Ahmed Azfar Moin. A Hybrid Technique for Deterministic Algorithms

with a Shortest Path Example. 25 Apr. 1994,

pdfs.semanticscholar.org/813e/964caabcd0dc60a0926e89f7adca1e91b668.pdf.

Fikri, Muhammad Fauzan. “Grafik Perbandingan.”

Musser, David R. Introspective Sorting and Selection Algorithms. 1997,

citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.14.5196&rep=rep1&type=pdf.

“Overview of Merge Sort.” Khan Academy, Khan Academy,

www.khanacademy.org/computing/computer-science/algorithms/merge-sort/a/overview-of-

merge-sort.

Anda mungkin juga menyukai