배열 (Array)

배열선언
Java언어에서 배열을 사용하는 것은 2단계로 이루어진다.

예를 들어, 크기가 3인 int 배열 a를 선언한다고 가정해 보자.
1단계로, 배열을 가리킬 수 있는 변수 a부터 만들어야 한다.
int[] a; 
int[]는 int 배열형을 나타낸다.
여기에서 주의할 것은, a는 배열이 아니라는 것이다.
이것은 단지 배열을 가리킬 수 있는 변수일 뿐이다.
C언어와 비슷하게 다음과 같이 a를 선언해도 되지만,
그리 추천하지는 않는다.
int a[];
왜냐하면, 위의 표기 방식이 "int 배열형의 변수 a"라고 
보다 자연스럽게 읽히기 때문이다.
 
2단계로는 크기 3인 int배열을 만들고, 그 배열을 a로 하여금
가리키게 하는 것이다. 
a = new int[3];
new int[3]은 실제로 크기 3인 배열을 생성한다.
이 때 이것을 a에 대입하게 되면, 그 다음부터는 
a를 이용해서 이 배열에 읽고 쓸 수 있게 된다.

배열에 값을 쓰는 것은 다음과 같다.
a[0] = 10;
a[2] = 20;
C언어의 배열 사용하는 방법과 동일하다.
그리고 index를 사용할 때의 주의 점도 똑같다.
index는 0부터 시작하고, 크기 n보다 하나 작은 n-1까지 사용이 가능하다는 것이다.

또다른 배열선언 방법
위에서는 2단계로 나누어 배열을 선언하는 방법에 대해
설명했다.
하지만 이것은 아래와 같이 1단계로도 가능하다.
int[] a = new int[3];


배열의 초기화

배열을 선언함과 동시에 원하는 값들로 초기화시킬 수도 있다.

이것은 아래와 같이 할 수 있다.

int[] a = {1, 2, 3, 4, 5};

이것은 크기 5인 int배열을 만들고, 

값들로 1, 2, ..., 5를 채운 후, 변수 a에 대입한 것이다.


배열 각 요소에 순차접근

배열이 만들어지면, 그 요소들에 대해 순차적인 접근을 하기 위해서는

반복문을 이용하면 된다.

이를 위해서, for, while, do-while loop등을 이용할 수 있다.

int[] a = new int[3];

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

{

   a[i] = i;

}


int[] a = {1, 2, 3};

int i = 0;

while (i < 3) 

{

   System.out.println(a[i]);

   i++;

}


for each 문

Java 언어는 배열요소들에 대한 순차접근 방법을 위해

'for each' 문을 제공한다.

위의 예제코드는 아래와 같이 for each문을 이용하여 구현될 수 있다.

int[] a = {1, 2, 3};

for (int i: a)

{

   System.out.println(i);

}

분석해 보면, 아래 그림과 같이,

변수 i에는 반복문이 실행될 때마다, a[0], a[1], a[2],... 이런 식으로

순차적으로 값이 바뀌게 된다.

따라서 위 프로그램은 결과적으로 배열 a에 들어있는 값을 순차적으로 출력하게 된다.



배열의 길이

배열의 길이는 배열 안에 저장할 수 있는 공간의 개수와 같다.

배열을 선언할 때 크기로 지정하는 값이 바로 길이라고 할 수 있는데,

이것은 배열의 이름에 .length 를 붙여서 알 수 있다. 

아래 프로그램에서 크기가 10인 배열 m을 선언하고,

각 요소마다 값을 지정하는 프로그램에서, 배열의 크기를 m.length로 지정하였다.



자세한 설명

위의 내용을 동영상에서 보다 자세한 예를 들어 설명합니다. 



반응형
LIST

java.util.Scanner 클래스: 키보드로부터 입력받아들이기.

키보드로부터 입력되는 값을 받아야 할 경우에는
java.util.Scanner 클래스를 이용하면 편하다.

이것을 사용하여 
키보드 입력하는 두 개의 숫자를 받아 들이고,
이 중에서 큰 값을 출력하는 프로그램은 아래와 같이 
작성할 수 있다.





자세한 설명.
위의 내용을 동영상에서 자세히 설명합니다.


반응형
LIST
입력을 받기위한 InputStreamReader 클래스에 대해 설명합니다.


반응형
LIST

Typecasting에 대해서 설명합니다.



반응형
LIST

Java언어에서 지원하는 데이터 타입에 대해서 설명합니다.



반응형
LIST

Java 프로그램에서 변수 이름 붙이는 방법에 대해서 설명합니다.



