재귀함수 문제

1. 횟수를 입력받은 다음, 입력받은 횟수만큼 "hello" 문자열을 출력하는 재귀함수를 만드세요.

[입력]

횟수 : 4

[출력]

결과 : hello hello hello hello

 

2. 대문자 A에서 Z까지 출력하는 재귀함수를 만드세요.

그리고 Z에서 A까지 거꾸로 출력하는 재귀함수도 만드세요.

[입력]

없음

[출력]

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

 

3. 문자열을 출력하는 재귀함수를 만드세요.

이때 문자열은 scanf 함수로 입력받도록 합니다.

[입력]

문자열 : This_is_a_recursive_call.

[출력]

결과 : This_is_a_recursive_call.

 

4. 범위를 표현하는 구조체가 있습니다.

struct RANGE

{

int from, to;

};

RANGE 구조체에 입력한 범위 안에 포함된 모든 정수를 더하는 재귀함수를 만듭니다.

from과 to 멤버 또한 범위에 포함되는 것으로 처리합니다.

[입력]

범위 : 5 11

[출력]

합계 : 56

 

5. 크기가 15인 int 배열을 선언하고, 0부터 11 사이의 난수로 채웁니다.

그리고 배열 내의 위치를 가리키는 정수를 입력받아서,

자신을 포함한 인접한 한 자리 정수들을 모두 -1로 바꾸는 재귀함수를 만듭니다.

[입력]

위치 : 7

[출력]

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

=============================================

3 5 8 10 5 2 0 0 8 3 11 9 1 8 0

3 5 8 10 -1 -1 -1 -1 -1 -1 11 9 1 8 0

 

 

재귀함수 문제

1. 횟수를 입력받은 다음, 입력받은 횟수만큼 "hello" 문자열을 출력하는 재귀함수를 만드세요.

[입력]

횟수 : 4

[출력]

결과 : hello hello hello hello

 

답: Qt

 

void printHello(int n)

{

if( n == 0)

return ;

else

{

qDebug("hello" );

printHello(n-1);

}

}

 

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

printHello(4);

return a.exec();

}

 

void main()

{

int count;

 

printf( "횟수 : " );

scanf( "%d", &count );

 

printf( "결과 : " ); PrintHello( count );

printf( "\n" );

}

 

void PrintHello( int count )

{

if( count > 0 )// 리턴 조건을 다름

{

printf( "hello " );

PrintHello( count-1 );

}

}

 

2. 대문자 A에서 Z까지 출력하는 재귀함수를 만드세요.

그리고 Z에서 A까지 거꾸로 출력하는 재귀함수도 만드세요.

[입력]

없음

[출력]

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

 

void printAlfabet(int n)

{

if( n < 65 || n > 90)

return ;

else

{

qDebug("%c", n);

printHello(n+1);

}

}

 

int main(int argc, char *argv[]){

QApplication a(argc, argv);

printAlfabet(65);

return a.exec();

}

 

역으로 출력하는 것은 초기값을 -1 시키면 된다.

 

void PrintUpper( char ch );

void PrintUpperRev( char ch );

 

 

void main()

{

PrintUpper( 'A' ); printf( "\n" );

PrintUpperRev( 'A' ); printf( "\n" );

}

 

void PrintUpper( char ch )

{

if( ch > 'Z' )

return;

 

printf( "%c ", ch );

PrintUpper( (char) (ch+1) );

}

 

void PrintUpperRev( char ch )

{

if( ch > 'Z' )

return;

 

PrintUpperRev( (char) (ch+1) );

printf( "%c ", ch );

}

 

3. 문자열을 출력하는 재귀함수를 만드세요.

이때 문자열은 scanf 함수로 입력받도록 합니다.

[입력]

문자열 : This_is_a_recursive_call.

[출력]

결과 : This_is_a_recursive_call.

 

void printStr(char* str, int nStart, int nEnd)

{

if(nEnd == nStart)

return

else

{

printf("%c",str[nStart]);

printStr(str, nStart+1, nEnd);

}

}

 

 

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

char str[20];

printf("문자열을 입력하세요. \n");

scanf("%s", str);

int len = strlen(str);

printStr(str, 0, len);

return a.exec();

}

 

#include <stdio.h>

 

void PrintString( char* str );

 

void main()

