재귀(Resursion)란?


재귀(Recursion)란?

  - 위키에 따르면 자신을 정의할 때 자기자신을 재참조 하는것을 뜻하며 이를 프로그램에 적용한 재귀호출(Recursive Call)의 형태로 많이 사용된다고 한다.

 

재귀호출(Recursive Call)이란?

 - A함수를 정의할 때 A함수 코드 내부에 나 자신(A함수)를 다시 호출하는것을 말한다.

void Recursive(){
    printf("Recursive Call\n");
    Recursive(); // 재귀호출
}

재귀함수(Recursive Function)란?

  - 함수 내에서 자기자신을 다시 호출하는 함수를 말한다.

void Recursive(){ // 재귀함수
    printf("Recursive Call\n");
    Recursive();
}

 

재귀함수의 동작 원리

  - 재귀함수의 동작 원리를 그림으로 간단히 표현하면 아래와 같다.

<재귀함수의 동작 원리>

실제 위 코드를 디스어셈블해서 살펴보면 아래와 같다.

<테스트 코드>
<디스어셈블>

위 <디스어셈블> 사진을 살펴보면 printf 함수 호출 후 call c_test.851014 와 같은 명령어를 실행한다는 것을 볼 수 있다. 그리고 명령어 오른쪽 코멘트 부분을 살펴보면 C_TEST.c:5 라고 되어있는데 이는 C_TEST.c파일의 5번째 줄을 의미한다. <테스트 코드>를 살펴보면 5번째 줄에 있는 코드는 Recursive() 함수를 재귀호출하는 부분임을 알 수 있으며 <디스어셈블> 사진 속 851014 주소로 가보면 아래와 같이 Recursive 함수로 점프하는 것을 알 수 있다. 

<호출부분 확인>

즉, 실제 컴파일된 파일도 마찬가지로 내부적으로 위 <재귀함수의 동작 원리>의 그림대로 동작한다는 것을 알 수 있다. 그러나 위 코드를 실행시켜보면 잘 동작하다가 Stack overflow 오류가 발생한다.

<스택 오버플로우>

Stack overflow는 프로그램 내부에서 사용하는 스택(쉽게 말해서 특정 값들을 저장하기 위한 공간)의 크기보다 데이터가 많이 저장되어 발생하는 오류인데, 원인은 프로그램의 구조를 알면 이해할 수 있다.

위 <테스트 코드>를 이용해 간단히 설명하자면 프로그램은 함수(Recursive) 내부로 들어가게 되면 함수 호출 전 데이터들(함수의 지역변수, 호출이 완료되고 다시 돌아갈 주소 등)을 스택에 저장하게 되는데, 위 코드의 경우 함수가 종료되는 조건이 없기 때문에 무한루프를 돌게 된다. 따라서 계속해서 데이터들을 스택에 저장하게 되고 무한루프를 돌면서 저장된 데이터들의 크기가 일정 크기를 넘어가게 되면서 스택 오버플로우가 발생하게 된 것이다.

이러한 문제를 해결하기 위해서는 재귀함수엔 무조건 재귀함수를 탈출할 수 있는 조건이 있어야 한다. 그 코드는 아래와 같다.

<테스트 코드2>

위 코드를 간단히 설명하면 if (n == 0) 의 조건과 Recursive 함수의 파라미터로 n값을 받도록 코드를 수정하였고, 따라서 5번만 Recursive Call을 실행한 후 동작이 완료된다.

<실행결과>

위 <테스트 코드2>를 직접 비주얼 스튜디오에서 디버깅하면서 확인해보면 쉽게 알 수 있다.

'0x00. 자료구조' 카테고리의 다른 글

단순 연결 리스트  (0) 2021.10.11
순차 리스트  (0) 2021.10.06
공간복잡도(Space Complexity)란?  (0) 2021.05.05
시간복잡도(Time Complexity)란?  (0) 2021.04.30
자료구조란?  (0) 2021.04.25

공간복잡도(Space Complexity)란?


공간복잡도(Space Complexity)

 - 알고리즘을 수행할 때 필요한 메모리의 총량

 - Space Complexity = Auxiliary Space + Input Size Space

 - Auxiliary Space는 알고리즘을 실행하면서 필요한 임시변수 등을 의미

 - Input Size는 알고리즘에 전달되는 파라미터 값이나 문제해결을 하는데 사용되는 변수를 의미

 

프로그램의 메모리 사용

 - 프로그램의 명령어들

   => 컴파일러에 의해 컴파일된 명령어 mov, sub, ...

 

 - 환경적인 부분

   => A함수에서 B함수를 호출하면 A함수의 다음 위치 및 A함수에서 사용된 변수값들을 스택에 PUSH하고 B함수가 종료되면 A함수의 변수값들을 다시 POP해서 원래 내용대로 돌아오는 행위들

 

 - 데이터 공간

   => 변수 또는 상수의 메모리 양

 