반응형
LIST
Java 프로그램의 기본구조에 대해서 설명합니다.



반응형
LIST
Java Archive (jar)에 대해서 설명합니다.




반응형
LIST




Eclipse: Java Integrated Development Environment (IDE)의 최강자


eclipse라는 프로그램이 있다.

Java 소스코드를 작성하고, 컴파일할 때 사용하는 도구 프로그램이다.

이런 프로그램을 IDE (Integrated Development Environment)라고 한다.

우리 말로는 '통합개발환경'.

Java IDE가 많지만,

그 중에서도,

제일은

Eclipse가 아닐까 쉽니다.

그리고

무료다.


Eclipse설치

www.eclipse.org 사이트로 간다.

다른 거 좀 살펴보다가,

우축에 다운로드를 클릭한다.



Eclipse설치를 도와주는 installer를 다운로드 받아서

실행하면 된다.

윈도우즈, 맥, 리눅스, 다 있다.

32 bit, 64 bit 다 따로.

보통은 윈도우즈 32 bit나 64 bit를 다운로드 받으면 된다.

안전빵은 32 bbit



아래와 같이,

무엇을 설치할 것인지를 물어본다.

당연히,

Java개발자를 위한 Eclipse통합개발환경을 선택한다.

아래에 선택된 것 말이다.


설치할 폴더를 지정하고 나면,

더 이상은 할 것이 없다.

설치가 끝날 때까지 기다리면 된다.

삭제는 더 쉽다.

설치된 폴더를 통째로 지워버리면 된다. 쉽다. 깨끗하다. 개운하다.





Eclipse 사용법에 대해서 설명합니다.




반응형
LIST


Java프로그램 개발을 위한 환경 구축


이제부터 프로그램을 짜 보려면,

그걸 하기위한 환경을 컴퓨터에 설치해야 한다.

우선, 용어 설명부터


JVM: Java Virtual Machine

이건 가상머신.

설명을 앞에서 너무 많이 해서 패스


JRE: Java Runtime Environment

이것은 JVM 더하기 Java Class Library 이다.

Java Class Library는

프로그램 짜는 데 필요한 기본적인 라이브러리를 말한다.

모든 것을 프로그래머가 일일이 다 짜려면 힘드니,

기본적으로 제공해주는 라이브러리이다.

따라서,

JRE는 가상머신과, 그 위에서 실행되는 프로그램이

필요한 라이브러리를 합쳐 놓은 것을 말한다.

그래서,

Java 프로그램을 개발하는 것이 아니라,

남이 만들어놓은 Java 프로그램을 가져다 실행만 하려면,

JRE만 설치하면 된다.


JDK: Java Development Kit

용어가 많기도 하다.

JVM, JRE, 이젠 JDK까지.

JDK는 JRE 더하기 Java컴파일러와 기타도구 들을 말한다.

뭔가 규칙이 보이지 않는가?

JDK = JRE + Java컴파일러

JRE = JVM + Java Class Library

JVM < JRE < JDK 

이런 관계에 있다.


JDK 설치

개발을 위해서는

검색엔진에 "JDK download"를 입력해서,

Oracle사의 JDK 페이지로 

이동한다.


그러면, 아래와 같이 여러가지 JDK 버전들이 나오는데,

이 중에서

Java SE (Standard Edition)을 선택한다.

그리고, JDK 다운로드를 클릭



아직 끝난 것이 아니다.

Java SE도 운영체제별로 여러 가지 버전이 있다.

이 중에서 윈도우즈 운영체제이면, 

32bit 냐, 64bit를 골라서 설치하면 된다.

제일 안전빵은

32bit를 골라서 설치한다.

이것을 다운로드 받은 다음에 실행하면, JDK 설치 끝




Java Development Kit (JDK)에 대해서 설명합니다.




반응형
LIST


Platform Independency

플랫폼 독립성.

굉장히 멋진 단어들이다.

내용은,

앞 차시에 설명했던 대로,

Java언어로 짜고, 빌드한 실행프로그램은

운영체제에 상관없이 돌아갈 수 있다는 것이다.


Platform-dependent language C:

반면에,

C언어 프로그램은 운영체제와 상관있다.

그래서,

멋진 말로 표현하자면,

C언어는 platform dependent하다고 한다.


Java 소스코드의 확장자: .java

프로그래밍 언어별로

고유의 확장자가 있다.

C언어 확장자는 .c

C++언어 확장자는 .cpp

요즘 한참 뜨고 있는 Python언어 확장자는 .py

이렇듯이

Java언어의 확장자는 .java 이다. 확장자치곤 좀 길다.


