Computer Science/Algorithms

๐ŸงญRecursion

metamong 2022. 9. 27.

intro

๐Ÿ“ ์žฌ๊ท€ํ•จ์ˆ˜๋ž€, ์ž๊ธฐ ์ž์‹ ์„ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ํ•จ์ˆ˜ ๋‚ด์— ๋‹ค์‹œ ํ•จ์ˆ˜๋ฅผ ๋ถˆ๋Ÿฌ์„œ, ๋™์ผ ํ•จ์ˆ˜ ๋กœ์ง์„ ๋ฐ˜๋ณต์ ์œผ๋กœ(์žฌ๊ท€์ ) ์ง„ํ–‰ํ•œ๋‹ค. DFS ๊ตฌํ˜„์„ ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ฐœ๋…. ์•„๋ž˜ ์ฝ”๋“œ ์˜ˆ์‹œ ์ฐธ์กฐ.

def recursive_function():
    print('recursive call')
    recursive_function()

recursive_function()

 

→ ๋ฌดํ•œํžˆ ์ถœ๋ ฅ๋˜๋‹ค๊ฐ€ python์˜ ๊ฒฝ์šฐ 'RecursionError: maximum recursion depth exceeded while calling a Python object'๋ผ๋Š” ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ - ์žฌ๊ท€ ์ตœ๋Œ€ ํ—ˆ์šฉ ๊นŠ์ด๊ฐ€ ์žˆ์–ด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋์— ์ถœ๋ ฅ๋˜๋ฉฐ ์ข…๋ฃŒ. ํ•จ์ˆ˜๋ฅผ ๋ถ€๋ฅผ ๋•Œ ๋งˆ๋‹ค ์Šคํƒ ์ž๋ฃŒ ๊ตฌ์กฐ์— ํ•จ์ˆ˜๊ฐ€ ๊ณ„์† ์Œ“์ด๋ฉด์„œ ์ปดํ“จํ„ฐ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌ๊ฐ€ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ, ๋ฉ”๋ชจ๋ฆฌ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์žฌ๊ท€ ๊นŠ์ด ์ œํ•œ์„ ๋Š์Šจํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜, ๋ณ„๋„ ์Šคํƒ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์žฌ๊ท€๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ํ’€๋ฉด์„œ ์ต์ˆ™ํ•ด์ง€๊ณ  ์ ์‘ํ•˜๋Š” ๊ฒŒ BEST. ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. (๋‹จ, ์˜คํžˆ๋ ค ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šด ํ˜•ํƒœ์˜ ์ฝ”๋“œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•จ!) ๋˜ํ•œ ๋ชจ๋“  ์žฌ๊ท€ํ•จ์ˆ˜๋Š” ๋ฐ˜๋ณต๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ (์—ญ๋„ ๊ฐ€๋Šฅ) / ์žฌ๊ท€ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋ณต๋ฌธ๋ณด๋‹ค ์œ ๋ฆฌํ•œ ๊ฒฝ์šฐ๋„, ๋ถˆ๋ฆฌํ•œ ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค. (๋ฌธ์ œ ์ƒํ™ฉ๋ณ„๋กœ ๊ตฌ๋ณ„) ์ปดํ“จํ„ฐ๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์—ฐ์†์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉด ์ปดํ“จํ„ฐ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด๋ถ€์˜ ์Šคํƒ ํ”„๋ ˆ์ž„์— ์Œ“์ž„ (๋”ฐ๋ผ์„œ ์Šคํƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ ๊ตฌํ˜„์ƒ ์Šคํƒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋Œ€์‹ ์— ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค - ๋Œ€ํ‘œ์ ์œผ๋กœ DFS๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์งง์€ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ) divide & conquer, DP, backtracking, DFS ๋“ฑ ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์ ์šฉ๋˜๋Š” recursion ํ•„์ˆ˜ ์ˆ™์ง€! (ex ํ•˜๋…ธ์ด ํƒ‘, Tree Traversal(Inorder, preorder, postorder)

 

→ Recursion helps in logic building. Recursive thinking helps in solving complex problems by breaking them into smaller subproblems.

 

→ Steps

โ‘  define a base case: Identify the simplest (or base) case for which the solution is known or trivial. This is the stopping condition for the recursion, as it prevents the function from infinitely calling itself.

โ‘ก define a recursive case: Define the problem in terms of smaller subproblems. Break the problem down into smaller versions of itself, and call the function recursively to solve each subproblem.

โ‘ข Ensure the recursion terminates: Make sure that the recursive function eventually reaches the base case, and does not enter an infinite loop.

โ‘ฃ Combine the solutions: Combine the solutions of the subproblems to solve the original problem.

 

→ stack ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ : stack์€ LIFO(Last-In First-Out) ๊ตฌ์กฐ์ด๋ฏ€๋กœ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์‹คํ–‰๋œ recursive function์ด ๋จผ์ € ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ์ƒ stack ๋ฉ”๋ชจ๋ฆฌ์— ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋•Œ๋งˆ๋‹ค ์ ์žฌ๋œ๋‹ค.
(When any function is called from main(), the memory is allocated to it on the stack. A recursive function calls itself, the memory for a called function is allocated on top of memory allocated to the calling function and a different copy of local variables is created for each function call. When the base case is reached, the function returns its value to the function by whom it is called and memory is de-allocated and the process continues)

 

→ disadvantages

โ‘  recursive programs typically have more space requirements / more time to maintain the recursion call stack

โ‘ก recursion can make the code more difficult to understand & debug(it requires thinking about multiple levels of function calls)

 

→ advantages

โ‘  provides a clean & simple way to write code

implementation

๐Ÿ“ ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ๋ฌธ์ œ ํ’€์ด์—์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์žฌ๊ท€ํ•จ์ˆ˜์˜ ์ข…๋ฃŒ ์กฐ๊ฑด์„ ๋ฐ˜๋“œ์‹œ ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค. ์ข…๋ฃŒ ์กฐ๊ฑด์„ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด RecursionError ๋ฐœ์ƒํ•˜๊ณ  ํ•จ์ˆ˜๊ฐ€ ๋ฌดํ•œํžˆ ํ˜ธ์ถœ. ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ์ฐธ์กฐ

def recursive_function(i):

    if i == 5:
        return #recursion end 
    print(i,'th recursion function calls', i+1, 'the recursion function')
    recursive_function(i+1)
    print(i,'th recursion function ends')

recursive_function(1)

๐Ÿ“ ๋งˆ์น˜ ์Šคํƒ์ฒ˜๋Ÿผ, ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์Šคํƒ ํ”„๋ ˆ์ž„์— ์Œ“์ด๋ฉด์„œ ์ฐจ๋ก€๋Œ€๋กœ ํ˜ธ์ถœ๋˜๋‹ค๊ฐ€ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ํ˜ธ์ถœ๋œ ํ•จ์ˆ˜๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ ์ข…๋ฃŒ. ์•„๋ž˜ ๊ทธ๋ฆผ์„ ์ฐธ๊ณ ํ•˜์ž. ๊ฐ€์žฅ ๋จผ์ € ํ˜ธ์ถœ๋˜๋Š” ์žฌ๊ท€ ํ•จ์ˆ˜๊ฐ€ ๋งจ ์ฒ˜์Œ๊ณผ ๋์„ ๋‹ด๋‹น. ๊ทธ ๋‹ค์Œ ํ˜ธ์ถœ๋˜๋Š” ์žฌ๊ท€ ํ•จ์ˆ˜๊ฐ€ ๋‘ ๋ฒˆ์งธ ์ฒ˜์Œ๊ณผ ๋์„ ๋‹ด๋‹น..... ์ด๋ ‡๊ฒŒ ๊ณ„์† ๋‚ด๋ถ€๋กœ ์ง„ํ–‰. ๋งจ ๋งˆ์ง€๋ง‰ ํ˜ธ์ถœ๋˜๋Š” ์žฌ๊ท€ํ•จ์ˆ˜์—์„œ return ์ฒ˜๋ฆฌ. ์•„๋ž˜ ๊ทธ๋ฆผ ๊ธฐ์ค€ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ง„ํ–‰๋˜๋Š” ๋ฐฉํ–ฅ์ด ๊บพ์—ฌ์„œ, recursive_function() ํ˜ธ์ถœ ์ดํ›„ ์•„๋ž˜ ์ฝ”๋“œ๊ฐ€ ์ฐจ๋ก€๋Œ€๋กœ ์ง„ํ–‰.

examples

โ‘  factorial

def factorial_recursive(n):
    if n<=1:
        return 1
    return n*factorial_recursive(n-1)

print(factorial_recursive(5))

 

โ‘ก euclidean algorithm

๐Ÿ“ ๋‘ ๊ฐœ์˜ ์ž์—ฐ์ˆ˜์— ๋Œ€ํ•œ ์ตœ๋Œ€๊ณต์•ฝ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ '์œ ํด๋ฆฌ๋“œ ํ˜ธ์ œ๋ฒ•'์ด ์žˆ๋‹ค. ๋‘ ์ž์—ฐ์ˆ˜ A,B์— ๋Œ€ํ•˜์—ฌ (A>B) A๋ฅผ B๋กœ ๋‚˜๋ˆˆ ๋‚˜๋จธ์ง€๋ฅผ R์ด๋ผ๊ณ  ํ•˜์ž. ์ด ๋•Œ A์™€ B์˜ ์ตœ๋Œ€๊ณต์•ฝ์ˆ˜๋Š” B์™€ R์˜ ์ตœ๋Œ€๊ณต์•ฝ์ˆ˜์™€ ๊ฐ™๋‹ค. ์•„๋ž˜ ์žฌ๊ท€ ์ฝ”๋“œ ์ฐธ์กฐ

a,b=map(int,input().split())

def gcd(a,b):
    if b == 0:
        return a
    return gcd(b,a%b)

print(gcd(a,b))

 

๐Ÿงญ <BOJ S5 17478 ์žฌ๊ท€ํ•จ์ˆ˜๊ฐ€ ๋ญ”๊ฐ€์š”?>

Q. ํ•จ์ˆ˜ ์•ˆ์— return๋ฌธ์„ ๋จผ์ € ๋„ฃ๊ณ  ๋™์ผ ์žฌ๊ท€ ํ•จ์ˆ˜ ๋„ฃ๊ธฐ ์ „๊ณผ ๋’ค ๊ฐ๊ฐ print()๋ฌธ ์ง„ํ–‰

 

๐Ÿงญ <BOJ S3 4779 ์นธํ† ์–ด ์ง‘ํ•ฉ>

Q. ํ•จ์ˆ˜ ์•ˆ์— ์žฌ๊ท€ํ•จ์ˆ˜๊ฐ€ 2๊ฐœ ์žˆ๋Š” ๋ฌธ์ œ. ๊ฐ€์šด๋ฐ๋Š” ๋นˆ์นธ์œผ๋กœ ๋†”๋‘๊ณ  ๋นˆ์นธ ๊ธฐ์ค€ ์•ž๊ณผ ๋’ค ๊ฐ๊ฐ ์žฌ๊ท€ํ•จ์ˆ˜ ์ง„ํ–‰

 

๐Ÿงญ<BOJ B5 27433 ํŒฉํ† ๋ฆฌ์–ผ 2 + B2 10870 ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜ 5>

Q. ๋‘ ๋ฌธ์ œ ๋ชจ๋‘ ์žฌ๊ท€ํ•จ์ˆ˜๋กœ๋„ ํ’€ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ.

 

๐Ÿงญ<BOJ B2 25501 ์žฌ๊ท€์˜ ๊ท€์žฌ>

Q. ์žฌ๊ท€ํ•จ์ˆ˜ ๋‚ด๋ถ€์— return ์ข…๋ฃŒ ์กฐ๊ฑด 2๊ฐœ + return๋ฌธ์— ๋‚ด๋ถ€ ์žฌ๊ท€ํ•จ์ˆ˜ ํ˜ธ์ถœ

 

 

'Computer Science > Algorithms' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

๐Ÿ‘€ Binary Search ๐Ÿ‘€  (2) 2022.12.06
understanding pesudo-code of QuickSort  (0) 2022.12.05
DFS / BFS  (0) 2022.10.14
Implementation  (1) 2022.09.21
Greedy  (0) 2022.09.12

๋Œ“๊ธ€