Learn and Understand Recursion in JavaScript - Lee-hyuna/33-js-concepts-kr GitHub Wiki

Learn and Understand Recursion in JavaScript

๋ฒˆ์—ญ : https://codeburst.io/learn-and-understand-recursion-in-javascript-b588218e87ea

What is Recursion?

์žฌ๊ท€๋Š” ๊ฐ„๋‹จํžˆ ํ•จ์ˆ˜๊ฐ€ ์ž์‹ ์„ ํ˜ธ์ถœํ• ๋•Œ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค.

๋ฐ”๋กœ ๋›ฐ์–ด ๋“ค์–ด ์•„๋งˆ๋„ ๊ฐ€์žฅ ์œ ๋ช…ํ•œ ์žฌ๊ท€ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ๋Š” ์ œ๊ณต๋œ ์ •์ˆ˜์˜ ๊ณ„์Šน์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

function factorial(x) {  
  if (x < 0) return;  
  if (x === 0) return 1;  
  return x * factorial(x - 1);  
}factorial(3);  
**// 6**

** ์šฐ์™€ ๊ดœ์ฐฎ๋‹ค๋ฉด ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. **. ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ 4 ๋ฒˆ ์ค„์—์„œ ์ผ์–ด๋‚˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค : return x * factorial (x โ€” 1);. ๋ณด์‹œ๋‹ค์‹œํ”ผ, ํ•จ์ˆ˜๋Š” ์‹ค์ œ๋กœ ์ž์‹ ์„ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜์ง€๋งŒ (factorial (x-1)), ์ฒ˜์Œ ํ˜ธ์ถœ ํ–ˆ์„ ๋•Œ๋ณด๋‹ค 1์ด ์ž‘์€ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์žฌ๊ท€ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— ๊ณ„์Šน์ด ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์ˆซ์ž์˜ ๊ณ„์Šน์„ ์–ป์œผ๋ ค๋ฉด ์ˆซ์ž 1์— ๋„๋‹ฌ ํ•  ๋•Œ๊นŒ์ง€ ๊ทธ ์ˆซ์ž์— 1์„ ๋บ€ ๊ฐ’์„ ๊ณฑํ•˜์‹ญ์‹œ์˜ค.

์˜ˆ์ œ 1: 4 ์˜ ํŒฉํ† ๋ฆฌ์–ผ์€ 4 * 3 * 2 * 1, or 24.

์˜ˆ์ œ 2: 2 ์˜ ํŒฉํ† ๋ฆฌ์–ผ์€ 2 * 1, or 2.

์ด์ œ ์šฐ๋ฆฌ ๊ณ ๋“ฑํ•™๊ต ์ˆ˜ํ•™ ์ˆ˜์—…์ด ๋๋‚ฌ์œผ๋‹ˆ, ์ข‹์€ ๊ฒƒ๋“ค๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

The three key features of recursion

๋ชจ๋“  ์žฌ๊ท€ ํ•จ์ˆ˜์—๋Š” 3๊ฐ€์ง€ ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

A Termination Condition

if (๋ญ”๊ฐ€ ๋‚˜์œ ์ผ์ด ์ƒ๊ฒผ๋‹ค) {STOP}; ์ข…๋ฃŒ ์กฐ๊ฑด์€ ์šฐ๋ฆฌ์˜ ์žฌ๊ท€ ์‹คํŒจ ์•ˆ์ „์ž…๋‹ˆ๋‹ค. ๋น„์ƒ ๋ธŒ๋ ˆ์ดํฌ์ฒ˜๋Ÿผ ์ƒ๊ฐํ•˜์‹ญ์‹œ์˜ค. ์ž…๋ ฅ์ด ์ž˜๋ชป๋˜๋ฉด ์žฌ๊ท€๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ํŒฉํ† ๋ฆฌ์–ผ ์˜ˆ์ œ์—์„œ if (x <0) return; ์€ ์ข…๋ฃŒ ์กฐ๊ฑด์ž…๋‹ˆ๋‹ค. ์Œ์ˆ˜๋ฅผ ๊ณ„์Šน ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์Œ์ˆ˜๊ฐ€ ์ž…๋ ฅ ๋œ ๊ฒฝ์šฐ ์žฌ๊ท€๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

A Base Case

๊ฐ„๋‹จํžˆ ๋งํ•ด : if (์ด๋Ÿฌํ•œ ์ผ) {์˜ˆ! ๋๋‚ฌ๋‹ค.}; ๊ธฐ๋ณธ ์‚ฌ๋ก€๋Š” ์žฌ๊ท€๋ฅผ ์ค‘์ง€ํ•œ๋‹ค๋Š” ์ ์—์„œ ์ข…๋ฃŒ ์กฐ๊ฑด๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ข…๋ฃŒ ์กฐ๊ฑด์€ ๋‚˜์œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ํฌ๊ด„์  ์ธ ๊ฒƒ์ž„์„ ๊ธฐ์–ตํ•˜์‹ญ์‹œ์˜ค. ๊ธฐ๋ณธ ์‚ฌ๋ก€๋Š” ์žฌ๊ท€ ํ•จ์ˆ˜์˜ ๋ชฉํ‘œ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์‚ฌ๋ก€๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ if ๋ฌธ ์•ˆ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณ„์Šน ์˜ˆ์—์„œ if (x === 0) return 1; ์ด ๊ธฐ๋ณธ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. x ๋ฅผ 0์œผ๋กœ ๋‚ฎ์ถ”๋ฉด ๊ณ„์Šน์„ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค!