Java 빌드의 결과: 바이트 코드

Java 소스코드를 빌드하면

가상머신이 수행할 수 있는 코드가 생성되는데,

이것을 바이트코드라 하고, 아래처럼 생겼다.



바이트코드의 확장자: .class

소스코드를 빌드해서 나온 바이트코드는 

새로운 확장자를 갖게 되는데,

이것이 .class이다.

즉, hello.java 소스코드를 빌드하면,

hello.class 바이트코드가 나오게 된다.

그러면 이 바이트코드를

가상머신이 실행하게 되는 것이다. 


정리: Java 실행프로그램의 생성 순서

1. Java 소스코드를 작성한다. 이 때 확장자는 .java가 된다.

아래 그림과 같이 HelloWorld.java와 같은 소스코드가 

만들어진다.

2. 빌드를 하기 위해서, Java Compiler(컴파일러)를 이용한다.

컴파일러는 소스코드를 바이트코드로 변환시킨다.

생성되는 바이트코드의 확장자는 .class이다.

3. 마지막으로, 생성된 바이트코드는 가상머신 (JVM)위에서 실행된다.


바이트코드 생성의 진실

좀 더 자세한 내용을 들여다 보자.

바이트코드가 생성되는 과정에서

단순히 컴파일러를 사용하는 것은 아니다.

Java의 platform independency를 보장하는 것은

공짜로 얻는 것이 아니다.

이를 위해서 가상머신을 사용하는 것은 물론,

컴파일러도 운영체제별로 별도로 있다.

아래 그림에서 

컴파일러는 javac.exe 프로그램이지만,

각 운영체제, HW별로 다 다르다.

따라서, Java 프로그램을 작성하는 운영체제와 HW에 따라

별도의 컴파일러를 설치해서 사용해야 한다.

정리하자면,

Java 소스코드와 바이트코드는 platform independenct하다.

그러나,

컴파일러는 platform dependent하다.

또한,

가상머신도 patform dependent하다.

아래 그림에서 java.exe로 표시된 것이 가상머신이고,

그림에는 Java interpreter라고 표시되어 있다.

Interpreter라는 것은 사전적인 의미로 '통역자'인데,

바이트코드를 실제 '통역'해서 컴퓨터가

실행하도록 하는 것이다.

사실, Java interpreter가 가상머신을 구동시키는 구조로 되어 있다. 



바이트코드의 진실

만약 바이트코드에 대해서 좀 더 알고 싶다면,

아래 그림을 보자.

왼쪽은 Java코드로 작성한 것이고,

오른쪽은 이에 해당하는 바이트코드이다. 

그러면 중간은 무엇인가?

이건 바이트코드를 사람이 볼 수 있는 형태로

line-by-line으로

바꾸어 놓은 것이다.

이런 과정을 '역어셈블' (disassemble)이라고 한다. 

왜? 

이런 것이 필요할 때가 있다. 특히 디버깅할 때.


짧은 Java 소스코드지만,

바이트코드로 바꾸면, 

아주 간단한 명령들의 긴 순서로 바뀌는 것을 볼 수 있다.

사실, 컴퓨터는 아주 간단한 일들만 빠르게 할 수 있다.

그러므로, 복잡한 일을 시키려면,

간단한 일들을 조합해서 시켜야 하는 것이다.




Java 컴파일러와 인터프리터, 가상머신의 설치

Java 프로그램을 개발해서 실행해 보려면,

대충 감 잡았듯이,

컴파일러, 인터프리터, 그리고 가상머신을 먼저 설치해야 한다.

그것도 운영체제에 따라 각각 다른 것을..

그런데, 굿뉴스가 있다,

이 모든 것이 무료이고,

한 방에 다운로드 할 수 있다는 것이다.

컴파일러+인터프리터+가상머신, 이 세 개의 종합세트를

Java Development Kit (JDK)라고 하고,

이것에 대해서는 다음 차시에서 배운다.


Java언어의 patform independency에 대해서 설명합니다.



반응형
LIST


자동차 vs. 전기자동차




위 사진은 Elon Musk라는 사람이다.

'일란 머스크'라고 읽는다.

남자다.

남아프리카공화국 태생이지만,

미국에 산다. 미국 영주권이나 시민권이 있을 것이다.


이 사람이 한 일 중에 하나가

전기자동차를 대중화시킨 것이다.

'테슬라'라는 회사를 세워서

다소 가격은 비싸지만 실제로 사람들이 구매할 수 있는 전기차를 

생산해 낸 것이다.



기름을 넣고 달리는 자동차와

