728x90
반응형

이름 공간

  • 이름 공간이 존재 등장한 이유?

변수, 함수 등의 이름 충돌을 막기 위함이다.

  • 이름 공간

위와 같은 예제에서는 두 함수 모두 수행하는 내용은 다르지만 이름, 매개 변수가 같다는 이유로 오버로딩이 적용되지 않고 에러가 난다. 예제에서는 나타나지 않지만 두 함수 모두 다른 모듈이나 소스에 이미 의존되어 있는 부분이 있기 때문에 이름을 바꾸거나 할 수 없다. 이러한 경우 이름 공간을 이용한다.

위의 예제에서는 각 함수를 A, B라는 이름 공간(namespace) 으로 감싸고, 영역을 구분하였다. 영역을 구분하였기 때문에 함수 중복 문제로 오류가 발생하지 않는다. 그리고 24, 25번 라인에서는 ‘ :: ’ 범위 지정 연산자를 이용하여 이름 공간을 지정하여 그 내부의 함수를 지정하여 호출하는 식으로 함수 호출을 진행함.

  • 이름 공간 기반의 함수 선언과 정의 구분

이름 공간에서 동일한 이름 공간 내의 함수 호출 및 변수 참조가 일어날 경우 범위 지정 연산자를 이용하여 이름 공간을 명시할 필요가 없다.

  • 이름 공간의 중첩

이름 공간은 중첩이 가능하고, 범위 지정 연산자를 거듭 이용하여 범위를 지정하고 변수나 함수에 접근한다.

  • 이름 공간 std

std::cout, std::cin, std::endl 등은 모두 이름 공간 내의 어떤 요소들이었다.

위와 같은 형태로 존재하고 있는 요소들이고, cout/cin/endl 은 추후에 정리.

  • using 연산자를 이용한 이름 공간의 명시

위와 같이 이름 공간 전체를 명시하여 이름 공간의 범위 지정 연산을 생략할 수 있다.

위와 같이 이름 공간 내의 특정 요소를 지정하여 이름 공간 범위 지정을 생략할 수 있다.

아래는 이름 공간을 명시 혹은 이름 공간 내의 특정 요소에 이름 공간을 명시하여 범위 지정 연산을 생략한 예를 보여준다.

 

728x90
반응형
728x90
반응형

반복과 분기

  • 반복

반복을 명령하는 문장

While

왼쪽과 같은 형식으로 while문의 중괄호 속 내용을 반복하여 실행하는데 조건이 참인 경우에만 반복 내용을 실행하고, 조건이 거짓이 되는 순간을 꼭 만들어 주어야 한다. , 탈출 조건을 만들어 주어야 하는데 그 탈출 조건은 소괄호 속 조건과 반복 카운터 변수의 증감을 통해 이룰 수 있다.



For

역할은 while문과 완전히 같지만 형식이 주어져서 더욱 보기 깔끔하다 그러나 코딩의 유연성은 while문에 비해서 조금 떨어진다. for문의 동작 순서는 while문과 완전히 같다.

초기문 -> 조건문 -> 반복 내용 -> 증감문 -> 조건문 -> 반복 내용 -> 증감문 -> ~ -> 조건문 -> for문 종료

위와 같은 순으로 반복한다.



Do-While

위와 같은 형식으로 반복을 진행하는데, 다른 반복문과 다른 특이한 점은 반복 내용을 한 번은 무조건 실행하는 경우에 사용한다. Do~While 문은 조건과 상관없이 딱 한 번은 무조건 실행하게 되어 있다. 왜냐하면 조건을 밑에서 검사하는 형식이므로.

 

  • 분기

프로그램을 처음부터 끝까지 모두 실행하는 형태가 아닌 프로그램의 흐름을 원하는 형태로 제어하기 위한 구문.

If

아주 간단하게 소괄호 내의 조건이 만족하면 (참이면) 반복 내용을 실행하고, 만족하지 못하면 중괄호 속에 해당하는 내용은 통째로 실행하지 않고 뛰어 넘는다.

다음과 같이 중괄호의 생략도 가능한데 이러한 경우는 반복할 문장이 한 줄일 때만 가능하다.

다음과 같이 else 를 이용하면 위의 if 조건을 만족하지 않은 모든 경우를 다 받아들이는 구문이 존재한다. 여기서 기억해야하는 중요한 포인트는 else는 위의 if 조건에 부합한 모든 경우들을 수용하기 때문에 따로 조건 검사를 하지 않는다는 것이다. 위와 같은 포인트를 잘 기억하고 다음을 보도록 하자.