The Recursion

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ : ์šฐ๋ฆฌ์˜ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ณ„์Šน ์˜ˆ์—์„œ return x * factorial (x โ€” 1); ์€ ์‹ค์ œ๋กœ ์žฌ๊ท€๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ˆซ์ž x ์˜ ๊ฐ’์— factorial (x-1) ์ด ํ‰๊ฐ€ํ•˜๋Š” ๋ชจ๋“  ๊ฐ’์„ ๊ณฑํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

All Three Together

์ด์ œ ์šฐ๋ฆฌ๋Š” ๊ณ„์Šน ์˜ˆ์ œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ•˜์ง€๋งŒ ์ด์ƒ์ ์œผ๋กœ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

function factorial(x) {  
  **// TERMINATION**  
  if (x < 0) return; **// BASE**  
  if (x === 0) return 1; **// RECURSION**  
  return x * factorial(x - 1);  
}factorial(3);  
// 6

Factorial Function Flow

ํŒฉํ† ๋ฆฌ์–ผ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•  ๋•Œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ๋จผ์ € 3์˜ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
factorial(3);
  1. ์ด๋กœ ์ธํ•ด ๊ธฐ๋Šฅ์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. if ๋ฌธ์ด ์‹คํŒจํ•˜๊ณ  ์žฌ๊ท€ ๋ผ์ธ์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. factorial (3-1) ์˜ ๊ฐ’๊ณผ 3์„ ๊ณฑํ•œ ์ •์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
return **3** * factorial(**2**);
  1. factorial (2) ๊ฐ€ ์‹คํ–‰๋˜๋ฉด if ๋ฌธ๋“ค์ด ์‹คํŒจํ•˜๊ณ  ์žฌ๊ท€๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ. factorial (2-1) ์˜ ๊ฐ’์„ 2์— ๊ณฑํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
return **2** * factorial(**1**);
  1. factorial (1) ์ด ์‹คํ–‰๋˜๋ฉด if ๋ฌธ๋“ค์ด ์‹คํŒจํ•˜๊ณ  ์žฌ๊ท€๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ. factorial (1-1) ์˜ ๊ฐ’ 1์— ๊ณฑํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
return **1** * factorial(**0**);
  1. factorial (0)์ด ์‹คํ–‰๋˜๋ฉด ๋‹ค๋ฅธ ์ผ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. 0์ด ๊ธฐ๋ณธ ์‚ฌ๋ก€์ด๋ฏ€๋กœ if ๋ฌธ์ด ์ „๋‹ฌ๋˜๊ณ  ํ•จ์ˆ˜๊ฐ€ 1์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
if (x === 0) return **1**;

์ด์ œ ํ•จ์ˆ˜๊ฐ€ ๋งˆ์นจ๋‚ด ๋ฐ˜ํ™˜๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ชจ๋“  ๊ฒƒ์ด 'ํ’€๋ฆฝ๋‹ˆ๋‹ค'. ์žฌ๊ท€๋Š” ๋‹จ์ˆœํžˆ ์ค‘์ฒฉ ๋œ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ทธ๋ฃน์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ค‘์ฒฉ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด most inner ์ค‘์ฒฉ ํ•จ์ˆ˜๊ฐ€ ๋จผ์ € ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ดํ•ดํ•ด์•ผ ํ•  ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ฒ˜์Œ์— ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด์ด ๋‚ด์šฉ์„ ๋ช‡ ๋ฒˆ ์ฝ์–ด๋ณด์‹ญ์‹œ์˜ค.

factorial(0) returns 1

factorial(1) returns 1 * factorial(0), or just 1*1

factorial(2) returns 2 * factorial(1), or just 2*1*1

factorial(3) returns 3 * factorial(2), or just 3*2*1*1

return 1 * 1 * 2 * 3  
**// 6**

๋”ฐ๋ผ ์™”๋‚˜์š”? ๋‹ค์Œ์€ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋œ ๋™์ผํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.

factorial(3) returns 3 * factorial(2)  
factorial(2) returns 2 * factorial(1)  
factorial(1) returns 1 * factorial(0)  
factorial(0) returns 1// Now that we've hit our base case, our function will return in order from inner to outer:factorial(0) returns 1                 => 1  
factorial(1) returns 1 * factorial(0)  => 1 * 1  
factorial(2) returns 2 * factorial(1)  => 2 * 1 * 1  
factorial(3) returns 3 * factorial(2)  => 3 * 2 * 1 * 1// 3 * 2 * 1 * 1 = **6**

