Rekursi adalah topik yang sulit untuk dipahami dan saya rasa saya tidak dapat sepenuhnya melakukannya dengan adil di sini. Sebaliknya, saya akan mencoba untuk fokus pada bagian kode tertentu yang Anda miliki di sini dan mencoba menjelaskan intuisi mengapa solusi tersebut bekerja dan mekanisme bagaimana kode tersebut menghitung hasilnya.
Kode yang Anda berikan di sini memecahkan masalah berikut: Anda ingin mengetahui jumlah semua bilangan bulat dari a hingga b, inklusif. Sebagai contoh, Anda ingin menjumlahkan angka dari 2 hingga 5, inklusif, yaitu
2 + 3 + 4 + 5
Saat mencoba memecahkan masalah secara rekursif, salah satu langkah pertama yang harus dilakukan adalah mencari cara untuk memecah masalah menjadi masalah yang lebih kecil dengan struktur yang sama. Jadi misalkan Anda ingin menjumlahkan angka dari 2 menjadi 5, inklusif. Salah satu cara untuk menyederhanakannya adalah dengan memperhatikan bahwa jumlah di atas dapat ditulis ulang sebagai
2 + (3 + 4 + 5)
Di sini, (3 + 4 + 5) kebetulan merupakan jumlah dari semua bilangan bulat antara 3 dan 5, inklusif. Dengan kata lain, jika Anda ingin mengetahui jumlah semua bilangan bulat antara 2 dan 5, mulailah dengan menghitung jumlah semua bilangan bulat antara 3 dan 5, lalu tambahkan 2.
Jadi, bagaimana Anda menghitung jumlah semua bilangan bulat antara 3 dan 5, inklusif? Nah, jumlah itu
3 + 4 + 5
yang bisa dianggap sebagai gantinya
3 + (4 + 5)
Di sini, (4 + 5) adalah jumlah dari semua bilangan bulat antara 4 dan 5, inklusif. Jadi, jika Anda ingin menghitung jumlah semua angka antara 3 dan 5, inklusif, Anda akan menghitung jumlah semua bilangan bulat antara 4 dan 5, lalu menambahkan 3.
Ada pola di sini! Jika Anda ingin menghitung jumlah bilangan bulat antara a dan b, inklusif, Anda dapat melakukan hal berikut. Pertama, hitung jumlah bilangan bulat antara a + 1 dan b, inklusif. Selanjutnya, tambahkan ke total itu. Anda akan melihat bahwa "menghitung jumlah bilangan bulat antara a + 1 dan b, inklusif" kebetulan merupakan jenis masalah yang hampir sama yang sudah kita coba selesaikan, tetapi dengan parameter yang sedikit berbeda. Daripada menghitung dari a ke b, inklusif, kami menghitung dari a + 1 ke b, inklusif. Itulah langkah rekursif - untuk memecahkan masalah yang lebih besar ("jumlah dari a ke b, inklusif"), kita mengurangi masalah ke versi yang lebih kecil dari dirinya sendiri ("jumlah dari a + 1 ke b, inklusif.").
Jika Anda melihat kode yang Anda miliki di atas, Anda akan melihat bahwa ada langkah ini di dalamnya:
return a + sumInts(a + 1, b: b)
Kode ini hanyalah terjemahan dari logika di atas - jika Anda ingin menjumlahkan dari a ke b, inklusif, mulailah dengan menjumlahkan a + 1 ke b, inklusif (itulah panggilan rekursif ke sumInt
s), lalu tambahkan a
.
Tentu saja, dengan sendirinya pendekatan ini tidak akan berhasil. Misalnya, bagaimana Anda menghitung jumlah semua bilangan bulat antara 5 dan 5 inklusif? Nah, dengan menggunakan logika kita saat ini, Anda akan menghitung jumlah semua bilangan bulat antara 6 dan 5, inklusif, lalu menambahkan 5. Jadi bagaimana Anda menghitung jumlah semua bilangan bulat antara 6 dan 5, inklusif? Nah, menggunakan logika kita saat ini, Anda akan menghitung jumlah semua bilangan bulat antara 7 dan 5, inklusif, lalu menambahkan 6. Anda akan melihat masalah di sini - ini terus berjalan dan berlangsung!
Dalam pemecahan masalah rekursif, perlu ada beberapa cara untuk berhenti menyederhanakan masalah dan sebaliknya hanya menyelesaikannya secara langsung. Biasanya, Anda akan menemukan kasus sederhana di mana jawabannya dapat ditentukan dengan segera, kemudian susun solusi Anda untuk menyelesaikan kasus sederhana secara langsung saat muncul. Ini biasanya disebut kasus dasar atau basis rekursif .
Jadi apa kasus dasar dalam masalah khusus ini? Saat Anda menjumlahkan bilangan bulat dari a ke b, inklusif, jika a ternyata lebih besar dari b, maka jawabannya adalah 0 - tidak ada angka dalam rentang tersebut! Oleh karena itu, kami akan menyusun solusi kami sebagai berikut:
- Jika a> b, maka jawabannya 0.
- Jika tidak (a ≤ b), dapatkan jawabannya sebagai berikut:
- Hitung jumlah bilangan bulat antara a + 1 dan b.
- Tambahkan a untuk mendapatkan jawabannya.
Sekarang, bandingkan pseudocode ini dengan kode Anda yang sebenarnya:
func sumInts(a: Int, b: Int) -> Int {
if (a > b) {
return 0
} else {
return a + sumInts(a + 1, b: b)
}
}
Perhatikan bahwa hampir ada peta satu-ke-satu antara solusi yang diuraikan dalam kodesemu dan kode aktual ini. Langkah pertama adalah kasus dasar - jika Anda meminta jumlah rentang angka kosong, Anda mendapatkan 0. Jika tidak, hitung jumlah antara a + 1 dan b, lalu tambahkan a.
Sejauh ini, saya hanya memberikan ide tingkat tinggi di balik kode. Tapi Anda punya dua pertanyaan lain yang sangat bagus. Pertama, mengapa ini tidak selalu mengembalikan 0, mengingat fungsinya mengatakan mengembalikan 0 jika a> b? Kedua, dari mana sebenarnya ke-14 itu berasal? Mari kita lihat ini secara bergantian.
Mari kita coba kasus yang sangat, sangat sederhana. Apa yang terjadi jika Anda menelepon sumInts(6, 5)
? Dalam kasus ini, menelusuri kode, Anda melihat bahwa fungsinya hanya mengembalikan 0. Itu hal yang benar untuk dilakukan, untuk - tidak ada angka dalam rentang. Sekarang, coba sesuatu yang lebih keras. Apa yang terjadi saat Anda menelepon sumInts(5, 5)
? Nah, inilah yang terjadi:
- Anda menelepon
sumInts(5, 5)
. Kami jatuh ke else
cabang, yang mengembalikan nilai `a + sumInts (6, 5).
- Untuk
sumInts(5, 5)
menentukan apa sumInts(6, 5)
itu, kita perlu menghentikan apa yang sedang kita lakukan dan menelepon sumInts(6, 5)
.
sumInts(6, 5)
dipanggil. Ini memasuki if
cabang dan kembali 0
. Namun, contoh sumInts
ini dipanggil oleh sumInts(5, 5)
, sehingga nilai yang dikembalikan dikomunikasikan kembali ke sumInts(5, 5)
, bukan ke pemanggil tingkat atas.
sumInts(5, 5)
sekarang dapat menghitung 5 + sumInts(6, 5)
untuk kembali 5
. Kemudian mengembalikannya ke pemanggil tingkat atas.
Perhatikan bagaimana nilai 5 dibentuk di sini. Kami memulai dengan satu panggilan aktif ke sumInts
. Itu memicu panggilan rekursif lain, dan nilai yang dikembalikan oleh panggilan itu mengkomunikasikan informasi kembali sumInts(5, 5)
. Panggilan ke sumInts(5, 5)
kemudian pada gilirannya melakukan beberapa perhitungan dan mengembalikan nilai ke pemanggil.
Jika Anda mencoba ini dengan sumInts(4, 5)
, inilah yang akan terjadi:
sumInts(4, 5)
mencoba untuk kembali 4 + sumInts(5, 5)
. Untuk melakukan itu, ia memanggil sumInts(5, 5)
.
sumInts(5, 5)
mencoba untuk kembali 5 + sumInts(6, 5)
. Untuk melakukan itu, ia memanggil sumInts(6, 5)
.
sumInts(6, 5)
mengembalikan 0 kembali ke sumInts(5, 5).</li>
<li>
sumInts (5, 5) now has a value for
sumInts (6, 5) , namely 0. It then returns
5 + 0 = 5`.
sumInts(4, 5)
sekarang memiliki nilai untuk sumInts(5, 5)
, yaitu 5. Kemudian kembali 4 + 5 = 9
.
Dengan kata lain, nilai yang dikembalikan dibentuk dengan menjumlahkan nilai satu per satu, setiap kali mengambil satu nilai yang dikembalikan oleh panggilan rekursif tertentu ke sumInts
dan menambahkan nilai saat ini dari a
. Ketika rekursi berhenti, panggilan terdalam mengembalikan 0. Namun, nilai itu tidak segera keluar dari rantai panggilan rekursif; sebagai gantinya, itu hanya menyerahkan nilai kembali ke panggilan rekursif satu lapisan di atasnya. Dengan cara itu, setiap panggilan rekursif hanya menambahkan satu angka lagi dan mengembalikannya lebih tinggi dalam rangkaian, yang berpuncak dengan penjumlahan keseluruhan. Sebagai latihan, cobalah menelusuri ini sumInts(2, 5)
, yang Anda ingin mulai dengan ini.
Semoga ini membantu!