다음과 같이 여러 조건을 if문으로 채우는 경우에는 모든 조건을 하나하나 검사하게 된다. 예를 들어 사칙 연산을 택하는 프로그램이 존재할 때 더하기, 빼기, 곱하기, 나누기의 총 네 개의 연산이 존재하지만 결국 선택되는 연산은 하나이다. 그러므로 한 가지 연산이 선택되었을 때에는 나머지 연산에 대해서는 확인하는 작업은 필요로 하지 않다. 다만, if문으로 제시되는 조건들이 모두 연관이 있는 하나의 주제에서의 선택에 대한 조건임을 전제로 한다.

왼쪽의 경우가 하나의 주제에 대해서 선택을 할 때, 모든 조건을 다 검사하는 소스이고, 오른쪽의 경우는 어떤 조건을 만족하게 될 경우 그 조건보다 아래에 오는 조건들은 자연스럽게 무시하는 경우의 소스이다. 이것이 가능한 이유는 위에서 언급한 두 가지 조건으로 인해 가능해진다.

  1. 실행할 문장이 한 줄일 경우에는 중괄호를 생략할 수 있다.

  2. else는 위의 라인의 if 조건에 부합한 모든 경우들을 수용하기 때문에 따로 조건 검사를 하지 않는다

이 두 전제에 의해서 else if 라는 문장이 생긴다.

원래 형태의 소스이고, 이 부분에서 두 가지 전제를 적용하여 중괄호를 없애게 되면 else if 구문을 확인할 수 있다. else 바로 밑의 조건문은 모두 유기적으로 연관되어 있기 때문에 if 문과 함께 한 줄로 취급하는 것이다. 그렇기 때문에 else의 중괄호를 생략할 수 있는 것이다.

결국, if, else if, else 구문은 ifelse 구문을 중첩시킨 형태에 지나지 않는다.

조건 연산자(삼항 연산자)

If 조건문을 대체할 수 있는 조건 연산자이다. 다음과 같은 형식을 지니고 ‘?’, ‘:’ 두 개의 연산자와 세 개의 피연산자를 이용하여 조건에 대한 결과 반환을 수행한다.

다음은 위와 따른 예제이다.

Switch~Case

스위치~케이스문은 if문과 마찬가지로 분기를 통한 프로그램의 흐름을 제어해주는 방법 중 하나인데 if문과는 구조가 많이 다르고 조금은 제한적인 형태로 구성되어 있지만 간결하고 가독성이 좋아진다는 장점이 있다.

switch 키워드 옆 소괄호에는 분기 선택에 대한 정보가 담겨 있는 ‘정수형’ 변수가 인자로 전달되어야 한다. 그리고 그 전달된 값을 case 별로 나눈 것이 11, 14, 17번 라인이다. 여기서 짚어야 할 포인트는 분기의 조건으로 범위가 올 수 없고, 떨어지는 값의 형태로 분기가 일어난다는 것이다. 그리고 해당 case부터 break; 부분 사이의 실행 내용을 실행한다. breakswitch문 하나를 탈출하는 분기이며 반복문과는 관련이 없다. 만약 break를 생략하게 되면 전달되어온 인자의 값과는 상관없이 다음 case 영역의 break문 전까지 모조리 실행하게 된다. 그리고 마지막으로 default는 위에서 정의된 모든 case 분기에 빠지지 못한 경우는 모두 이 default 영역으로 분기된다. else와 같은 역할이라고 보면 된다.

goto

레이블을 이용하여 분기를 제어하는 형태이다.

‘ 레이블: ’ 형식으로 레이블을 마킹한 후, ‘ goto 마킹한_레이블명; ‘ 명령어를 통해 프로그램의 흐름을 마킹한 레이블 라인으로 변경한다.

goto문은 절차지향의 패러다임에 위배되는데 그 이유는 위에서 아래로의 순차적인 실행이 아니라, 뒤죽박죽 어느 라인의 위치이든 간에 상관없이 흐름 변경이 가능하다. , 프로그램의 자연스러운 흐름을 방해하기 때문이다.

Continue & Break

먼저, continue문이다.

위와 같은 형식을 갖추며 continue를 감싸고 있는 가장 가까운 반복문의 조건 검사 위치로 이동한다. 단순히 반복문의 상단으로 프로그램의 흐름이 이동하는 것이 아니라, 조건을 찾아가는 것이다. , do~while문에서는 위로 가는 것이 아닌 하단의 조건 위치로 프로그램의 흐름이 변경된다. 그리고 for문에서 continue문을 실행하게 될 경우에는 조건문을 실행하기 이전에 증감문 또한 실행한 뒤 조건문을 실행하러 상단으로 위치한다.

다음은 break문이다.

