자료 구조 - 팩토리얼

 | 취미
2015. 3. 10. 16:31



1. recursive algorithm ( 재귀 알고리즘 )
2. iterative algorithm ( 반복 알고리즘 )

Recursive 란 알고리즘이나 함수가 수행 도중에 자기 자신을 다시 호출하여 문제를 해결하는 기법이다. 
대개 정의 자체가 순환적으로 되어 있는 경우에 적합한 방법이다.

가장 기본적인 재귀 알고리즘을 생각하여 보자.

 1. 팩토리얼 

n!  의 계산식은 n = 1 일 때는 1 
                       n >=2 일 때는 n*(n-1)! 이다.

이것을 단순한 반복접근 방식으로 해결해보자.

1) iterative approach 

n! = 1x2x3x....xn

 int fact ( int n ) {

int res = 1;
int i;

for (i = 1; i <= n , i++)
   res = res * i ;

return res;
}

단순히 for문을 사용하여 n번 반복하고 있다.

2) recursive approach

int fact(int n){

if( n <=1 ) return 1;
else return n*fact(n-1);
}

재귀 접근방식으로는 코드가 아주 간단해졌다. 팩토리얼의 수학적 정의를 그대로 이용한 것이다.

만약 n=5라면 몇 번이 실행될까.

iterative 방식이라면 당연히 5번 반복될 것이다.

recursive 방식이라면 

fact (5) = 5* fact(4)
            = 5*4*fact(3)
            = 5*4*3*fact(2)
            = 5*4*3*2*fact(1)
            = 5*4*3*2*1 
            =120

4번? 5번?  정답은 5번이다. 

fact(4) -> fact (3) -> fact (2) -> fact(1) -> 1

fact(4)는 fact(5)가 실행한것이며 fact(3)은 fact(4) 라는 함수 안에서 실행한 것이다.
1은 fact(1)이라는 함수안에서 실행한 결과이다.

결국 iterative 방식과 recursive 방식 모두 n이라는 결과가 나왔다.

항상 이렇게 두 방식의 성능이 똑같은 것은 아니다.

그렇다면 recursive 방식의 성능이 월등히 우월한 경우를 살펴보자.


그 전에 recursive 방식의 특징을 반드시 알아야 한다.

Recursive function은 반드시 2부분을 포함해야 한다.

a) recursive call을 하는 부분
b) recursive call을 멈추는 부분 

앞서 살펴본 팩토리얼의 경우도 if문을 통하여 n<=1 라는 조건을 통하여 return 1;로 멈추는 부분이 있었다. 이 부분이 없다면 시스템 오류가 발생할 때까지 무한정 호출되게 된다.



2. 거듭제곱 

1) iterative approach

double iter_power(double x, int n ){

int i;
double r= 1.0;
for(i=0; i<n ;i++)
    r=r*i;

return r;
}

단순히 for을 사용하여 x의 n승을 계산하고 있다.

2) recursive approach

double power (double x, int n )

if( n == 0 ) return 1;
else if ( (n % 2) == 0 )
           return power( x*x , n/2 );
else
          return x*power(x*x, n-1/2);
}

위의 알고리즘은 상당히 좋은 아이디어를 사용하여 만들어진 알고리즘이다.

if문을 사용하여 recursive를 멈추는 부분과 조건에 따라 2개의 recursive 호출을 하는 부분으로 나누어 진다.

위의 코드를 수학식으로 나타낸다면 

n= 짝수일 때
power ( x , n ) = power ( x*x, n/2 )

n= 홀수일 때 
power ( x , n ) =x* power ( x*x, n-1/2 )

즉 2의 10승을 계산할 때 2를 10번 곱하는 것보다는 4를 5번 곱하는 것이 더 효율적이라는 것이다.

2의 10승을 계산할 때는  -> 4의 5승 으로 

4의 5승을 계산할 때는 -> 4* 16의 2승으로 

16의 2승을 계산할 때는 -> 256의 1승으로 계산하여 현저하게 곱하는 횟수를 감소시킨다.

총 수행 횟수는 

n = 10일 때

power(2,10)  =  power(4,5) -> power(16,2) -> power(256 ,1) -> power(256*256,0) -> 1

5번을 호출하게 됩니다.

iterative 방식이 10번을 다 호출하게 되는 것과는 달리 recursive 방식은 그의 절반인 5번만을 호출하게 됩니다.

정확히 수학식으로 표현하면 [ logn ]+2 로 표현됩니다. ([] 가우스내림 ) (n=1부터 해보세요 ㅋ )

빅오 표기법으로 나타내보면 두 방식의 성능은 O(n)과 O(logn) 으로 n이 커질 때 엄청난 성능 차이를 보이게 됩니다.

이 때문에 많은 알고리즘에서 거듭제곱을 사용할 때 recursive 알고리즘을 사용합니다.


'취미' 카테고리의 다른 글

안녕하세요.  (0) 2012.11.28
Posted by 사라링
BLOG main image
.. by 사라링

카테고리

사라링님의 노트 (301)
JSP (31)
J-Query (41)
JAVA (24)
디자인패턴 (1)
스트러츠 (3)
안드로이드 (11)
오라클 (45)
우분투-오라클 (1)
이클립스메뉴얼 (6)
스프링3.0 (23)
자바스크립트 (10)
HTML5.0 (17)
정보처리기사 (1)
기타(컴퓨터 관련) (1)
문제점 해결 (3)
프로젝트 (2)
AJAX (4)
하이버네이트 (3)
트러스트폼 (11)
Jeus (2)
재무관리(회계) (5)
정규식 (5)
아이바티스 (8)
취미 (2)
소프트웨어 보안 관련모음 (0)
정보보안기사 (6)
C언어 베이직 및 프로그램 (3)
보안 관련 용어 정리 (2)
넥사크로 (6)
웹스퀘어_ (0)
Total :
Today : Yesterday :