{

char str[256];

 

printf( "문자열 : " );

scanf( "%s", str );

 

printf( "결과 : " ); PrintString( str );

printf( "\n" );

}

 

void PrintString( char* str )

{

if( *str == '\0' )

return;

 

putchar( *str );

PrintString( str+1 );

}

 

4. 범위를 표현하는 구조체가 있습니다.

struct RANGE

{

int from, to;

};

RANGE 구조체에 입력한 범위 안에 포함된 모든 정수를 더하는 재귀함수를 만듭니다.

from과 to 멤버 또한 범위에 포함되는 것으로 처리합니다.

[입력]

범위 : 5 11

[출력]

합계 : 56

 

typedef struct RANGE

{

int from, to

}R

 

int printSum(int nStart, int nPlus)

{

if(nPlus == -1)

return 0;

else

{

return nStart + printSum(nStart + 1, nPlus-1);

}

}

 

 

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

R r

r.from = 5;

r.to = 11;

int nPlus = r.to - r.from

printf("%d", printSum(r.from, nPlus ));

return a.exec();

}

 

#include <stdio.h>

 

struct RANGE

{

int from, to;

};

 

int Summation( int from, int to );

 

void main()

{

struct RANGE range;

 

printf( "범위 : " );

scanf( "%d %d", &range.from, &range.to );

 

printf( "합계 : %d\n", Summation(range.from, range.to) );

}

 

int Summation( int from, int to )

{

int sum;

 

if( from > to )

return 0;

 

sum = from;

sum += Summation( from+1, to );

 

return sum;

}

 

 

5. 크기가 15인 int 배열을 선언하고, 0부터 11 사이의 난수로 채웁니다.

그리고 배열 내의 위치를 가리키는 정수를 입력받아서,

자신을 포함한 인접한 한 자리 정수들을 모두 -1로 바꾸는 재귀함수를 만듭니다.

[입력]

위치 : 7

[출력]

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

=============================================

3 5 8 10 5 2 0 0 8 3 11 9 1 8 0

3 5 8 10 -1 -1 -1 -1 -1 -1 11 9 1 8 0

 

void replaceFunc(int* nStart, int nSearch)

{

int* number = nStart + nSearch

if ( nSearch != 1)

{

if(*number > 9)

{

return;

}

else

{

if( *number < 10 && nSearch == -1 )

{

*number = -1;

replaceFunc(number, -1 );

}

else if( nSearch != -1 )

replaceFunc(number, -1 );

}

replaceFunc(number, 1 );

}

 

if( nSearch == 1)

{

if(*number > 9)

{

return;

}

else

{

if( *number < 10 && nSearch == 1 )

{

*number = -1;

replaceFunc(number, 1 );

}

else if( nSearch != 1)

replaceFunc(number, 1 );

}

}

}

 

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

int nNumber[15];

int start = 1;

for(int i = 0 ; i < 15; i++)

{

nNumber[i] = rand()%11;

printf("%d = %d \n", i,nNumber[i]);

}

replaceFunc(nNumber, 7);// 위치입력

for(int i = 0 ; i < 15; i++)

{

printf("\n%d = %d \n", i,nNumber[i]);

}

return a.exec();

}

 

 

#include <stdio.h>

#include <stdlib.h>

 

void Init( int array[], int size, int max );

void PrintRuler( int size );

void Print( int array[], int size );

void TurnUp( int array[], int size, int pos );

 

void main()

{

int array[15];

int seed, pos;

 

printf( "씨앗 : " );

scanf( "%d", &seed ); // 15가 적당

 

srand( seed );

 

printf( "위치 : " );

scanf( "%d", &pos );

 

PrintRuler( 15 );

 

Init( array, 15, 12 );

Print( array, 15 );

 

TurnUp( array, 15, pos );

Print( array, 15 );

}

 

void Init( int array[], int size, int max )

{

int i;

for( i = 0; i < size; i++ )

array[i] = rand() % max;

}

 

 

void PrintRuler( int size )

{

int i;

for( i = 0; i < size; i++ )

printf( "%2d ", i );

printf( "\n" );

 

for( i = 0; i < size; i++ )

printf( "===" );

printf( "\n" );

}

 

 

void Print( int array[], int size )

{

int i;

for( i = 0; i < size; i++ )

printf( "%2d ", array[i] );

printf( "\n" );

}

 

 

