Menghitung Inversion Pada Barisan Dengan Menggunakan Modifikasi Bubble Sort, Insertion Sort, dan Merge Sort M Iqbal Tawakal - 0706271954 Abstract Paper ini akan menjelaskan mengenai cara menghitung inversion dengan menggunakan beberapa algoritma sorting yang dimodifikasi sehingga bisa untuk menghitung jumlah inversion di dalam sebuah baris bilangan. Algoritma sorting yang dimodifikasi adalah bubble sort, insertion sort, dan merge sort. Ketiga algoritma itu akan diujikan untuk menghitung jumlah inversion pada beberapa list dengan panjang yang berbeda-beda untuk kemudian dibandingkan sehingga dapat diketahui algoritma terbaik. Latar Belakang Inversion adalah kondisi pada sebuah barisan bilangan yang terjadi ketika sebuah bilangan yang letaknya lebih kiri namun memiliki nilai lebih besar dari bilangan di sebelah kanannya. Misalkan A[1..n] adalah barisan/list dari n buah angka yang berbeda, jika i < j dan A[i] > A[j], maka antara A[i] dengan A[j] terjadi inversion. Besarnya nilai inversion bisa menjadi indikator seberapa acaknya sebuah baris bilangan. Jumlah inversion memiliki nilai maksimal pada sebuah baris bilangan ketika barisan tersebut terurut terbalik, dan nilainya nol ketika barisan tersebut terurut. Contoh: 2 4 3 5 1 Pada barisan bilangan di atas, terdapat 5 buah inversion. Inversion terjadi pada pasangan bilangan (2,1), (4,3), (4,1), (3,1), dan (5,1). Definisi Masalah Inputnya adalah sebuah barisan bilangan yang elemen-elemennya unik satu sama lain. Output adalah sebuah bilangan jumlah inversion yang terjadi pada barisan bilangan tersebut. Penjelasan Algoritma Untuk menghitung inversion pada paper ini algoritma yang digunakan adalah modifikasi dari algoritma bubble sort, insertion sort, dan merge sort. Modifikasi yang dilakukan pada bubble sort adalah ditambahkan sebuah variabel untuk menghitung berapa kali dilakukan pertukaran, karena 1
jika terjadi pertukaran ketika sorting maka dapat dipastikan kalau itu adalah kondisi inversion. Pseudo code-nya INV-BUBBLE-SORT (A) 1 inv := 0 2 FOR i:= 0 TO length[a]-1 3 DO FOR j:= 0 TO length[a]-2 4 DO IF A[j] > A[j+1] THEN 5 temp := A[j] 6 A[j] := A[j+1] 7 A[j+1] := temp 8 inv := inv + 1 9 END 10 END 11 return inv Modifikasi yang dilakukan pada insertion sort adalah menghitung sejauh mana setiap nilai digeser ke kanan ketika melakukan insertion, karena jika suatu elemen masih digeser ke kanan berarti terjadi kondisi inversion di sana. Pseudo code-nya INV-INSERTION-SORT(A) 1 inv := 0; 2 FOR j := 2 TO length[a] 3 DO key := A[j] 4 i := j-1; 5 WHILE i > 0 and A[i] > key 6 DO A[i+1] := A[i]; 7 i := i-1; 8 inv := inv + 1; 9 END 10 A[i+1] := key 11 END 12 return inv; Jika dibandingkan algoritma aslinya, pada modifikasi ini cukup ditambahkan increment ke sebuah variabel setiap terjadi pergeseran untuk meletakkan elemen yang akan dimasukkan ke dalam sub barisan sebelah kiri yang sudah terurut. Modifikasi yang dilakukan pada merge sort adalah pada bagian merge-nya. Letak perubahannya adalah ketika dilakukan perbandingan antara nilai yang ditunjuk oleh pointer kiri yang menunjuk elemen terkecil yang masih ada di sublist kiri dengan pointer kanan yang menunjuk elemen terkecil yang ada di sublist kanan. Jika nilai yang ditunjuk pointer kiri lebih besar dari yang ditunjuk pointer kanan, maka terjadi inversion. Nilai inversion-nya ditambah sebanyak 1 plus semua sisa elemen di sebelah kanan sublist kiri. Pseudo code-nya INV-MERGE-SORT(A, p, r) 1 if p < r 2 then q <- floor (p+r)/2 3 a := INV-MERGE-SORT(A,p,q) 4 b := INV-MERGE-SORT(A,q+1,r) 5 c := INV-MERGE(A,p,q,r) 6 return a+b+c 7 else 8 return 0 INV-MERGE(A, p, q, r) 1 n1 <- q-p+1; n2 <- r-q; inv <- 0 2 //create L[1..n1+1] and R[1..n2+1] 3 for i <- 1 to n1 do L[i] <- A[p+i-1] 4 for j <- 1 to n2 do R[j] <- A[q+j] 5 L[n1+1] <- inf; R[n2+1] <- inf 6 i <- 1; j <- 1 7 for k <- p to r 8 do if L[i] < R[j] 9 then A[k] <- L[i] 10 i <- i + 1 11 else A[k] <- R[j] 12 j <-j + 1 13 inv <- inv + (length(l)-i-1) 14 end 2
15 return inv Jika dibandingkan dengan algoritma aslinya, algoritma modifikasi ini ditambahkan baris untuk menambah nilai variabel inv jika terjadi inversion dengan sebanyak elemen yang masih terdapat di sublist kiri. Karena setelah pemanggilan merge-sort, antar elemen dalam sublist yang sama pasti terurut, maka semua elemen yang ada di sebelah kanan elemen yang sekarang ditunjuk oleh pointer kiri nilainya pasti lebih besar dibandingkan elemen yang sedang ditunjuk itu. Akibatnya, pasti terjadi inversion untuk semua elemen di kanan. Karena itu cukup ditambahkan sebanyak elemen yang ada di sublist kiri, tidak perlu diperiksa satu-satu perelemennya. Percobaan Untuk percobaan perbandingan performa, semua algoritma akan diuji dengan beberapa test case. Inputnya adalah barisan bilangan yang semua elemennya unik dengan panjang bervariasi mulai dari 100, 1000, 10000, dan 100000. Contoh input dengan panjang 100: 96, 90, 10, 20, 67, 28, 25, 4, 84, 48, 93, 19, 54, 3, 14, 11, 2, 59, 92, 22, 24, 51, 70, 31, 77, 64, 99, 1, 23, 72, 29, 85, 6, 91, 98, 61, 73, 38, 62, 36, 81, 58, 9, 68, 35, 71, 42, 76, 7, 66, 78, 16, 74, 63, 52, 53, 95, 75, 45, 17, 30, 86, 15, 21, 8, 83, 12, 27, 39, 94, 37, 65, 82, 47, 60, 18, 49, 50, 87, 32, 56, 33, 13, 40, 88, 41, 89, 44, 79, 97, 100, 43, 34, 26, 46, 57, 80, 55, 69, 5 Jumlah inversion pada barisan tersebut adalah 2315. Hasil percobaan dapat dilihat di tabel. Waktu dalam sekon. n Bubble Insertion Merge 1000 0.002371 0.000633 0.0008269 10000 0.02566 0.00736 0.006524 100000 19.58041 0.214274 0.011369 1000000 201 22.16636 0.152429 Analisis Dari hasil percobaan penggunaan beberapa algoritma sorting yang sudah dimodifikasi untuk menghitung inversion, terlihat bahwa waktunya mengikuti kompleksitas dari algoritma sorting-nya. Bubble sort yang kompleksitas waktunya O(n 2 ) performanya kalah dibandingkan insertion sort yang juga sama-sama O(n 2 ) namun memiliki implementasi lebih efisien. Tetapi keduanya dibatasi batasan yang dimiliki oleh algoritma sorting by comparison yang perbandingannya dilakukan side by side (dengan angka disebelahnya). Sedangkan merge sort tidak terkena batasan itu, dan kompleksitasnya lebih bagus yaitu O(nlogn). Sehingga untuk perhitungan inversion dengan memakai merge sort jauh lebih cepat dibandingkan algoritma sorting lainnya, terutama untuk jumlah data yang banyak. Hal lain yang membuat merge sort lebih cepat dalam hal menghitung inversion adalah tidak perlu dibandingkan dengan semua elemen untuk mengetahui apakah terjadi inversion. Kesimpulan Inversion dapat dihitung dengan melakukan modifikasi terhadap beberapa algoritma sorting, dan kompleksitas penghitungannya mengikuti dari algoritma sorting mana 3
yang dipakai. Dalam paper ini, algoritma merge sort mengungguli algoritma bubble sort dan insertion sort dalam hal menghitung inversion. Referensi Cormen, Thomas H., Leiserson, Charles E., and Rivest, Ronald L.: Introduction To Algorithm, Second Edition. MIT Press, Massachusetts (2001). Lampiran - Source Code Program 4
import java.util.list; import java.util.arraylist; import java.util.date; public class DAA { public static void main(string[] args) int[] testcase = 100, 1000, 10000, 100000; for(int i=0; i<testcase.length; i++) System.out.println("Testcase "+(i+1)+": "+testcase[i]); int[] li = generatelist(testcase[i]); System.out.println("Bubble Sort"); long start = System.nanoTime(); System.out.println(invbubblesort(li.clone())); long end = System.nanoTime(); System.out.println("Waktunya "+(end-start)); System.out.println("Insertion Sort"); start = System.nanoTime(); System.out.println(invinsertionsort(li.clone())); end = System.nanoTime(); System.out.println("Waktunya "+(end-start)); System.out.println("Merge Sort"); start = System.nanoTime(); System.out.println(invmergesort(li.clone())); end = System.nanoTime(); System.out.println("Waktunya "+(end-start)); public static void cetak(int[] li) for(int i=0; i<li.length; i++) System.out.print(li[i]+", "); System.out.println(); public static int[] generatelist(int n) int[] res = new int[n]; List<Integer> list = new ArrayList<Integer>(); for(int i=1; i<=n; i++) list.add(i); 5
for(int i=0; i<n; i++) int rand = (int)(math.random()*list.size()); res[i] = list.remove(rand); return res; public static int invbubblesort(int[] A) int inversion = 0; for(int i=0; i<a.length; i++) for(int j=0; j<a.length-1; j++) if(a[j] > A[j+1]) int temp = A[j]; A[j] = A[j+1]; A[j+1] = temp; inversion++; return inversion; public static int invinsertionsort(int[] A) int inversion = 0; for(int j=1; j<a.length; j++) int key = A[j]; int i = j-1; while(i>=0 && A[i] > key) A[i+1] = A[i]; i--; inversion++; A[i+1] = key; return inversion; public static int invmergesort(int[] A) return mergesort(a,0,a.length-1); public static int mergesort(int[] A, int p, int r) if(p < r) int q = (p+r)/2; 6
int a = mergesort(a,p,q); int b = mergesort(a,q+1,r); int c = merge(a,p,q,r); return a+b+c; return 0; public static int merge(int[] A, int p, int q, int r) int n1 = q-p+1, n2 = r-q; int inversion = 0; int[] L = new int[n1+2]; int[] R = new int[n2+2]; for(int i=1; i<=n1; i++) L[i] = A[p+i-1]; for(int j=1; j<=n2; j++) R[j] = A[q+j]; L[n1+1] = Integer.MAX_VALUE; R[n2+1] = Integer.MAX_VALUE; int i = 1, j = 1; for(int k=p; k<=r; k++) if(l[i] < R[j]) A[k] = L[i]; i++; else A[k] = R[j]; j++; int temp = L.length-i-1; inversion += temp; return inversion; } 7