위와 같은 형식을 갖추며 break를 감싸고 있는 가장 가까운 반복문 하나를 탈출한다. 중첩된 반복문에서도 마찬가지로 break를 감싸고 있는 가장 가까운 반복문 1개’만 탈출한다.

728x90
반응형

'컴퓨터 언어 정리 > C 언어' 카테고리의 다른 글

07 1차원 배열  (0) 2020.09.11
06 함수와 변수의 생명주기  (0) 2020.09.10
04 상수와 자료형  (0) 2020.09.07
03 수의 표현 방식  (0) 2020.09.06
02 변수와 연산자  (0) 2020.09.06
728x90
반응형

지난 포스팅 때, 재귀는 믿음이 졸라 중요하다고 했다. 이번에도 마찬가지다.

그 전에 재귀를 공부할 때, 써야하는 경우에 대한 추가적인 기록이 필요할 것 같아서 먼저 기록한다.

재귀가 필요한 경우

재귀가 필요한 경우는 다음과 같다.

탈출 조건이 명확하고, 같은 작업이 계속해서 반복되는 경우.

피보나찌 수열에서는 n-2항과 n-1 항이 더해지는 부분이 반복된다.

Fibonacci(5) 이면 Fibonacci(4) + Fibonacci(3) 인데 Fibonacci(4)에도 Fibonacci(3)에도 n-2항과 n-1항이 더해지는 부분이 필요하기 때문에 반복이 되고, 이를 재귀로 구현했던 것이다.

이번 포스팅에서 구현해 볼 이진 탐색에서 또한 마찬가지다. 

가운데 값을 구한 후 비교 -> 범위 재설정 

이 작업이 반복되기 때문이다. 탈출 조건의 명확성은 말할 것도 없고 말이다.

이진 탐색에서도 믿음이 필요한가?

물론이다. 필요하다. 위에서 제시한 재귀가 필요한 경우믿음이 존재한다면 재귀 함수를 마음 놓고 신경도 안 쓰고 사용해도 된다.

728x90
반응형
728x90
반응형

재귀란 무엇인가?

피보나찌 수열 구하기이다. 재귀로 구해볼 것이다. 재귀는 매우 특이한 방법이 아닐 수 없다.

A라는 함수가 있을 때, A를 열심히 실행하는 도중에! 그것도 A가 미처 다 끝나지도 않은 채로 다시 A를 실행한다. 

이렇게 되면 와 진짜 너무 복잡한데, 또 두 번째 실행된 A안에서 또 A가 호출하면 와 진짜 머리 터진다.

극혐이다.

윤성우 선생님? 강사님? 교수님? 의 자료 구조에서 공부한 파트를 정리하게 되었다.

그냥 재귀를 하면 심심하니까 피보나찌 수열을 통해서 재귀 함수를 작성해보았다. 복잡할 수 있으므로 시간의 흐름에 따라 스텝을 밟을 것이다.

피보나찌 수열의 재귀적 구현

먼저, 다음은 피보나찌 수열이다.

0,   1,   1,   2,   3,   5,   8,   13,   ...

0번째 항과 1번째 항은 무조건, 지구가 멸망하지 않는 이상 0과 1로 각각 주어진다.(멸망하면 수학을 풀 필요가 없다) 그렇다면 2번째 항부터는 어떻구 구하는가?

  • 2번째 항을 구하는 방법 : 0번째 항의 값과 1번째 항의 값을 더한다.
  • 3번째 항을 구하는 방법 : 1번째 항의 값과 2번째 항의 값을 더한다.
  • 4번째 항을 구하는 방법 : 2번째 항의 값과 3번째 항의 값을 더한다. (ㄱ)
  • n번째 항을 구하는 방법 : n-2 번째 항의 값과 n-1 번째 항의 값을 더한다. ( 일반화 ) (ㄴ)

일단, (ㄱ) 까지의 상황을 코드로 정리해보겠다.

그렇다. 무식하다. 근데 이게 좀 쩌는 것이 무어냐면 ㅋㅋ,

  • Fibonacci(4); 의 결과 : 3
  • Fibonacci(3); 의 결과 : 2 
  • Fibonacci(2); 의 결과 : 1

함수의 결과가 중요하지 않다. Fibonacci 함수의 본질을 알려준다. Fibonacci 함수의 본질은 다음과 같다.

Fibonacci 함수에 원하는 항의 인덱스 값을 넣으면 해당 인덱스 항의 값을 구해줘요!

이게 진짜 개중요하다. 우리는 앞으로 만들 우리의 Fibonacci 함수를 믿어야 한다. 우리는 Fibonacci 함수의 인자로 원하는 항의 인덱스 값을 넣으면 해당 인덱스 항의 값을 내어준다는 사실을 믿어야한다. 믿음이다. 재귀 함수 루틴이 들어간다고 해서 이러한 사실이 부정인가? 아니다. 