void TurnUp( int array[], int size, int pos )

{

if( pos < 0 || pos >= size )

return;

 

if( array[pos] < 0 || array[pos] >= 10 )

return;

 

array[pos] = -1;

 

TurnUp( array, size, pos-1 );

TurnUp( array, size, pos+1 );

}

 

 

void replaceFunc(int* nStart, int nSearch)

{

if( nStart[nSearch] < 0 || nStart[nSearch] >= 10)

return

nStart[nSearch] = -1;

replaceFunc(nStart, nSearch-1 );

replaceFunc(nStart, nSearch+1 );

}

 

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

int nNumber[15];

int start = 1;

for(int i = 0 ; i < 15; i++)

{

nNumber[i] = rand()%11;

printf("%d = %d \n", i,nNumber[i]);

}

replaceFunc(nNumber, 5);// 위치입력

for(int i = 0 ; i < 15; i++)

{

printf("%d = %d \n", i,nNumber[i]);

}

return a.exec();

}

 

수정한 코드

 

void replaceFunc(int* nStart, int nSearch)

{

//int* number = nStart + nSearch;

if(nStart[nSearch] > 9 || nStart[nSearch] < 0)

{

return

}

else

{

if( nStart[nSearch] < 10 )

{

nStart[nSearch] = -1;

replaceFunc(nStart, nSearch-1 );

replaceFunc(nStart, nSearch+1 );

}

}

// if( nSearch == 1)

// {

// if(*number > 9)

// {

// return;

// }

// else

// {

// if( *number < 10 && nSearch == 1 )

// {

// *number = -1;

// replaceFunc(number, 1 );

// }

// else if( nSearch != 1)

// replaceFunc(number, 1 );

// }

// }

}

 

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

int nNumber[15];

int start = 1;

for(int i = 0 ; i < 15; i++)

{

nNumber[i] = rand()%11;

printf("%d = %d \n", i,nNumber[i]);

}

replaceFunc(nNumber, 6);// 위치입력

for(int i = 0 ; i < 15; i++)

{

printf("\n%d = %d \n", i,nNumber[i]);

}

return a.exec();

}

'Computer Science > 알고리즘' 카테고리의 다른 글

재귀의 이해  (0) 2017.10.21
알고리즘의 이해(1)  (0) 2017.10.21

 재귀호출은 함수가 완료되기 이전에 자기자신을다시 호출하는 것이다.

 

 재귀알고리즘을 사용하려면 탈출 조건이 성립해야 한다.

 재귀는 트리구조이고 트리구조는 스택으로 되어있다

 즉 먼저 호출된 재귀가 나중에 탈출하고 가장 마지막에 호출된 재귀함수부터 진행이 된다.

 구조상으로

 함수호출1 --> 함수호출2 --> 함수호출3 --> 함수호출4 --> 함수호출5 --> 함수호출6 --> 종료조건

--> 함수탈출6 --> 함수탈출5 --> 함수탈출4 --> 함수탈출3 --> 함수탈출2 --> 함수탈출1 --> 프로그램종료

 

스택 구조인 것이 이해되는가?

트리를 이야기 한 것은 최상위 노드(첫 재귀호출)부터 반복적으로 재귀호출이 되면서 위에서 아래단계로 함수호출이 이루어진다.

단순 재귀일 경우 선형으로 보이지만 재귀 안에 재귀가 두 개일 경우 분기를 가지게 되어 트리 구조를 이루게 된다 

Ex)

Int Fibo(int n)

{

           If(n == 1 )

             return 0;

          else if ( n == 1 )

             return 1;

       else

         return Fibo(n-1) + Fibo(n-2);     // Tree 구조 처럼 함수호출이 진행 된다.

}

 

재귀 구조를 사용하려면 두 번째 시도 이후부터는 탐색 대상을 찾을 때까지 동일한 패턴을 반복한다.

------------------------------------------------------------------------------------------------------------------------------------------

동일한 패턴을 반복한다... 이 말이 중요한 것 같다.. 재귀는 직접 코드를 짜보면서 이해하자..

'Computer Science > 알고리즘' 카테고리의 다른 글

간단한 재귀 문제 풀이  (0) 2022.10.02
알고리즘의 이해(1)  (0) 2017.10.21

참고문서 - 윤성우의 열혈 자료구조