전기로 달리는 자동차는 확연히 다르다.

이런 차이만큼이라,

서로 다른 것이

C언어와 Java언이다.


C언어: 함수기반으로 프로그래밍

C언어로 프로그래밍 한다는 것은,

함수들을 만들고,

이것들을 레고블럭처럼 조합해서

프로그램을 완성하는 것이다.

예를 들어, 

C언어가 제공하는 printf, scanf, 등등 여러 가지 함수들이 많았다.

결국 C 프로그래밍한다는 것은

이런 함수들을 호출하는 순서와 방법들의

조합이었던 것이다.


Java언어: 객체기반으로 프로그래밍

반면에,

Java 언어는 object기반, 혹은 객체기반 언어이다.

여러 가지 객체들을 만들어 놓고,

이것들을 조합해서 프로그램을 완성하는 것이다.

그러면,

객체란 무엇인가?

쉽게 말해서, 데이터와 그 데이터를 접근할 수 있는 함수들로 이루어진 것을 말한다.

이 객체에 대해서 배우는 것이

Java언어를 배우는 것이니,

지금 당장 와닿지 않더라도 걱정할 필요가 없다.


C언어 프로그램과 운영체제

C언어로 프로그램을 만들면,

빌드 과정 (컴파일 + 링크 과정)을 거쳐서

실행파일로 만든 다음에

사용한다.

예를 들어, 이렇다.

윈도우즈가 깔린 PC에서

Visual Studio 같은 것을 이용해서 프로그램을 만든다고 하자.

C언어 소스코드로 프로그램을 짜고,

빌드하고, 실행파일이 나오면 그걸 수행시킨다.

이 때,

이 실행파일을 다른 운영체제,

예를 들어, Linux, Android, Mac OS X, iOS가 설치된

PC나 기기에 넣고 돌릴 수 있을까?

안 된다.

되게 하려면, 소스코드를 가져다가,

그 PC나 기기에서 빌드를 해서

새로 실행파일을 만들어야 한다.

왜냐하면,

빌드하는 과정에서 '그 운영체제'에만 돌아가도록 만들어진

실행파일이 만들어지기 때문이다.


크로스 컴파일

윈도우즈 PC에서 빌드하면서 리눅스 PC에서 돌아가도록 실행프로그램을

만들 수도 있다. 

그런데, 이 실행프로그램은 윈도우즈 PC에서는

실행이 안 되고.

리눅스 PC에서만 돌아간다. 

이렇게 빌드하는 것을 크로스 컴파일(cross compile)이라고 한다.

여기에서 빌드해서 저리로 넘겨 (cross) 주기 때문이다.


포팅

윈도우즈 PC에서 작성한 C언어 소스파일을

리눅스 PC로 옮겨서 빌드만 다시 해서 실행파일을 만들면,

바로 수행이 가능할까?

결론은 그럴 수도 있고, 아닐 수도 있다.

'아닐 수 있는' 경우는

소스코드를 작성하면서, 

윈도우즈 운영체제만 제공하는 특수한 함수를 사용하는 경우이다.

당연히 리눅스에서는 그런 함수를 제공하지 않으니,

리눅스에서는 빌드과정이 제대로 될리 없다.

그러면 어떻게 해야 하나?

'특수 함수'를 리눅스에서 유사한 기능을 제공하는 함수로

바꿔야 한다. 즉, 소스코드를 수정해서.

이 과정을 포팅 (porting)이라고 한다.

실제로 이 포팅과정을 회사에서는 많이 한다.

같은 윈도우즈 운영체제라 할지라도 버전에 따라서,

예를 들어 윈도우즈 XP, 7, 8, 10 등등,

제공함수가 달라지기 때문에,

이 때마다 소스코드를 수정해서 포팅을 해야 하는 것이다. 


Java프로그램과 운영체제

Java언어로 소스코드를 작성하면,

C언어와 마찬가지로 빌드과정을 거쳐서

실행파일을 만든다.

그런데, 이 실행파일은

윈도우즈, 리눅스, 맥, 어디서든 돌아간다.

원래

Java언어의 설계 목적 중의 하나가

C언어가 운영체제때문에 겪는 문제점을 없애기 위한 것이기 때문이다.

어떻게 이런 마법이 가능한 걸까?

세상에 공짜는 없다.

결론부터 말하자면 가상머신 (Virtual machine) 때문이다.

어느 운영체제이든,

우선 가상머신을 동작시키고,

그 위에서 Java 프로그램을 동작시킨다.

이러면,

Java프로그램 입장에서는

자기가 어느 운영체제 위에 있는지

