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 dimodi-fikasi sehingga bisa untuk menghitung jum-lah inversion di dalam sebuah baris bi-langan. Algoritma sorting yang dimod-ifikasi adalah bubble sort, insertion sort, dan merge sort. Ketiga algoritma itu akan diujikan untuk menghitung jumlah inversion pada beberapa list dengan pan-jang yang berbeda-beda untuk kemudian dibandingkan sehingga dapat diketahui al-goritma terbaik.
Latar Belakang
Inversion adalah kondisi pada sebuah barisan bilangan yang terjadi ketika se-buah bilangan yang letaknya lebih kiri na-mun memiliki nilai lebih besar dari bilan-gan 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 an-tara A[i] dengan A[j] terjadi inversion. Be-sarnya 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 jum-lah inversion yang terjadi pada barisan bi-langan tersebut.
Penjelasan Algoritma
Untuk menghitung inversion pada paper ini algoritma yang digunakan adalah mod-ifikasi dari algoritma bubble sort, insertion sort, dan merge sort. Modifikasi yang di-lakukan pada bubble sort adalah ditam-bahkan sebuah variabel untuk menghitung berapa kali dilakukan pertukaran, karena
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 in-sertion, karena jika suatu elemen masih di-geser ke kanan berarti terjadi kondisi inver-sion 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 incre-ment ke sebuah variabel setiap terjadi pergeseran untuk meletakkan elemen yang
akan dimasukkan ke dalam sub barisan se-belah kiri yang sudah terurut.
Modifikasi yang dilakukan pada merge sort adalah pada bagian merge-nya. Letak perubahannya adalah ketika dilakukan per-bandingan antara nilai yang ditunjuk oleh pointer kiri yang menunjuk elemen terke-cil yang masih ada di sublist kiri dengan pointer kanan yang menunjuk elemen terke-cil 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 se-banyak 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
15 return inv
Jika dibandingkan dengan algoritma aslinya, algoritma modifikasi ini dita-mbahkan 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. Ak-ibatnya, 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 beber-apa test case. Inputnya adalah barisan bi-langan 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 al-goritma sorting-nya. Bubble sort yang kompleksitas waktunya O(n2) performanya kalah dibandingkan insertion sort yang juga sama-sama O(n2) namun memiliki
imple-mentasi lebih efisien. Tetapi keduanya di-batasi batasan yang dimiliki oleh algoritma sorting by comparison yang perbandingan-nya dilakukan side by side (dengan angka disebelahnya). Sedangkan merge sort tidak terkena batasan itu, dan kompleksitasnya lebih bagus yaitu O(nlogn). Sehingga un-tuk 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 penghitungan-nya mengikuti dari algoritma sorting mana
yang dipakai. Dalam paper ini, algoritma merge sort mengungguli algoritma bubble sort dan insertion sort dalam hal menghi-tung inversion.
Referensi
Cormen, Thomas H., Leiserson, Charles E., and Rivest, Ronald L.: Introduction To Al-gorithm, Second Edition. MIT Press, Mas-sachusetts (2001).
Lampiran - Source Code
Program
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++)
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 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; }