1차 작성 - 2016/03/04 (이글루스에서 옮김)

 

알고리즘을 평가하는 요소

시간복잡도 어떤 알고리즘이 더 빠르고 느린지 속도에 관한 것

공간복잡도 메모리를 적게 쓰고 많이 쓰는 지와 같은 메모리 사용량에관한 것

최적의 알고리즘은 메모리를 적게 쓰고 속도가 빠른 것

일반적으로는 속도에 초점을 둔다 속도에서의 기준은 연산 횟수를 들 수 있다.

 

책에서는 비교연산 즉 ‘==’ 값의 동등을 비교하는 연산을 적게 수행하는탐색알고리즘이 좋은 것이라고 나타나 있다

Ex)

for( I = 0 ; I < len ; i++ )

{

   If( ar[i] == target )       // 알고리즘의 복잡도를 분석할 수 있는 연산 부분

     return;

}

알고리즘의 성능 판단 최악의 경우로 비교한다

이유: 평균적인 경우로 판단해야 맞는다고 생각하기 쉽지만 실제로 평균을계산하거나 판단하기가 쉽지 않다 그리고 최악의 경우에 수행되는 연사의 횟수가 최선의 경우보다 더 큰 차이를 보이므로 대조하여 분석하기 쉽다.

부연 설명: 이를 평균적으로 계산하기 위해서는 다양한 이론이 적용되어야하고 분석에 필요한 여러 가지 시나리오와 데이터를 현실적이고 합리적으로 구성해야 정확한 시뮬레이션이 되는데 시간과 비용이 이를 감당하기 쉽지 않으므로쉽게 판단 가능한 최악의 경우로 비교하는 것이다.

  • 의문 최악의 경우로만 비교할 경우 생기는부작용은 없는가??  확률적인 느낌이다.. 정답은 없을 듯

 

-오 표기법

빅오 성능분석의 도구

시간복잡도라는 함수 T(n)에서 가장 영향력이 큰 부분이 어디인가는따지는 것

함수 T(n)은 알고리즘의 (비교)연산 횟수를 다항식으로 표현 한 것

보통 T(n)은 다항식으로n^2+2n+2 라고 할 때 최고차항 차수 n^2가 빅오가 된다.

  • 의문: 빅오를 구하는 이유는 무엇일까? 실제 알고리즘의 복잡도는 어떻게 구하고 판단해야 하는 가? 그 분석예를 알아 볼 순 없는가?

  • 빅오는 비교하는 도구로 생각하지 복잡도 공부는 전공공부를 따로 하자 (알고리즘 과목)

 

다항식의 차수로 나타내는 이유는 빅오는 X-Y 좌표평면의 그래프와같다

X축은 데이터의 개수, Y축은 시간을 나타내는데 빅오의 O(n^2)는 결국 f(x) = n^2인 이차 방정식 그래프와 같다. X(데이터 수)의 증가 에 따라 Y(시간 or 연산횟수)의 증가를 보여주는 그래프의 형태나 패턴을 나타내는것과 같다

 

 정리하면데이터의 수의 증가에 따른 연산횟수의 증가 형태를 표현 한 것이 빅오이다.

  • 질문: 빅오를 알아야 하는 이유는 무엇인가? 성능이겠지... 그리고 성능비교를 위해 근데 위 그림은 다시 공부하자

 

결과적으로 if구문이나 ‘==’와같은 조건 비교를 적게 써야 한다 (for문과 같은 반복문 포함)

데이터의 수가 많은 경우 순차검색보다 이진 트리 검색의 경우가 더 빠르다   

이중 for문으로 돌려야 하는 경우 순차접근을 사용할 수 있지만 데이터가 순서대로 정렬되어 있고 조건비교를 할 수 있는 경우 이진검색 또는 다른 방법으로 더 빠른 성능 속도를 낼 수 있는지 고민해 볼 수 있어야 한다.

-----------------------------------------------------------------------------------------------------------------------

알고리즘은 아직 논할만큼 충분한 공부를 못했다 (전공책 한번만이라도 처음부터 끝까지 읽어보자... 인터넷 검색은 단편조각만 제공한다) 

'Computer Science > 알고리즘' 카테고리의 다른 글

간단한 재귀 문제 풀이  (0) 2022.10.02
재귀의 이해  (0) 2017.10.21

+ Recent posts