์•„์ง๋„ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ์•Š์•„๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํ˜ผ๋ž€์„ ํ•ด์†Œํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ์˜ˆ์ œ๋กœ ๋„˜์–ด ๊ฐ‘์‹œ๋‹ค.

Lets look at a second example

์ด ๋‘ ๋ฒˆ์งธ ์˜ˆ์—์„œ๋Š” ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ธธ์„ ๊ฐ€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ธํ„ฐ๋„ท์—์„œ ์ธ๊ธฐ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ์˜ˆ์ด๋ฉฐ ๋ฌธ์ž์—ด์„ ๋’ค์ง‘๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์€ JavaScript์—์„œ ๋ฌธ์ž์—ด์„ ๋’ค์ง‘๋Š” ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์€ ์•„๋‹™๋‹ˆ๋‹ค. ํ›จ์”ฌ ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์žฌ๊ท€์˜ ์ผ๋ฐ˜์ ์ธ ์ธํ„ฐ๋„ท ์˜ˆ ์ผ ๋ฟ์ด๋ฏ€๋กœ ์ด๋ฅผ ๋‹ค๋ฃจ๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด์‹ญ์‹œ์š”

function revStr(str){  
  if (str === '') return '';  
  return revStr(str.substr(1)) + str[0];  
}

revStr('cat');  
// **tac**

Instantly you can (ideally) notice a few things:

  1. str === "" ๊ฐ€ ์šฐ๋ฆฌ์˜ ๊ธฐ๋ณธ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ๋ˆ์— ๋ฌธ์ž๊ฐ€ ์—†์œผ๋ฉด ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.
  2. return revStr (str.substr (1)) + str [0]; ์€ ์žฌ๊ท€ ๋งˆ์ˆ ์ด ์ผ์–ด๋‚˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
  3. ์—ฌ๊ธฐ์—” ์ข…๋ฃŒ ์‚ฌ๋ก€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๊ธฐ๋ณธ ์‚ฌ๋ก€๊ฐ€ ์ข…๋ฃŒ ์‚ฌ๋ก€์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์Œ์ˆ˜ ๋ฌธ์ž๊ฐ€ ํฌํ•จ ๋œ ๋ฌธ์ž์—ด์„ ์–ป์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜์—๋งŒ ๋ฌธ์ž์—ด ๋งŒ ์ž…๋ ฅํ•˜๋ฉด ๊ดœ์ฐฎ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Letโ€™s break it down line by line

์ด ์˜ˆ์—์„œ๋Š” ๋ฌธ์ž์—ด cat ์„ ๋ฐ˜์ „์‹œํ‚ต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ฌธ์ž์—ด cat์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

revStr('cat');

์žฌ๊ท€ ์‚ฌ๋ก€๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

JavaScript์—์„œ substr () ๋ฉ”์†Œ๋“œ๋Š” ์ง€์ •๋œ ์œ„์น˜์—์„œ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด์„ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. สปcat'.substr (1) ===โ€˜atโ€™

str [0] ์€ ๋ฌธ์ž์—ด์—์„œ ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ ๋ฌธ์ž๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ cat [0] === 'c'

return revStr(str.substr(1)) + str[0];// SAME AS  
return revStr('at') + 'c'

์žฌ๊ท€ ์‚ฌ๋ก€๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

return revStr(str.substr(1)) + str[0];// SAME AS  
return revStr('t') + 'a'

์šฐ๋ฆฌ์˜ ์žฌ๊ท€ ์‚ฌ๋ก€๋Š” ๋งˆ์ง€๋ง‰ ํ•œ ๋ฒˆ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

return revStr(str.substr(1)) + str[0];// SAME AS  
return revStr('') + 't'

์ด๋ฒˆ์—๋Š” ๊ธฐ๋ณธ ์‚ฌ๋ก€๊ฐ€ ์‹คํ–‰๋˜๊ณ  ํ•จ์ˆ˜๋Š” ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

if (str === '') return '';

์ด์ œ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ชจ๋“  ๊ฒƒ์ด 'ํ’€๋ฆฌ๊ณ '์ˆœ์„œ๋Œ€๋กœ ๋Œ์•„์˜ต๋‹ˆ๋‹ค.

return โ€˜โ€™ + โ€˜tโ€™ + โ€˜aโ€™ + โ€˜cโ€™  
// **tac**

Break it down even more

revStr('cat')  returns 
revStr('at') + 'c'revStr('at')   returns 
revStr('t') +  'a'revStr('t')    returns 
revStr('') +   't'revStr('')     returns               ''
revStr('')     returns                ''  => ''
revStr('t')    returns revStr('') +   't' => '' + 't'
revStr('at')   returns revStr('t') +  'a' => '' + 't' + 'a'
revStr('cat')  returns revStr('at') + 'c' => '' + 't' + 'a' + 'c'

**// tac**