알고리즘에서 공간복잡도를 구할때 보통 데이터 공간을 이용하여 계산함

 

예시)

int sum(int a, int b){
	return a + b;
}

위 예시에서 공간복잡도는 파라미터 a(4byte), 파라미터 b(4byte), return값(4byte)해서 총 12byte이며 빅-오를 이용하여 공간복잡도를 구하면 O(1)이 된다. 

 

int sum(int arr[], int b){
	int sum = 0;
	for(int i=0; i<b; i++){
    	sum += arr[i];
    }
    
    return sum;
}

위 예시에서 공간복잡도는 파라미터 arr배열(4 * n), 파라미터 b(4byte), 지역변수 sum(4byte), 지역변수 i(4byte), return값(4byte)해서 총 4n + 16이며 빅-오를 이용하여 공간복잡도를 구하면 O(n)이 된다.

 

 

[참고사이트]

1. www.studytonight.com/data-structures/space-complexity-of-algorithms

2. hoseockchoi.wordpress.com/2019/04/05/time-complexity-%EC%99%80-space-complexity-%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4-%EA%B7%B8%EB%A6%AC%EA%B3%A0-code-review-%EA%B4%80%EC%A0%90%EC%97%90%EC%84%9C-%EB%8B%A4%EC%8B%9C-%EB%B3%B4/

 

'0x00. 자료구조' 카테고리의 다른 글

단순 연결 리스트  (0) 2021.10.11
순차 리스트  (0) 2021.10.06
재귀(Recursion)란?  (1) 2021.05.08
시간복잡도(Time Complexity)란?  (0) 2021.04.30
자료구조란?  (0) 2021.04.25

시간복잡도란?

(Time Complexity)


시간복잡도라는 말 자체가 뭔가 되게 모순되어 보인다.. 그래도 한 번 살펴보자.

 

시간복잡도 (Time Complexity)

 - 입력 데이터가 특정 알고리즘을 거쳐 결과가 나오는데 걸리는 시간을 의미

   여기서 "시간"은 정확히 몇 초 걸린다! 그런 의미가 아닌 데이터의 증가에 따른 시간(연산속도)의 증가 정도를 의미

 - 시간복잡도는 대입연산, 사칙연산, 비교구문, 함수호출 등의 연산을 기준으로 계산

 - 시간복잡도는 최선, 평균, 최악의 경우로 나눌 수 있음

 

최선의 경우(빅-오메가, Big-Ω)  - 최선의 상황을 기준으로 시간복잡도를 측정
 - 대부분의 알고리즘은 빅-오메가로 시간복잡도를 측정했을 때 만족할만한 결과가 나와 실제로 잘 쓰이지 않음.
 - 예를들어, 특정 배열을 탐색하는 알고리즘에서 찾고자하는 값이 첫번째로 있을 경우
평균의 경우(빅-세타, Big-θ)  - 평균적인 상황을 기준으로 시간복잡도를 측정
 - 평균적인 상황이 무엇인가?에 대한 문제가 발생
 - 간단한 알고리즘의 경우에는 구하기 쉽지만, 조금만 복잡해질 경우 경우의 수가 많아져 평균적인 상황을 구하기 어려움
 - 빅-오 보다는 많이 쓰이지않지만 어느정도 쓰이는 것으로 보임
 - 예를들어, 동전 하나를 100회 던졌을 때 앞, 뒤가 나온 횟수의 평균적인 상황,
   앞, 뒤가 나올 확률이 무조건 50%인 상황 등
최악의 경우(빅-오, Big-O)  - 최악의 상황을 기준으로 시간복잡도를 측정
 - 최악의 상황을 기준으로 측정을 하게되면 입력데이터의 개수가 많더라도 이정도의 성능은 보장한다는 뜻이 됨
 - 대부분 알고리즘의 시간복잡도를 표현할 때 빅-오 로 표현함
 - 예를들어, 특정 배열에서 탐색 알고리즘을 이용해 탐색할 때 찾고자 하는 값이 배열에 없을 경우

빅-오(Big-O) 표기법

 - 단순히 시간복잡도를 표현한 다항식에서 최고차항의 차수가 빅-오가 된다.

 - 예를들어, 100n^3 + 99999n^2 + 888 이라는 시간복잡도를 가진 함수가 있을 때, 이 다항식을 빅-오 표기법으로 표현하면 O(n^3)이 된다. 99999n^2도 상당히 큰 수인데 제외하는 이유는 단순히 시간복잡도는 위에 언급한 것처럼 데이터의 증가에 따른 시간(연산횟수)의 증가 정도를 표현하기 때문이다. 

빅-오(Big-O) 표기법에 따른 계산방법

 - 다음과 같은 코드가 있을 때의 시간복잡도를 빅-오로 표현하면 어떻게 될까?

for(int i=0; i<sizeof(arr)/sizeof(int); i++){
	if (arr[i] == 7){
    	printf("7 => index %d\n", i + 1);
        break;
    }
}

