Golang으로 끄적여보는 피보나치 수열

Root(√)·2020년 7월 31일
0

피보나치 수열이 무엇인지 아주아주 간략하게 적어보면

f(n) = f(n-1) + f(n-2) 이다.

1, 1, 2, 3, 5, 8, 13, ... ... 이런 식으로 전개되는 수열이다.

어떤 언어이든 코딩 공부할 때 피보나치 수열을 코딩해보라는 문제는 꽤 자주 나온다.

피보나치 수열은 재귀호출을 이용해서 간단하게 구현할 수 있다.

// 재귀호출을 이용한 피보나치 수열
func Fibonacci1(x int) int {

	if x <= 2 {
		return 1
	} else {
		return Fibonacci1(x-1) + Fibonacci1(x-2)
	}
}

간단하게 구현할 수 있지만, 이 알고리즘에는 맹점이 있는데 성능이 매우 구리다는 것이다. Fibonacci1(5)을 알고 싶다고 할 때, 이를 계산하기 위해서는 Fibonacci1(4) + Fibonacci1(3)을 알아야하고, Fibonacci1(4)를 알기 위해 또 Fibonacci1(3)과 Fibonacci1(2)를 알아야하고, Fibonacci1(3)을 알기 위해 Fibonacci1(2)와 Fibonacci1(1)을 알아야한다. 계산에 계속해서 중복이 들어간다. 그렇기 때문에 숫자가 커지면 성능이 아주 구려진다. 성능을 개선하기 위해서는 코드가 덜 간결해질 수는 있지만 반복문을 쓰는 것이 좋다.

// 재귀호출이 아닌 반복문을 통한 피보나치 수열
func Fibonacci2(n int) int {
	var index int
	var last1 int
	var last2 int
	var result int

	if n <= 2 {
		return 1
	}
	last1 = 1
	last2 = 1
	for index = 2; index < n; index++ {
		result = last1 + last2
		last1 = last2
		last2 = result
	}
	return result
}

이른 바 동적 프로그래밍을 활용한 알고리즘이다. 둘의 동작시간을 비교해보면

package main

import (
	"fmt"
	"time"
)

func main() {

	// 두 알고리즘의 실행시간 비교
	// 재귀호출의 경우
	startTime := time.Now()
	result := Fibonacci1(50)
	runTime := time.Since(startTime)
	fmt.Printf("재귀호출을 이용한 피보나치 수열 알고리즘 결과는 %d입니다\n", result)
	fmt.Printf("실행시간은 %s입니다\n", runTime)
	startTime = time.Now()
	result = Fibonacci2(50)
	runTime = time.Since(startTime)
	fmt.Printf("반복문을 이용한 피보나치 수열 알고리즘 결과는 %d입니다\n", result)
	fmt.Printf("실행시간은 %s입니다\n", runTime)
}


// 재귀호출을 이용한 피보나치 수열 알고리즘 결과는 12586269025입니다
// 실행시간은 1m1.4258082s입니다
// 반복문을 이용한 피보나치 수열 알고리즘 결과는 12586269025입니다
// 실행시간은 0s입니다

100번째까지도 실행시켜보려고 했는데 드럽게 오래걸려서 그냥 껐다. 속도는 비교할 수 없을 정도로 후자가 빠르다. '누워서 읽는 알고리즘'을 보다가 golang으로 끄적여봤다. 그리고 기존에 tucker님 강의 보다가 재귀호출을 이용한 코드를 짜봤는데 오류가 있는 것을 오늘의 독서 덕분에 발견하여 바로잡아봤다.

profile
Software Engineer

0개의 댓글