위의 믿음을 가지고 특정 항을 생각해보자. 특정 항은 예를 들어 5번째 항의 값을 구한다고 생각하자.

Fibonacci(5) = Fibonacci(4) + Fibonacci(3);

재귀를 생각하지 말라. 믿음이 있어야한다.
Fibonacci(4)는 4번째 항의 값을 리턴할 것이라는 믿음.
Fibonacci(3)은 3번째 항의 값을 리턴할 것이라는 믿음.

이런 믿음을 바탕으로 (ㄴ)까지의 상황으로 아래와 같이 구현해보았다.

그렇다면, 실제로 어떻게 동작을 해보는지 재귀의 경우를 그려볼까?

 

피보나치 수열의 재귀적 구현의 동작 원리

그만 알아보자

728x90
반응형
728x90
반응형

이진 탐색을 구현해보았다.

이진 탐색에 대해 간단하게 기록하기 전에 이진 탐색의 전제 조건에 대해서 기록을 먼저 해보겠다.

이진 탐색의 전제 조건

  • 이진 탐색은 오름차순이든 내림차순이든 관계없이 '정렬'이 되어있는 연속된 배열 자료구조에서 적용된다.

이러한 전제를 갖는 자료구조를 대상으로 탐색을 진행하는 것이 이진 탐색이다. 그렇다면 왜 이진 탐색은 저런 전제를 갖나?
그 해답은 이진 탐색의 정의에 있다.

이진 탐색이란?

타겟을 탐색할 때, 전체 자료구조의 (1)최대한 가운데 위치하는 값과 타겟을 (2)비교하여 탐색의 범위를 비교한 가운데 값을 기준으로 왼쪽과 오른쪽 중 하나로 탐색의 (3)범위를 좁히고 다시 좁혀진 범위에서 최대한 가운데 값을 다시 비교하고 탐색의 범위 결정을 반복하여 타겟을 탐색하는 알고리즘이다.

이진 탐색은 반복이 들어간다. (4)반복이 들어간다는 의미는 탈출 조건이 필요하다는 뜻이다.

탈출 조건은 매우 당연하고 자연스럽다.

허나, 이 이유를 알기 전에 범위를 잡는다는 개념을 알아야 한다. 범위를 잡는 것은 여러 케이스들이 있을테지만 선형(배열) 자료 구조에서의 범위를 잡는다는 행위에 대해서 적어보겠다.

탐색할 범위를 잡는다는 것은 시작 인덱스끝 인덱스를 잡는 것이다. 쉽게 말해서 시작을 잡아야한다. 배열에서 시작과 끝을 잡는다는 의미는 시작 인덱스 값과 끝 인덱스 값을 잡는다는 것이다.

자, 그러면 세 가지의 경우가 있다.

  • 시작 인덱스 < 끝 인덱스
    : 정말 당연한 것이다. 탐색할 범위의 양 시작과 끝을 잡고 있다고 보면 된다.
  • 시작 인덱스 == 끝 인덱스
    : 이런 경우가 나올 수 있을까? 나올 수 있다. 시작 인덱스이자 끝 인덱스에 위치한 값이 타겟인 경우다. 운이 안 좋은 가장 최악의 경우인 것이다. 어떻게 이렇게 제일 끝에 나올 수 있어? 재수 없단 말이지! 이런 뉘앙스의 최악의 경우를 뜻하고, 이런 경우까지 고려하여 알고리즘의 성능 평가를 시행한다 실제로.
  • 시작 인덱스 > 끝 인덱스
    : 이런 경우가 가능할까? 알고리즘이고 말고를 떠나서 글자 자체만 보더라도 불가능하다. 고로, 탈출 조건이 된다. 이 경우는 해당 배열 자료구조에 타겟에 해당하는 값이 없기 때문에 발생하는 경우이다. 시작 인덱스와 끝 인덱스가 같은 바로 위의 경우에도 타겟이 검출되지 않으면 발생하는 경우이고, 이 경우에는 조건 제어를 통해 반복을 탈출해야한다. 왜냐고? 배열에 타겟이 없으니까!

자 그렇다면 구현하는데에 생각하는 순서를 좀 정리해본 것이 위 본문에서의 괄호 안의 숫자들이다.

  • (1)최대한 가운데 위치하는 값(을 구한다)
  • (2)비교
  • (3)범위를 좁힌다(결정한다)
  • (4) 탈출 조건

위 순서에 해당하는 부분들을 주석으로 표시해봤다.

728x90
반응형

+ Recent posts