REKURSI Fungsi Rekursi Fungsi Rekursi adalah fungsi yang memanggil dirinya sendiri Rekursi dapat digunakan sebagai alternatif dari iterasi/perulangan (looping) dari iterasi/perulangan (looping) Algoritma Rekursi Algoritma rekursif secara umum dapat dituliskan terdiri dari if statement sebagai berikut: if this is a simple case solve it else redefine the problem using recursion (recursive step) Simple case & recursive step Simple case (base case) adalah kondisi untuk menghentikan rekursi Recursive step adalah kondisi untuk melakukan rekursi melakukan rekursi int multiply(int m, int n) { int ans; Contoh1: Rekursi untuk Perkalian 2 Bilangan if (n == 1) ans = m; /* simple case */ else ans = m + multiply (m, n - 1);/* recursive step */ return (ans); } int count (char ch, const char *str) { int ans; if (str[0] == \0) /* simple case */ Contoh2: Menghitung jumlah Karakter dalam suatu String if (str[0] == \0) /* simple case */ ans = 0; else /* redefine problem using recursion */ if (ch == str[0]) /* first character must be counted */ ans = 1 + count (ch, &str[1]); else /* first character is not counted */ ans = count(ch, &str[1]); return (ans); } Penelusuran (tracing) pada Fungsi Rekursi Fungsi Rekursi Penelusuran fungsi rekusi yang mengembalikan suatu nilai Fungsi Rekursi untuk Perkalian 2 buah bilangan int multiply(int m, int n) { int ans; int ans; if (n == 1) ans = m; /* simple case */ else ans = m + multiply (m, n - 1); /* recursive step */ return (ans); } Penelusuran fungsi void yang rekursi parameter and local Variable Stacks stack adalah Struktur data dimana data yang terkhir masuk adalah data yang akan diproses terlebih dahulu. Stack biasanya dimplementasikan dengan Stack biasanya dimplementasikan dengan menggunakan sebuah array. dalam stack kita bisa menambah data dengan perintah operasi push dan menghapus data dengan menggunakan perintah operasi pop Fungsi Rekursi pada Matematika Banyak fungsi matematika yang dapat didefinisikan dengan rekursi. Contoh: fungsi faktorial dari n (n!), dapat didefinisikan secara iteratif : 0! Adalah 1 n! Adalah n x (n-1)!, untuk n>0 n! Adalah n x (n-1)!, untuk n>0 Misal: 4! Adalah 4 x 3!, yang artinya 4 x 3 x 2 x 1, atau 24 Fungsi rekursi untuk faktorial Program : //menghitung n! Menggunakan definisi rekursi //pre : n>=0 Int factorial (int n) { int ans; if (n == 0) ans = 1; /*simple case*/ else ans = n * factorial (n-1); /*recursive step*/ return(ans); } Penulusuran dari fact= factorial(3); return(ans) n = 3 ans=3 * factorial (2) Fact=factorial(3); 2 6 return(ans) n = 2 ans=2 * factorial (1) return(ans) n = 0 ans=1 return(ans) n = 1 ans=1 * factorial (0) 1 1 2 Iteratif untuk faktorial Program : //menghitung n! Menggunakan iteratif //pre : n>=0 Int factorial (int n) { int i; /*variabel lokal */ Product =1; Product =1; //menghitung perkalian n x (n-1) x (n-2) x ... X 2 x 1 For (i=n; i>1; --i) { Product=product * i; } //Mengembalikan kembalian fungsi Return(product); } Persamaan dan perbedaan iteratif & rekursi adalah Persamaan Sama-sama merupakan bentuk perulangan Dilakukan Perbedaan Pada rekursi, dikenal adanya istilah recursive step Sedangkan pada Dilakukan pengecekan kondisi terlebih dahulu sebelum mengulang Sedangkan pada iteratif ada decrement Kelebihan dan kelemahan rekursi : Kelebihan solusi sangatlah efisien dapat memecahkan Kelemahan sulit dipahami perlu stack besar (stack overrun) dapat memecahkan masalah yang sulit dengan tahapan yang mudah dan singkat 10.4 Fungsi Rekursi dengan Parameter Array dan String 10.5 Pemecahan Masalah dengan Rekursi 10.6 Studi Kasus Klasik dengan Rekursi: Tower of Hanoi Fungsi Rekursi dengan Parameter Array dan String Study Kasus: Menemukan Huruf Kapital dalam string Analisa input : String (str) output : Huruf kapital (caps) penyelesaian: if (str[0] == '\0') caps[0] = '\0'; else{ else{ if (isupper(str[0])) sprintf(caps, "%c%s", str[0],find_caps(restcaps, &str[1])); else find_caps(caps, &str[1]);} return (caps); Desain 1. Jika string kosong, maka string kosong tersebut akan disimpan dalam caps. 2. Jika huruf pertama dari string adalah huruf kapital, simpan huruf kapital dalam caps dan sisanya dalam str kembali. 3. Jika huruf pertama kapital, simpan sisanya dalam str. 3. Jika huruf pertama kapital, simpan sisanya dalam str. Implementasi #include<stdio.h> #include<ctype.h> #define STRSIZ 50 char *find_caps(char *caps, //output-string of all caps found in str const char*str); //input-string of from which to caps extract caps void main() { char caps[STRSIZ]; printf("Capital letters in JoJo are %s\n",find_caps(caps, "JoJo")); printf("Capital letters in JoJo are %s\n",find_caps(caps, "JoJo")); } char *find_caps(char *caps, const char*str) { char restcaps[STRSIZ]; //caps from reststr if (str[0] == '\0') caps[0] = '\0'; //no lettrers in str => no caps in str else{ if (isupper(str[0])) sprintf(caps, "%c%s", str[0],find_caps(restcaps, &str[1])); else find_caps(caps, &str[1]);} return (caps); } Penelusuran pemanggilan untuk Fungsi Rekursi Menemukan Huruf Kapital 10.5 Pemecahan Masalah dengan Rekursi Karena di dalam C tidak ada representasi dari himpunan struktur data, kita akan mengimplementasikan operasi pada himpunan dengan string sebagai himpunan. Study Kasus: Operasi pada Himpunan
Menara Hanoi adalah problem di mana kita harus memindahkan
balok yang mempunyai perbedaan ukuran dari suatu menara (tower) ke menara lainnya. Studi Kasus Klasik dengan Rekursi : Menara Hanoi Problem Memindahkan n balok dari menara A ke menara C A B C menara A ke menara C menggunakan menara B bila dibutuhkan. Hal yang harus dicermati : Hanya satu buah balok saja yang dapat dipindahkan dalam satu waktu Balok yang lebih besar tidak boleh diletakkan di atas balok yang lebih kecil Solusi dari menara hanoi terdiri dari daftar pemindahan balok secara individual. Kita membutuhkan fungsi rekursi yang dapat digunakan untuk mencetak instruksi untuk memindahkan balok- balok dari menara awal ke menara yang dituju menggunakan menara ketiga sebagai perantara. Data yang dibutuhkan : Analisis Data yang dibutuhkan : Problem inputs int n /* jumlah balok yang dipindahkan */ Char awal /* menara awal */ Char akhir /* menara akhir atau menara yang dituju */ Char mid /* menara sebagai perantara */ Problem Outputs Daftar perpindahan balok Algorithma 1. Jika n adalah 1 maka 2. Pindahkan balok satu dari menara awal ke menara akhir if (n==1) printf("pindahkan balok ke-%d dari %c ke %c\n",n,awal,akhir); else / jika tidak 3. Pindahkan n-1 disks dari menara awal ke menara perantara dengan menggunakan menara akhir 4. Pindahkan balok n dari menara awal ke menara akhir Desain 4. Pindahkan balok n dari menara awal ke menara akhir 5. Pindahkan n-1 balok dari menara perantara ke menara akhir menggunakan menara awal. masuk rekursi else { menara(awal,mid,akhir,n-1); printf("pindahkan balok ke-%d dari %c ke %c\n",n,awal,akhir); menara(awal,mid,akhir,n-1); } 6. Menghitung banyaknya perpindahan yang dibutuhkan jum=pow(2,n)-1; 7. Menampilkan banyaknya perpindahan printf("\n>>jumlah perpindahannya adalah : %d", jum); #include<stdio.h> #include<math.h> #include<conio.h> int n; char awal='A'; char akhir='C'; char mid='B'; void menara(char awal,char akhir,char mid,int n) Implementasi Menara Hanoi { if (n==1) printf("pindahkan balok ke-%d dari %c ke %c\n",n,awal,akhir); else { menara(awal,mid,akhir,n-1); printf("pindahkan balok ke-%d dari %c ke %c\n",n,awal,akhir); menara(awal,mid,akhir,n-1); } } void main() { int jum; printf ("Masukkan banyak balok n : "); scanf ("%d",&n); menara(awal,akhir,mid,n); jum=pow(2,n)-1; printf("\n>>jumlah perpindahannya adalah : %d", jum); printf("\n\n\n"); } #include <stdio.h> #include <string.h> #include <ctype.h> #define SETSIZE 65 #define TRUE 1 #define FALSE 0 int is_empty (const char *set); int is_element (char ele, const char *set); int is_set (const char *set); int is_subset (const char *sub,const char *set); char *set_union (char *result, const char *set1, const char *set2); char *set_union (char *result, const char *set1, const char *set2); void print_with_commas (const char *str); void print_set (const char *set); char *get_set (char *set); int main(void) { char ele, set_one[SETSIZE], set_two[SETSIZE], set_three[SETSIZE]; printf ("A set is entered as a string of up to %d letters\n", SETSIZE-3); printf ("and digits enclosed in {}"); printf ("for example, {a, b, c} is entered as {abc}\n"); printf ("enter a set to test validation function>"); get_set (set_one); putchar ('\n'); print_set (set_one); if (is_set(set_one)) printf ("is a valid set\n"); else printf ("is invalid\n"); printf ("Enter a single character, a space, and a set>"); while (isspace (ele = getchar())) get_set (set_one); printf ("\n%c", ele); if (is_element(ele, set_one)) printf ("is an element of"); printf ("is an element of"); else printf ("is not an element of"); printf ("\nEntered two sets to test set_union>"); get_set (set_one); get_set (set_two); printf ("\nThe union of"); print_set (set_one); printf (" and "); print_set (set_two); printf ("is"); print_set (set_union(set_three, set_one, set_two)); putchar ('\n'); return (0); } int is_empty (const char *set) { return (set [0] == '\0'); } int is_element(char ele, const char *set) { int ans; if (is_empty(set)) if (is_empty(set)) ans = FALSE; else if (set [0] == ele) ans = TRUE; else ans = is_element (ele, &set[1]); return (ans); } int is_set (const char *set) { int ans; if (is_empty(set)) ans = TRUE; else if (is_element (set [0], &set [1])) ans = FALSE; else ans = is_set (&set[1]); return (ans); } int is_subset (const char *sub, const char *set) { int ans; if (is_empty(sub)) ans = TRUE; else if (!is_element (sub [0], set)) ans = FALSE; else ans = is_subset (&sub[1], set); return (ans); } char *set_union (char *result, const char *set1, const char *set2) { char temp [SETSIZE]; if (is_empty(set1)) strcpy (result, set2); else if (is_element (set1 [0], set2)) set_union (result, &set1 [1], set2); else sprintf (result, "%c%s", set1 [0], set_union (temp, &set1 [1], set2)); return (result); } void print_with_commas (const char *str) { if (strlen (str)== 1) { putchar (str [0]); } else { printf ("%c, ", str [0]); print_with_commas (&str[1]); } } void print_set (const char *set) { putchar ('{'); if (!is_empty(set)) print_with_commas(set); putchar('}'); } char *get_set (char *set) { char inset [SETSIZE]; scanf ("%s", inset); scanf ("%s", inset); strncpy (set, &inset[1], strlen (inset)-2); set [strlen (inset) - 2] = '\0'; return (set); } Referensi Bab 10, Recursion, Problem Solving and Program Design in C, Jeri R. Hanly dan Elliot B. Koffman, Addison Wesley, 2002