Masukkan Password
33 Recursion in Dart | Dart Tutorial #32
Materi kali ini membahas recursion (rekursi) dalam Dart. Konsep ini memang sedikit lebih menantang dibanding for, while, atau function biasa, karena sebuah function memanggil dirinya sendiri.
Kita akan membahasnya pelan-pelan, terutama bagian yang biasanya membuat pemula bingung: bagaimana function bisa memanggil dirinya sendiri, kapan berhenti, dan bagaimana factorial(5) bisa menjadi 120.
1. Apa Itu Recursion?
Recursion adalah teknik ketika sebuah function memanggil dirinya sendiri.
Contoh sederhana:
void hello() {
hello();
}
Perhatikan:
void hello() {
hello();
}
Di dalam hello(), kita memanggil:
hello();
Artinya:
hello()
↓
memanggil hello()
↓
memanggil hello()
↓
memanggil hello()
↓
dan seterusnya...
Function yang melakukan hal seperti ini disebut recursive function.
2. Tapi Bukankah Itu Akan Berjalan Selamanya?
Betul!
Kalau kita membuat:
void hello() {
hello();
}
tidak ada kondisi yang membuat recursion berhenti.
Akibatnya function akan terus memanggil dirinya sendiri sampai program mengalami error, biasanya berupa stack overflow.
Karena itu, setiap recursion yang benar biasanya mempunyai dua bagian penting:
1. Base case
2. Recursive case
Ini adalah dua konsep terpenting dalam recursion.
3. Base Case
Base case adalah kondisi yang memberitahu recursion:
“Sudah cukup. Jangan panggil function lagi.”
Contohnya:
int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
Perhatikan:
if (n == 1) {
return 1;
}
Ini adalah base case.
Ketika:
n = 1
function berhenti melakukan recursion.
4. Recursive Case
Bagian ini:
return n * factorial(n - 1);
adalah recursive case.
Kenapa?
Karena function:
factorial
memanggil dirinya sendiri:
factorial(n - 1)
Jadi:
int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
mempunyai:
Base case:
n == 1
Recursive case:
n * factorial(n - 1)
5. Memahami Factorial Terlebih Dahulu
Sebelum masuk ke recursion, kita harus memahami factorial.
Factorial ditulis menggunakan tanda:
!
Contoh:
5!
dibaca:
“5 factorial”
Artinya:
5! = 5 × 4 × 3 × 2 × 1
Hasilnya:
5! = 120
Contoh lainnya:
1! = 1
2! = 2 × 1 = 2
3! = 3 × 2 × 1 = 6
4! = 4 × 3 × 2 × 1 = 24
5! = 5 × 4 × 3 × 2 × 1 = 120
6. Kenapa Factorial Cocok untuk Recursion?
Ini bagian yang sangat penting.
Perhatikan:
5! = 5 × 4 × 3 × 2 × 1
Kita bisa memecahnya:
5! = 5 × 4!
Kemudian:
4! = 4 × 3!
Kemudian:
3! = 3 × 2!
Kemudian:
2! = 2 × 1!
Dan akhirnya:
1! = 1
Perhatikan polanya:
5! = 5 × 4!
4! = 4 × 3!
3! = 3 × 2!
2! = 2 × 1!
Artinya:
factorial(n) = n × factorial(n - 1)
Nah!
Itulah yang membuat factorial sangat cocok diselesaikan dengan recursion.
7. Function Recursive-nya
Sekarang kita tulis dalam Dart:
int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
Mari kita baca satu per satu.
Baris pertama
int factorial(int n)
Artinya kita membuat function:
factorial
yang:
- menerima satu parameter
n - parameter tersebut bertipe
int - mengembalikan
int
Bagian berikutnya
if (n == 1) {
return 1;
}
Artinya:
Kalau
nsudah mencapai 1, berhenti.
Ini base case.
Kemudian:
return n * factorial(n - 1);
Artinya:
Kalikan
ndengan hasil factorial darin - 1.
Ini recursive case.
8. Mari Kita Jalankan factorial(5)
Ini bagian yang paling penting.
Misalnya:
int result = factorial(5);
Jangan langsung berpikir hasilnya 120.
Kita ikuti prosesnya.
Langkah 1
Kita memanggil:
factorial(5)
Karena:
5 != 1
maka:
return 5 * factorial(4);
Jadi sekarang kita perlu mengetahui:
factorial(4)
Langkah 2
Sekarang:
factorial(4)
Karena:
4 != 1
maka:
4 * factorial(3)
Langkah 3
Sekarang:
factorial(3)
menjadi:
3 * factorial(2)
Langkah 4
Sekarang:
factorial(2)
menjadi:
2 * factorial(1)
Langkah 5
Sekarang:
factorial(1)
Nah, kondisi:
if (n == 1)
terpenuhi.
Maka:
return 1;
Recursion berhenti.
9. Setelah Mencapai Base Case, Apa yang Terjadi?
Ini bagian yang sering membuat pemula bingung.
Kita tadi turun:
factorial(5)
↓
5 × factorial(4)
↓
5 × 4 × factorial(3)
↓
5 × 4 × 3 × factorial(2)
↓
5 × 4 × 3 × 2 × factorial(1)
↓
5 × 4 × 3 × 2 × 1
Sekarang hasilnya dikembalikan naik kembali.
Mulai dari:
factorial(1) = 1
Kemudian:
factorial(2)
= 2 × factorial(1)
= 2 × 1
= 2
Kemudian:
factorial(3)
= 3 × factorial(2)
= 3 × 2
= 6
Kemudian:
factorial(4)
= 4 × factorial(3)
= 4 × 6
= 24
Kemudian:
factorial(5)
= 5 × factorial(4)
= 5 × 24
= 120
Jadi:
120
dikembalikan ke:
int result = factorial(5);
10. Visualisasi Recursion
Kamu bisa membayangkannya seperti ini:
factorial(5)
│
├── 5 × factorial(4)
│ │
│ ├── 4 × factorial(3)
│ │ │
│ │ ├── 3 × factorial(2)
│ │ │ │
│ │ │ ├── 2 × factorial(1)
│ │ │ │ │
│ │ │ │ └── 1
│ │ │ │
│ │ │ └── 2 × 1 = 2
│ │ │
│ │ └── 3 × 2 = 6
│ │
│ └── 4 × 6 = 24
│
└── 5 × 24 = 120
Jadi recursion mempunyai dua arah:
TURUN
↓
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
↓
BASE CASE
↓
NAIK
↓
hasil dihitung
11. Kenapa Function Bisa Memanggil Dirinya Sendiri?
Mungkin kamu berpikir:
“Kok bisa? Bukannya function harus sudah selesai dulu sebelum dipanggil lagi?”
Tidak.
Ketika sebuah function dipanggil, Dart menyimpan informasi mengenai pemanggilan tersebut di call stack.
Misalnya:
factorial(5)
memanggil:
factorial(4)
Maka pemanggilan factorial(5) belum selesai.
Dart menyimpan kondisi tersebut dan menjalankan factorial(4).
Kemudian factorial(4) memanggil:
factorial(3)
dan seterusnya.
Secara sederhana:
Stack
factorial(5) ← menunggu factorial(4)
factorial(4) ← menunggu factorial(3)
factorial(3) ← menunggu factorial(2)
factorial(2) ← menunggu factorial(1)
factorial(1) ← selesai
Setelah factorial(1) selesai, hasilnya digunakan oleh function yang berada di bawahnya.
12. Analogi Menumpuk Piring
Bayangkan kamu sedang menumpuk piring.
Kamu punya:
Piring 5
Piring 4
Piring 3
Piring 2
Piring 1
Kamu terus menambahkan piring sampai mencapai kondisi:
“Sudah cukup.”
Kemudian kamu mulai mengambil dari atas.
Recursion mirip seperti itu:
Tambah pemanggilan
↓
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
↓
STOP
↓
Kembali satu per satu
Inilah gambaran sederhana call stack.
13. Base Case Sangat Penting
Kesalahan paling berbahaya dalam recursion adalah lupa membuat kondisi berhenti.
Misalnya:
int factorial(int n) {
return n * factorial(n - 1);
}
Apa masalahnya?
Tidak ada:
if (n == 1)
Maka:
factorial(5)
↓
factorial(4)
↓
factorial(3)
↓
factorial(2)
↓
factorial(1)
↓
factorial(0)
↓
factorial(-1)
↓
factorial(-2)
↓
...
Tidak pernah berhenti.
Akhirnya bisa terjadi:
Stack Overflow
Jadi setiap kali kamu membuat recursive function, tanyakan:
“Kapan recursion ini berhenti?”
Kalau jawabannya tidak ada, kemungkinan besar ada masalah.
14. Ada Dua Hal yang Harus Ada dalam Recursion
Hampir setiap recursive function yang baik mempunyai:
1. Base case
Kondisi berhenti.
if (n == 1) {
return 1;
}
2. Recursive case
Function memanggil dirinya sendiri dengan masalah yang lebih kecil/dekat dengan base case.
return n * factorial(n - 1);
Jadi pola umumnya:
returnType function(parameter) {
if (baseCondition) {
return baseResult;
}
return something + function(smallerParameter);
}
15. Contoh Recursion yang Sangat Sederhana
Tidak harus factorial.
Misalnya kita ingin mencetak angka mundur:
void countdown(int n) {
if (n == 0) {
return;
}
print(n);
countdown(n - 1);
}
Panggil:
countdown(5);
Output:
5
4
3
2
1
Bagaimana prosesnya?
countdown(5)
↓
print 5
↓
countdown(4)
↓
print 4
↓
countdown(3)
↓
print 3
↓
countdown(2)
↓
print 2
↓
countdown(1)
↓
print 1
↓
countdown(0)
↓
STOP
Ini contoh recursion yang lebih mudah untuk dipahami.
16. Contoh Recursion untuk Menjumlahkan Angka
Misalnya kita ingin menghitung:
1 + 2 + 3 + 4 + 5
Kita dapat mendefinisikannya:
sum(5)
= 5 + sum(4)
sum(4)
= 4 + sum(3)
sum(3)
= 3 + sum(2)
sum(2)
= 2 + sum(1)
sum(1)
= 1
Dart:
int sum(int n) {
if (n == 1) {
return 1;
}
return n + sum(n - 1);
}
Kemudian:
print(sum(5));
Output:
15
17. Recursion vs Loop
Nah, pertanyaan yang sangat bagus:
“Kalau factorial bisa dibuat dengan recursion, bukankah bisa pakai
for?”
Bisa.
Sebelumnya kita bahkan sudah belajar factorial dengan loop:
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
Hasil:
factorial(5) = 120
Dengan recursion:
int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
Hasilnya juga:
120
18. Jadi Mana yang Lebih Baik?
Tidak ada jawaban:
“Recursion selalu lebih baik.”
Tidak.
Bahkan untuk kasus sederhana seperti factorial, loop sering lebih sederhana dan menggunakan memori lebih sedikit.
Recursion menjadi sangat berguna ketika masalahnya memang secara alami berbentuk:
masalah besar
↓
masalah yang sama tetapi lebih kecil
↓
masalah yang sama tetapi lebih kecil
↓
...
Contohnya:
- tree
- directory/folder
- graph pada kasus tertentu
- traversal struktur data
- divide and conquer
- backtracking
- algoritma tertentu
19. Contoh Nyata: Folder di Komputer
Bayangkan struktur folder:
Documents
├── Flutter
│ ├── Project A
│ └── Project B
├── Dart
│ ├── Notes
│ └── Exercises
└── Photos
├── 2025
└── 2026
Folder bisa berisi folder lagi.
Untuk memproses semua folder:
proses Documents
↓
proses Flutter
↓
proses Project A
↓
proses Project B
↓
proses Dart
↓
...
Struktur seperti ini secara alami cocok dengan recursion karena:
Folder berisi folder yang bentuknya sama dengan folder induknya.
20. Contoh Recursion pada Struktur Tree
Misalnya:
A
/ \
B C
/ \
D E
Kita ingin mengunjungi setiap node.
Secara konsep:
proses A
↓
proses B
↓
proses D
↓
kembali
↓
proses E
↓
kembali
↓
proses C
Ini adalah salah satu area di mana recursion sangat umum digunakan.
21. Recursion Bukan Hanya “Function Memanggil Dirinya Sendiri”
Definisi tersebut memang benar, tetapi belum lengkap.
Yang lebih penting adalah:
Recursion adalah cara menyelesaikan masalah dengan menyelesaikan versi yang lebih kecil dari masalah yang sama.
Contoh factorial:
factorial(5)
diubah menjadi:
5 × factorial(4)
Kemudian:
factorial(4)
diubah menjadi:
4 × factorial(3)
Jadi kita terus mengubah masalah:
5 → 4 → 3 → 2 → 1
sampai mencapai masalah paling sederhana:
factorial(1) = 1
22. Kesalahan yang Sering Dilakukan Pemula
Kesalahan 1 — Tidak mempunyai base case
void test(int n) {
test(n - 1);
}
❌ Tidak ada kondisi berhenti.
Kesalahan 2 — Parameter tidak mendekati base case
Misalnya:
void test(int n) {
if (n == 0) {
return;
}
test(n + 1);
}
Kalau dipanggil:
test(5);
nilai malah menjadi:
5
6
7
8
9
...
Tidak pernah mencapai 0.
Kesalahan 3 — Base case salah
Misalnya:
if (n == 100) {
return;
}
tetapi function dipanggil dengan n = 5 dan terus dikurangi:
test(n - 1);
Maka:
5
4
3
2
1
0
-1
-2
...
tidak akan pernah mencapai 100.
23. Contoh Program Lengkap dari Materi
Versi yang mudah dibaca:
int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
void main() {
int fact = factorial(5);
print("Factorial of 5 is = $fact");
}
Output:
Factorial of 5 is = 120
24. Kalau Mau Lebih Aman
Contoh di atas mengasumsikan n >= 1.
Kalau kita memberikan:
factorial(0)
function tersebut tidak berhenti karena kondisi hanya:
if (n == 1)
Untuk definisi matematika factorial, sebenarnya:
0! = 1
Jadi kita bisa membuat:
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
}
return n * factorial(n - 1);
}
Sekarang:
print(factorial(0));
print(factorial(1));
print(factorial(5));
hasil:
1
1
120
Ini lebih lengkap untuk factorial bilangan bulat non-negatif.
25. Hubungkan dengan Function yang Sudah Kamu Pelajari
Sebelumnya kamu belajar function:
int cube(int n) {
return n * n * n;
}
Kemudian anonymous function:
(int n) => n * n * n
Sekarang recursion:
int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
Perbedaannya:
Function biasa
→ function dipanggil oleh function lain/main
Recursive function
→ function memanggil dirinya sendiri
26. Rumus Mental untuk Memahami Recursion
Setiap kali melihat recursive function, coba cari 3 hal:
Pertanyaan 1:
Apa base case-nya?
Contoh:
if (n == 1) {
return 1;
}
Jawaban:
n == 1
Pertanyaan 2:
Di mana function memanggil dirinya sendiri?
Contoh:
factorial(n - 1)
Pertanyaan 3:
Apakah pemanggilan berikutnya semakin dekat dengan base case?
Dari:
5 → 4 → 3 → 2 → 1
Ya.
Kalau tiga hal ini kamu bisa identifikasi, biasanya recursion akan jauh lebih mudah dipahami.
27. Ringkasan Visual
RECURSION
│
▼
Function memanggil
dirinya sendiri
│
┌──────┴──────┐
▼ ▼
Base Case Recursive Case
│ │
berhenti panggil diri
│
▼
masalah lebih kecil
│
▼
ulangi
Untuk factorial:
factorial(5)
↓
5 × factorial(4)
↓
4 × factorial(3)
↓
3 × factorial(2)
↓
2 × factorial(1)
↓
factorial(1) = 1 ← BASE CASE
↓
2 × 1 = 2
↓
3 × 2 = 6
↓
4 × 6 = 24
↓
5 × 24 = 120
28. Cheat Sheet
| Konsep | Arti |
|---|---|
| Recursion | Function memanggil dirinya sendiri |
| Recursive function | Function yang melakukan recursion |
| Base case | Kondisi yang menghentikan recursion |
| Recursive case | Bagian yang memanggil function itu sendiri |
| Call stack | Tempat pemanggilan function yang sedang menunggu diselesaikan |
| Stack overflow | Error yang dapat terjadi jika recursion terlalu dalam/tidak berhenti |
factorial(n - 1) | Contoh recursive call |
if (n == 1) | Contoh base case |
29. Inti yang Harus Kamu Ingat
Kalau hanya ingin mengingat satu pola, ingat ini:
int function(int n) {
if (kondisi_berhenti) {
return hasil_dasar;
}
return sesuatu_dengan_function(n - 1);
}
Recursion bukan sekadar:
“Function memanggil dirinya sendiri.”
Pemahaman yang lebih penting adalah:
“Saya menyelesaikan masalah dengan meminta function yang sama menyelesaikan versi masalah yang lebih kecil, lalu berhenti ketika mencapai base case.”
Pada factorial:
5!
↓
5 × 4!
↓
5 × 4 × 3!
↓
5 × 4 × 3 × 2!
↓
5 × 4 × 3 × 2 × 1!
↓
120
Jadi dua kata kunci yang wajib kamu ingat ketika belajar recursion adalah:
BASE CASE + RECURSIVE CALL
Kalau tidak ada base case, recursion berisiko terus berjalan sampai stack overflow. Kalau recursive call tidak bergerak mendekati base case, masalah yang sama juga bisa terjadi.