배열 arr의 크기를 모르며 어떤 데이터가 들어있는지 모른다는 최악의 상황을 가정하고 구해보면 다음과 같다.

연산을 기준으로 시간복잡도를 구한다고 했으니

 

int i = 0 => 1회 연산
i<sizeof(arr)/sizeof(int) => n회 연산
i++ => n회 연산
arr[i] == 7 => n회 연산

 

이 된다. 따라서 위 코드의 시간복잡도는 T(n) = 3n + 1이 되며, 이를 빅-오로 표현하면 최고차항의 차수인 O(n)이 된다.

 

마지막으로 아래 사진은 대표적인 빅-오 이다.

<빅-오에 따른 증가형태>

자료구조와 각 정렬 방법의 빅-오는 아래 사이트를 참고하면 된다.

 

https://www.bigocheatsheet.com/

 

Big-O Algorithm Complexity Cheat Sheet (Know Thy Complexities!) @ericdrowell

Know Thy Complexities! Hi there!  This webpage covers the space and time Big-O complexities of common algorithms used in Computer Science.  When preparing for technical interviews in the past, I found myself spending hours crawling the internet putting t

www.bigocheatsheet.com

 

'0x00. 자료구조' 카테고리의 다른 글

단순 연결 리스트  (0) 2021.10.11
순차 리스트  (0) 2021.10.06
재귀(Recursion)란?  (1) 2021.05.08
공간복잡도(Space Complexity)란?  (0) 2021.05.05
자료구조란?  (0) 2021.04.25

자료구조란 무엇인가?


자료구조가 무엇인지 위키백과를 확인해보면 자료구조는 효율적인 접근 및 수정을 가능하게 하는 자료의 조직, 관리, 저장을 의미한다고 나와있다. 즉, 당연한 말이지만 위의 말 그대로 자료를 어떻게 구성(조직)할 것이고 어떤 방식으로 관리하고 저장할 것인지를 말한다.

자료구조는 알고리즘과 밀접한 관계를 맺고 있는데, 한가지 간단한 예를 들어보면 다음과 같다.

 

[예시]
반짝이가 일하는 편의점에 홈런볼 5박스가 들어왔는데 박스마다 유통기한이 다르게 들어왔으며 쌓여있는 순서도 유통기한 순서에 맞게 쌓여있는 것이 아니라 뒤죽박죽 섞인채로 쌓여있었다. 반짝이는 홈런볼 재고관리를 쉽게하기 위해 유통기한이 가장 길게 남아있는 박스를 아래에 쌓고 위로 쌓을수록 유통기한이 짧게 남은 박스를 올려두었고, 맨 위에 유통기한이 가장 짧게 남은 박스의 홈런볼부터 차례대로 매대에 진열해 놓았다. 진열된 홈런볼들이 다 팔릴때마다 한박스씩 맨 위에 쌓여있는 박스를 바닥으로 내려 홈런볼들을 꺼낸 후 진열하였다.

 

위 예시에서 홈런볼은 "자료"를 의미한다. 그리고 이 홈런볼들을 모아놓은 박스를 "조직"이라고 할 수 있다. 즉, 관련있는 것들(홈런볼)을 어떤 방식으로 구성(박스)할 것인지를 말한다. 그리고 유통기한 순서대로 홈런볼을 판매하는데 이것을 "관리"라고 할 수 있다. 이 박스들을 유통기한 순서대로 가장 길게 남은 박스는 아래에 두고 위로는 유통기한이 짧은 박스를 쌓아두는데 이 쌓아두는 것을 "저장"이라고 할 수 있다. 마지막으로 맨 위에 쌓여있는 박스를 바닥으로 내려 홈런볼을 꺼내는 행위를 "알고리즘"이라고 할 수 있다.

 

나중에 배우게 될 자료구조이지만 위 저장방식은 LIFO(Last-In First-Out)로 나중에 들어간 데이터가 먼저 나오는 자료구조인 스택을 이용하였으며, 알고리즘은 이 자료구조를 이용하여 어떻게 문제를 해결하는지를 말한다. 즉, 자료구조가 결졍되어야 그에 맞는 알고리즘을 결정할 수 있기 때문에 자료구조와 알고리즘은 밀접한 관계를 맺고 있다고 볼 수 있다. 물론 자료구조가 달라지면 알고리즘도 바뀌어야 한다. 위 예시에서 스택 자료구조가 아닌 큐(Queue) 자료구조가 쓰인다면 그에 맞는 알고리즘(맨 위의 상자를 아래로 내린 후 홈런볼을 꺼내는 행위)도 바뀌어야 한다는 뜻이다. 

'0x00. 자료구조' 카테고리의 다른 글

단순 연결 리스트  (0) 2021.10.11
순차 리스트  (0) 2021.10.06
재귀(Recursion)란?  (1) 2021.05.08
공간복잡도(Space Complexity)란?  (0) 2021.05.05
시간복잡도(Time Complexity)란?  (0) 2021.04.30

+ Recent posts