알 수도, 알 필요도 없어진다.

그래서, 운영체제와 상관없이

한 번 빌드된 Java프로그램은

어떤 컴퓨터든지 가상머신만 있다면

수행될 수 있는 것이다.

그럼,

가상머신은 무엇인가?

쉽게 말하자면, 하나의 프로그램에 불과하다.

다만 이 프로그램은 자기 안에서 다른 프로그램이 수행되도록 한다.




위 그림에서

JVM이라고 표시된 것들이,

Java Virtual Machine (자버 가상머신)이라고,

위에서 설명한 가상머신들이다.


그리고,

참고로

C언어에서는 소스코드를 컴파일해서 나오는 

이진파일들을 오브젝트코드라고 부르는데,

Java언어에서는 바이트코드라고 부른다.


C언어와 비교하여 Java 언어를 설명합니다.





반응형
LIST

알고리즘이 우수한가?

같은 문제에 대해 이를 해결할 수 있는 알고리즘은 여러 개가 있을 수 있다.

어느 것이 더 우수한지 비교할 수 있는 기준은 무엇인가?

기준은 크게 두 가지가 있다.

하나는 시간이고, 다른 하나는 공간이다.

시간은 알고리즘을 이용해서 문제를 풀 때 시간이 얼마나 소요되느냐 하는 것이다.

공간은 알고리즘이 수행되기 위해서 얼마만큼의 메모리가 필요하느냐 하는 것이다.


시간복잡도,  

알고리즘의 우수성을 사용하는 시간측면에서의 기준을 말한다.

영어로는 time complexity.

예를 들어,

1부터 정수 숫자 n까지 모든 숫자를 더해서 합을 구하는 문제를 생각해보자.

이 문제를 푸는 방법에는 두 가지가 있다.

즉, 두 가지 알고리즘이 있다.

첫 번째 알고리즘은 누구나 생각할 수 있는 간단한 방법이다.

1부터 n까지 숫자를 하나씩 더하면 된다.

C언어로 프로그래밍하면 다음과 같다.

 


두 번째 알고리즘은 파스칼이 생각해낸 방법이다.

어린 시절 파스칼은 1부터 10까지의 합이 55라는 것을 

아래와 같은 천재적인 방식으로 알아냈다.


어느 것이 시간복잡도면에서 더 우수한가?

첫 번째 알고리즘은 n이 커질수록 계산하는 데 시간이 더 오래 걸린다.

for-loop 반복횟수가 많아지기 때문이다.

두 번째 알고리즘은 n의 크기와 상관없이 아래와 같은 공식으로 계산이 가능하다

따라서 두 번째 알고리즘이 첫 번째보다 시간 복잡도면에서 우수하다고 할 수 있다.


Big-O notation

시간 복잡도를 나타내기 위해서 사용하는 표현식이다.

읽을 때는 '빅 오 노테이션'이라고 읽는다.

첫 번째 알고리즘의 시간복잡도를 big-O notation으로 쓰면

O(n)이 된다. 

즉, n에 비례하여 걸리는 시간도 그만큼 증가한다는 것이다.

두 번째 알고리즘의 시간복잡도는 O(1)이다.

즉, n에 상관없이 항상 일정(1)하다는 것이다.

특히 어떤 문제에 대해 O(1) 알고리즘을 만들어 낼 수 있다면 

최상의 해결책을 찾아낸 것이다. 


다양한 시간복잡도

O(n) 시간복잡도의 알고리즘과 시간복잡도를 보자면

당연히 후자 알고리즘이 시간이 더 많이 걸린다는 것이다.

이 외에도 같은 것도 있다.

이것은 보다는 우수하지만, O(n)보다는 시간이 오래 걸리니 좋지 않다.



알고리즘의 시간복잡도를 나타내는 Big-O notation에 대해서 설명합니다.


반응형
LIST



1. 데이터구조, 매우 중요한 전공지식


대부분의 대학 컴퓨터관련 학과에서 2학년에 배우는 과목 중에 가장 중요한 과목은 자료구조 (Data structure) 혹은 데이터구조이다. 아래는 미국 명문 스탠포드 대학교 (Stanford university)의 컴퓨터과학과 (Department of computer science)에 편성된 전공필수과목인 "Data structures and Algorithms"과목에 대한 설명이다. 이 과목이 바로 데이터구조 과목인 것이다.





2. 데이터구조, 기술면접의 핵심


