함수와 재귀함수를 호출할때, 어떤 블록이 호출되고 프로그램의 흐름이 어떻게 작동하는지 짚어보는 시간을 가지도록 하겠습니다.
함수와 블록의 이동
#include <iostream>
using namespace std;
void f(){
cout << "A";
return;
}
int main(){
cout << "B";
f();
cout << "C";
return 0;
}
다음 C++ 프로그램을 실행했을 때의 결과는 B -> A -> C
순으로 출력이 됩니다. 함수는 처음 만들었을 때는 아무런 실행을 하지 않으며, 먼저 main 함수나 다른 함수가 f();
구문을 통해 호출을 해주어야 그제서야 실행됩니다.
함수 안의 내용을 풀어 적은 것과 비슷한 역할을 하는 것이 함수의 호출입니다. f();
로 호출된 시점에서, 안의 내용물이 반드시 먼저 실행되고, 그 이후에 다시 호출되었던 원래의 블록으로 돌아와 남은 내용을 실행합니다.
함수의 목적
#include <iostream>
using namespace std;
int f(){
cout << "A";
return 0;
}
int main(){
cout << "B";
f();
cout << "C";
f();
cout << "D";
return 0;
}
이 소스코드에서의 실행 결과B -> A -> C -> A -> D
와 같이, 똑같은 함수를 여러번 실행할 수 있다는것이 함수의 주된 사용 목적입니다. 지금은 A
의 출력이라는 간단한 역할을 부여받은 함수이지만, 보다 복잡한 처리를 함수로 분리해 낼 수록 이를 재사용 가능하다는것이 큰 장점으로 작용합니다.
함수와 인자의 전달
매번 똑같은 작동만을 하는 함수는 자주 사용할 일이 적어지게 되기에,
하나의 함수가 보다 다양한 일을 처리할 수 있도록 "인자", 매개변수를 넘겨주게 됩니다.
수학에서의 f(x) 에 x라는 값이 바뀔 수 있듯이, C++에서의 함수에도 원하는 변수를 전달할 수 있습니다.
#include <iostream>
using namespace std;
int print(int K){
for(int i=0; i<K; i++){
cout << "*";
}
return;
}
int main(){
print(5);
return 0;
}
위 프로그램의 결과는 *****
으로,
함수 print(int K)
는 K라는 숫자를 입력받아
K개의 *
을 출력하는 함수입니다.
함수에 이렇게 명확한 의미를 부여하면, 문제를 해결하기가 더 간단해집니다. 백준 별 찍기 - 1 (2438번)
문제를 해당 함수로 해결하면
아래와 같습니다.
#include <iostream>
using namespace std;
int print(int K){
for(int i=0; i<K; i++){
cout << "*";
}
return;
}
int main(){
int N;
cin >> N;
for(int i=1; i<=N; i++){
print(i);
cout << "\n";
}
return 0;
}
1부터 시작해 N번까지 반복하는 i는 몇번째 줄을 출력할지 결정하고,
i번째 줄에 i개의 별을 출력하고 줄내림을 합니다.
함수와 반환값
main 함수는 반환값을 사용할 일이 없어 return 0;
만을 사용하지만,
일반적인 함수나 재귀함수는 반환값을 가질 수 있습니다.
함수에서 반환값을 넘겨주는 방법은
int f(){
return 5;
}
char f2(){
return 'A';
}
위와 같이 return 뒤에 넘겨줄 값을 적으면 됩니다. 넘겨줄 값은 변수와 식 둘 모두 가능합니다. 이때, 넘겨주는 값은 반드시 함수의 앞에 명시한 자료형 과 맞추어야 함에 유의해주세요.
반환값의 사용은
int A = f();
cout << f();
와 같이 함수의 반환값을 변수에 대입하는 것으로 사용 가능합니다.
두번째 줄과 같이 함수의 반환값을 바로 출력할 수도 있습니다.
재귀함수와 블록
재귀함수에서는 블록을 어떻게 이동하게 될까요?
#include <bits/stdc++.h>
using namespace std;
int f(int x){
if(x==0){
cout << "E";
return 0;
}
cout << "A";
f(x-1);
cout << "B";
return 0;
}
int main(){
f(3);
}
위 프로그램의 실행 결과는A A A E B B B
입니다. 실행 결과에 임의로 괄호를 치면 조금 더 명확해집니다.(A(A(A(E)B)B)B)
로 괄호를 쳐보았습니다.
A와 B 사이에 f(x-1) 이 실행되면서, 새로운 괄호가 생겨
그 안에서 다시 A와 B를 출력하는 구문이 실행되고 있습니다.
깊게 들어가다가 f(0)
이 호출되는 순간 탈출 조건을 충족하고,E
를 출력하고 탈출하면 f(0)
을 호출했던 f(1)
으로 돌아가게 됩니다.f(1)
은 B
를 출력하고 반환하며 f(2)
로 돌아가게 되며, 이렇게 들어갔던 순서의 역순으로 나오게 됩니다.
결론
함수는 사실 solved ac 기준 실버
에서는 크게 사용할 일이 없을 수 있으나, 골드
문제나 플래티넘
이상의 문제에서 매우 높은 빈도로 사용됩니다.
특히나 재귀함수에서, 들어갈때의 반대의 순서로 나온다는 이 특징이 깊이 우선 탐색(dfs)
알고리즘에서 굉장히 적극적으로 활용됩니다.
깊이우선탐색을 사용한 문제를 해결할 수 있다는 것은 코딩테스트 등에서 요구하는 영역에 도달했다는 것으로, 재귀함수에 대해 깊게 이해해두신다면 추후 dfs에 대해 공부할 때 분명히 도움이 될 것입니다.