데이터구조 과목에서 배우게 되는 것들이 요즘 취업면접과정에서 흔히 기술면접과정에서 흔히 나온다. 예를 들어 숫자정렬, sorting이라는 것이 있다. 10, 6, 4, 1, 45, ... 와 같이 무작위 순서로 숫자들이 주어졌을 때 이들 숫자를 오름차순 혹은 내림차순으로 정렬하는 것을 sorting이라고 한다. Sorting하는 방법은 크게 4가지가 있는데, 기술면접에서는 이들 중에서 한 가지를 직접 구현해 보도록 시키는 경우가 많다고 한다. 물론 이 정도 문제는 난이도가 쉬운 편에 속한다. 기술면접 문제의 대부분은 이 데이터 구조에서 나온다. 


미국의 구글, 페이스북, 마이크로소프트 같은 회사들은 오래 전부터 직원채용 면접을 할 때 코딩면접을 시행해 왔는데, 여기에서 데이터구조의 내용을 많이 물어본다고 한다. 면접이 진행되는 방식은 다음과 같다. 면접은 작은 회의실 같은 곳에 진행되는 데, 거기에는 화이트보드, 즉 칠판이 하나 있다. 면접자가 문제를 주면, 피면접자는 화이트 보드에 문제를 풀기위한 핵심코드나 아이디어를 써 가면서 설명해야 한다. 


3. 핵심개념: 데이터는 컴퓨터가 처리할 수 있는 모든 것이다.


컴퓨터 영역에서 데이터는 무엇이든 될 수 있다. 회사의 재정정보를 나타내는 숫자일 수도 있고, 개인이 운영하는 블로그의 글이 될 수도 있고, 유튜브 같은 곳에서 서비스하는 동영상이 될 수도 있고, 멜론에서 보내주는 음원이 될 수도 있다. 또는 정류장의 버스 도착정보가 될 수도 있다.


4. 핵심개념: 데이터구조는 데이터를 어떻게 배치할 것인가에 대한 것이다.


데이터구조는 사실 두 단어의 합성이다. 즉 데이터 + 구조 이다. 순 우리말로는 자료구조, 순 영어로는 data structure. 영어의 data와 우리 말의 구조를 합쳐서 데이터 구조라고 한 것이다. 물론 자료구조라고 해도 되고, data structure라고 해도 된다. 


데이터구조를 비유를 통해 설명해 보자. 교실 안에 학생들이 있다고 하자. 이 때 학생들은 데이터가 된다. 마침 수업이 토론수업이면 4명씩 서로 마주보면서 앉는 것이 수업하기에 편할 것이다. 그렇지 않고, 선생님이 설명하는 강의라면 줄을 지어 앉는 것이 효율적일 것이다. 점심배식을 할 때는 한 줄로 늘어서서 식판에 밥을 받아가는 것이 좋을 것이다. 이렇듯 데이터구조는 데이터의 배치형태를 말한다. 이러한 배치형태는 굉장히 많기 때문에 매우 다양한 데이터구조들이 가능하다. 하지만 필요와 상황에 따른 적절한 데이터구조는 판단할 수 있을 것이다. 예를 들어, 토론수업시간에 학생들이 일렬로 줄지어 서는 것보다는, 4명씩 짝지어 마주 보고 앉는 것이 더 바람직한 것처럼 말이다. 


이미 유용하다고 알려진 데이터구조들이 많다. 그래서 데이터구조 과목에서는 이러한 것들을 배우게 된다. 그런데 이런 데이터구조들 각각은 레고조각과 같아서, 서로 다른 구조들을 합성해서 또 다른 구조들을 만들어낼 수도 있다. 


5. 핵심개념: 알고리즘은 컴퓨터가 어떤 문제를 처리하기 위한 절차, 순서를 말한다.


컴퓨터에게 다음과 같은 일을 시킨다고 가정하자. 숫자 10개를 주고 짝수에는 모두 1씩 더해서 홀수로 만들고, 홀수는 2를 곱해서 짝수로 만든다고 하자. 과연 컴퓨터에게는 이 일을 어떻게 지시해야 할까? 사실 컴퓨터에게 일을 시킬 때에는 아주 구체적으로, 세세히 단계단계 설명해 줘야 한다. 예를 들어 다음과 같다.

1단계: 숫자를 읽는다.

2단계: 1단계에서 읽은 숫자가 짝수이면, 그 숫자에 1을 더한다. 4단계로 간다.

3단계: 1단계에서 읽은 숫자가 홀수이면, 그 숫자를 두 배한다. 

4단계: 10개 숫자를 모두 읽어서 처리를 끝냈으면 일을 끝낸다. 아니면 1단계부터 다시 반복한다.


위에서 설명한 1~4단계와 같이 컴퓨터가 일을 처리하는 절차를 정의한 것을 알고리즘이라고 한다. 이 알고리즘은 주어진 문제 (10개 숫자를 짝수와 홀수에 따라 변환)를 처리하기 위한 절차이다. 문제가 간단하기 때문에 알고리즘이 매우 간단했다. 보다 복잡한 문제라면 알고리즘도 복잡해 질 것이다. 정리하자면, 알고리즘은 주어진 문제를 해결하기 위해 컴퓨터가 수행해야 하는 절차를 규정한 것을 말한다.


6. 알고리즘의 표현: 글, pseudo code, 순서도


알고리즘을 표현하는 방법은 크게 세 가지라고 할 수 있다. 첫 번째 방법은 그냥 글로 쓰는 것이다. 위에서 1~4단계도 글로 표현한 예가 되겠다. 이렇게 했을 때 단점은 군더더기가 많아진다는 것이다. 그래서 나온 것이 pseudo code이다. Pseudo는 "수도"라고 읽는다. P가 묵음이다. 뜻은 "의사"인데, '비스무리 하나, 그것은 아님', 혹은 '사이비' '비슷한 것'이다. 즉, 프로그래밍 언어로 코딩한 것 처럼 보이는데, 코드는 아닌 것을 말한다. 얼핏보면 프로그래밍해 놓은 것처럼 보이는데, 자세히 보면 문법에 맞지 않는 엉성한 코딩이다. 비록 프로그램은 아니지만 의도한 바를 깔끔하게 표현할 수 있는 장점이 있다. 마지막 방법은 순서도이다. 그림으로 그리는 것이다. 화살표와 네모 등을 이용한다. 네모는 각 단계, 화살표는 단계 간의 이동을 나타낸다. 그림이니까 접근하기 쉽다는 장점이 있다.


7. 어느 알고리즘이 좋은가? 시간 복잡도와 공간 복잡도 - 설렁탕집 비유


우선 시간복잡도와 공간복잡도라는 생소한 용어부터 설명해보도록 하겠습니다. 


시간복잡도를 비유를 통해 설명하면 이렇습니다. 설렁탕 집이 하나 있다고 합시다. 거기가서 설렁탕 한 그릇을 주문문했을 때, 설렁탕이 나올 때까지 걸리는 시간은 손님이 몇 명있느냐에 따라 다를 겁니다. 상식적으로 생각했을 때 손님 수에 비례적으로 시간이 길어지는게 당연합니다. 이렇게 손님 수에 따라 음식나오는 시간이 어느 정도 길어지는지를 이 설렁탕집의 시간복잡도라고 합니다. 


설렁탕집 마다 시간복잡도는 다를 수 있습니다. 여기 두 개의 설렁탕집이 있다고 합시다. 하나는 "똑똑 설렁탕집"이고, 다른 하나는 "정성 설렁탕집"이라고 합시다. "똑똑 설렁탕집"은 큰 가마에 설렁탕 국물을 많이 끓여 놓았다가 그릇에 담아 내는 방식으로 하고, "정성 설렁탕집"은 주문을 받으면, 그 때부터 사골넣어서 끓여 낸다고 합시다. 자 이제 두 설렁탕집에 점심시간이 되어 손님들이 들이 닥치기 시작했다고 합시다. 어느 설렁탕집에 가는 것이 기다리는 시간이 짧을까요? 당연히 똑똑 설렁탕집이겠지요. 유식한 말로 하자면, 똑똑설렁탕집은 시간복잡도가 낮고, 정성설렁탕집은 시간복잡도가 높다고 합니다.


알고리즘의 시간복잡도는 입력되는 데이터 크기 (개수)에 따라 낮다, 높다 라고 말합니다. 데이터 개수가 많아질 수도록 수행되는 데 시간이 많이 길어지면 시간복잡도는 높은 것입니다. 반대로 개수에 상관없이 시간이 일정하거나, 조금만 늘어나면 시간복잡도는 낮은 것입니다. 시간복잡도는 낮을수록 좋은 겁니다.  


공간복잡도도 비유를 통해서 설명해 보면 이렇습니다. 또 설렁탕 집을 예로 듭시다. 똑똑 설렁탕 집은 테이블에 모르는 사람들도 같이 앉아서 먹도록 했고, 정성 설렁탕 집은 한 사람이 테이블을 차지하고 여유 자리가 있어도, 그 테이블에는 다른 사람을 앉히지 않는다고 합시다. 점심시간에 두 설렁탕집에 모두 똑같이 100명의 손님이 들이닥쳤다고 합니다. 이 손님들을 모두 한 번에 앉히기 위해서, 어느 설렁탕 집에 더 많은 테이블이 필요할까요? 당연히 정성 설렁탕집입니다. 즉, 정성설렁탕집은 손님이 많이 오면 올수록 필요한 테이블 수가 똑똑 설렁탕집보다 많을 겁니다. 이를 유식한 말로, 똑똑설렁탕집은 공간복잡도가 낮고, 정성설렁탕집은 공간복잡도가 높다고 합니다. 


알고리즘의 공간복잡도는 입력되는 데이터의 크기 (개수)가 늘어날 때 필요한 저장공간이 늘어나는 정도를 말합니다. 공간복잡도가 낮은 알고리즘은 높은 알고리즘보다 필요공간이 더 느리게 늘어납니다. 공간복잡도도 시간복잡도처럼 낮을수록 좋은 겁니다.


물론, 설렁탕집 손님입장에서는 똑똑설렁탕집 보다는 정성설렁탕집을 선호하는 사람들이 있을수도 있겠지만요.


참, 시간복잡도는 영어로 time complexity, 공간복잡도는 space complexity라고 합니다. 시간과 공간에 해당하는 단어는 쉬운데, 복잡도가 조금 그렇지요. 복잡도는 complexity라는 단어를 씁니다.


8. 네이버지식인과 시간복잡도/공간복잡도: 회사 기술면접 기출문제


시간/공간 복잡도 개념이 머리속에 잘 자리잡도록 아래 문제를 생각해 봅시다. 실제로 모회사의 기술면접에서 나온 문제입니다. 뭔가 긴장이 되죠.. 


네이버지식인 서비스를 잘 알겁니다. 자 문제 나갑니다. "네이버지식인 서비스를 제공하는 회사 입장과 이를 사용하는 유저 입장에서 시간복잡도와 공간복잡도를 논하시오." 정답은 없습니다. 이 문제의 의도는 시간복잡도와 공간복잡도 개념을 제대로 이해하고 있는지를 평가하기 위한 것입니다.


정답은 아니겠지만, 하나의 답을 만들어보자면 이렇습니다. 유저입장에서는 시간복잡도가 훨씬 중요합니다. 공간복잡도는 신경쓸 필요도 없지요. 예를 들어, 시간복잡도가 높으면, 동시접속 유저 수가 많아짐에 따라 검색결과를 얻을 때까지 기다려야 하는 시간이 길어진다는 것입니다. 유저들은 동시접속이 아무리 많더라도 상관없이 빠른 시간에 결과를 보기를 원하는 것이 당연합니다. 따라서, 유저입장에서는 시간복잡도가 낮은 것이 중요합니다. 공간복잡도가 높으면, 동시접속 수가 많을 수록 저장공간 (메모리, 디스크)이 더 많이 필요하다는 것인데, 그건 회사가 돈을 들여 해결할 문제이고, 유저의 문제는 아닙니다.  회사입장에서는 어떨까요? 회사도 시간복잡도가 공간복잡도보다 중요할 겁니다. 동시접속이 많아졌다고 검색시간이 길어지면 유저들은 더 이상 이 서비스를 사용하지 않게 되기 때문입니다. 그렇다고 공간복잡도를 무시할 수는 없습니다. 메모리, 디스크를 더 많이 사용하면 그게 다 돈이 드는 것이기 때문입니다. 그렇지만, 하드웨어 가격이 빠르게 하락한다는 점을 고려하면, 회사는 공간복잡도를 개선하기 보다는 시간복잡도를 개선하여, 더 많은 유저들을 서비스에 끌어모으는 것이 좋을 겁니다. 포털같은 서비스에서는 "사람이 돈"이기 때문입니다.


9. 구글에 입사하고 싶은가? 그러면 시간/공간 복잡도를 손에서 놓지 말게.

 

해외회사는 물론 요즘은 국내회사들도 개발자를 채용할 때, 프로그래밍 면접을 봅니다. 그 면접에서 프로그램을 완성해서 문제를 푸는 것도 중요하지만, 진짜 핵심은 완성된 프로그램의 시간/공간 복잡도를 평가, 분석할 수 있고, 그것을 개선할 수 있는 여지를 찾아내어 프로그램을 수정하는 능력까지 보여줘야 하는 것입니다. 그러니, 앞으로는 프로그램을 짰다 하고, 거기서 끝낼 것이 아니라 복잡도가 어떤지 생각해보고, 더 좋은 방법은 없는지 생각해 봐야 할 것입니다. 



반응형
LIST

+ Recent posts