알고리즘에 발가락 담그기
[한빛미디어] 2005-12-02 11:42  
저자: 김대곤

* 알고리즘의 Complexity 또는 계산복잡도
* 탐욕 알고리즘(Greedy Algorithm)
* 동적 프로그래밍(Dynamic Programming) – 고급 설계 기법인가?
* Induction과 병합 정렬(Merge Sort) 알고리즘
* 거짓말 같은 Induction


다음과 같은 신탁이 주어졌다고 합시다. “1에서 n까지 출력하는 알고리즘을 개발하라”

너무 단순해 보여서 한가지 방법만 있는 듯 보입니다. 보기와는 다르게 아주 다양한 방법이 있습니다. 프로그래밍 책을 한 번이라도 본 사람들은 쉽게 다음과 같은 프로그램을 작성할 수 있을 것입니다.

public static void printUsingLoop(int N) {
    for ( int i=1 ; i <= N ; i++ ) {
        System.out.println(i);
    }
}

하지만 재귀 프로그램으로도 쉽게 구현할 수 있습니다.

public static void printUsingRecursion(int N) {
    if ( N == 1 ) {
        System.out.println(N);
    } else {
        printUsingRecursion(N-1);
        System.out.println(N);
    }
}

실행속도는 어떻게 될까요? 반복문을 사용한 경우에는 N에 비례하는 것이 분명하게 보입니다. 그러면 위의 재귀 프로그램의 속도는 어떻게 될까요? 이것도 N에 비례합니다. 재귀 프로그램의 실행속도는 재귀방정식으로 주어집니다. 즉 위의 프로그램의 수행속도는 다음과 같이 정의됩니다.



T(N)를 계속적으로 전개해 보면, N개의 1이 나옵니다. 이것들을 모두 더하면 N이므로 실행속도는 N이 됩니다. 조금 더 복잡해 보이는 프로그램을 만들어 봅시다. 다음과 재귀 프로그램도 1부터 N까지 출력합니다. 초기값은 1과 N이 되겠지요.

public static void printUsingRecursion(int i, int j) {
    if ( i == j ) {
        System.out.println(i);
    } else {
        int k = (int)((i+j)/2);
        printUsingRecursion(i,k);
        printUsingRecursion(k+1,j);
    }
}

수행속도는 어떻게 될까요? 먼저 실행속도는 재귀함수로 표현해 봅시다. 그러면 실행속도는 다음과 같이 표현됩니다.



간단히 말하기 힘들어 보입니다. T(1,5)를 전개해 봅시다.
T(1,4)=T(1,2)+T(3,4)+1={T(1,1)+T(2,2)+1}+{T(3,3)+T(4,4)+1}+1
다시 정리하면 T(1,4)=7이 됩니다. 동일하게 방법으로 T(1,8)=15가 됩니다. N에 비례한다고 말하기가 조금 주저되는 상황입니다. 결론부터 말하면 실행속도는 N에 비례합니다. 그리고 N(=j-i+1)이 2의 제곱승일 때 T(1,N)은 2N-1이 됩니다. 이것은 고등학교 수학으로 간단하게 계산이 가능합니다. 그 전에 재귀 트리(Recursion Tree)를 생각해 봅니다.



실제적인 출력은 leaf에서만 수행됩니다. 만약 leaf의 갯수가 N이고 leaf가 아닌 모든 노드들이 2개의 하위 노드를 가지고 있는 경우, 이러한 노드의 갯수는 N-1이 됩니다. 이것은 고등학교 수학으로 증명이 가능합니다. 최상위 노드는 하나이고 그 다음은 2개가 되고 그 다음은 4개 됩니다. 최상위 노드에서 Leaf 노드까지의 거리는 일정합니다. 그리고 이 거리를 h라고 합시다. Leaf가 아닌 노드의 갯수는 다음과 같이 계산됩니다. 등비수열의 합을 구하는 공식 생각나시죠.



N이 이므로 내부 노드의 갯수는 N-1이 됩니다. 전체 합은 2N-1입니다. 여기서 비례한다는 것은 알고리즘의 계산복잡도를 말하는 것입니다. 이것에 대한 간략한 설명은 “알고리즘 Complexity 또는 계산복잡도” 기사에서 찾을 수 있습니다.

알고리즘을 시작하는 사람들이 가지는 가장 일반적인 고정관념 중에 하나는 여기서 알고리즘이 끝났다고 생각하는데 있습니다. 하지만 알고리즘은 반드시 증명을 따라옵니다. 즉, 알고리즘이 목표한 결과를 가져온다는 것을 증명하지 않으면 무용지물입니다. 어떻게 그 알고리즘을 사용해서 프로그램을 할 수 있습니까 어떤 값을 나올지 모르는 상황에서. 일반적으로 알고리즘의 핵심을 알고리즘을 증명하는 과정에 있다고 할 수 있습니다. 이 과정을 연습해서 얻는 결과물은 자신의 문제에 대한 알고리즘 개발할 수 있는 것입니다. 알고리즘의 개발과 알고리즘의 증명은 동전의 양면과 같습니다.

여기서 사설은 중단하고 위에 있는 각 알고리즘을 증명해 봅시다. 먼저 첫번째 재귀 프로그램(R1이라고 합시다)을 증명해 봅시다. 만약 N=1이면, R1은 1(=N)를 출력합니다. 1에서 N(=1)까지 출력하였습니다. 만약 이 R1이 N=k일 때, 1에서 k까지 출력한다고 가정합시다. N=k+1일 때, R1(k)이 1부터 k까지 출력합니다. 그리고 나서 k+1를 출력합니다. 그러므로 1부터 k+1까지 출력합니다. 즉, 어떠한 자연수 N에 대하여 R1은 1부터 N까지 출력합니다. 이것으로 증명은 끝났습니다. 재귀 프로그램은 Induction를 이용하여 증명합니다.

그러면 처음에 있는 반복문은 어떻게 증명할까요? Loop Invariant로 이용하여 반복문을 증명합니다. Loop Invariant은 간단하게 말하면, 반복문이 시작되는 위치에서 항상 만족하는 성질입니다. 즉

각 루프의 시작점(for 과 출력문 사이), 이 때의 i의 값은 k라고 합시다. 1부터 k-1까지 출력되었다.

이것에 대하여 반복문 이전, 반복문이 수행되는 동안, 반복문이 끝난 시점에 위의 성질이 만족하는 것을 보이는 것이 반복문 증명의 방법입니다. 자 시작해 봅시다.

반복문이 시작되는 전에는 i=1입니다. 아직 아무것도 출력되지 않았습니다. 1에서 0까지는 아무것도 없으므로 Loop invariant를 만족합니다.

반복문이 i=k라고 합시다. 이 때에는 1부터 k-1까지 출력되었습니다. 그리고 k까 출력됩니다. 그리고 반복문은 i=k+1인 시작점을 통과하게 됩니다. 이 때에 1부터 k까지 출력되었습니다. 즉 1부터 (k+1)-1까지 출력되었습니다. 그러므로 모든 루프의 시작점에서 위의 성질은 만족합니다.

반복문이 끝나면, i는 N+1이 됩니다. i=N인 루프의 시작점에서 1에서 N-1까지 출력했고, 반복문을 빠져나오기 전에 N를 출력하였습니다. i=N+1일 때 1부터 N까지 출력하였습니다.

즉 반복문을 빠져 나온 시점에 우리가 예상할 수 있는 결과는 1부터 N까지 출력되었다는 것입니다. 이것으로 반복문을 사용한 알고리즘의 증명은 끝났습니다.

무슨 말 장난이냐고 생각하실 분이 계실지 모릅니다. 하지만 이 과정 없이는 스스로 알고리즘을 개발하기는 아주 힘듭니다. 이제 위의 과정을 잘 이해되었다면 쉽게 풀리는 몇가지 문제를 제시함으로써 기사를 마무리 하려고 합니다.

1. 주어진 N에 대하여 N부터 1까지 출력하는 프로그램.
2. 주어진 N(= )에 대하여 1에서 N까지의 짝수를 순서대로 출력하는 프로그램.
3. 주어진 N(= )에 대하여 1에서 N까지의 수 중에서 4로 나누었을 때 2가 남는 수를 순서대로 출력하는 프로그램.
4. 정렬된 정수의 배열 A[1…N]에서 k가 있는지 없는지 확인하는 프로그램. 예를 들어 A[1…5]가 다음과 같이 주어졌다고 하자.



k=8이면 2, k=15이면 -1를 출력해야 한다. 즉 있으면 그 위치를 출력하고 없으면 -1를 출력하는 프로그램.


path와 classpath 정확한 개념 
간단한건데 이해가 잘 안가서요...

path를 잡아주는 이유는 다른 디렉토리에서 컴파일이 가능하게끔 하려고 하는거죠?

잘못 알고 있나..

그렇다면 classpath는요...

 

어떤 파일은 classpath를 걸어줘야 하고 또 다른 문서를 그러지 않아도 되는데 정확한 개념좀 잡아주세요...

 

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

 

간단하게 생각하시면
path는 os 환경에서 필요한거구, classpath 는 자바 컴파일 할때 필요한 거라고 생각하시면 되구여

자세히 말하면
가령 우리가 윈도우 실행에서 cmd 라고 쳤을때..
command 창이 실행되는건 이것이 path에 잡혀있기 때문입니다.
사실 명령어를 실행하려면.. C:\어쩌구저쩌구\cmd.XXX 를 실행시켜야 겠죠..
이것때문에 우리는 os 환경에서 경로를 다 적을 필요없이..
간단한 명령어만 실행시켜도 실행이 되는겁니다.

하지만 classpath는 자바에서 컴파일 하기위해 classes 가 모여 있는곳을 가르키는 겁니다.
우리가 가령 com.okjsp.util 을 import 한다면..
컴파일 하는곳에선 이 경로를 알아야 합니다.
만약 이것이 c\어쩌구저쩌구\classes\com\okjsp\util 에 있다면..

이경로를 자바 컴파일 하는곳에서는 일일이 경로 지정을 해주어야 합니다.

하지만. 이런식으로
classpath = c\어쩌구저쩌구\
잡아주면 컴파일 경로를 javac에서 자기가 알수 있는겁니다.

 

돌쇠
2005-07-28 17:29:28
 


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


1. 처음 jsk 설치시 잡아주는 환경변수 중 CLASSPATH 가 하는 역활이 뭔지요?
2. 설치시 잡아주는 환경변수 CLASSPATH 와 컴파일시 javac -classpath 와 차이점은 무엇인지요?
3. jdk 1.4 부터는 설치시 환경변수 CLASSPATH를 안잡아줘도 상관없다는데 사실인지요?
4. 만일 aaa.java 를 컴파일시 javac -classpath 를 잡아줬을경우 그 패스가 컴파일되면서 aaa.class 안 어딘가에 기억이 되는건지요?
아니면 컴퓨터를 리붓하면 사라지는 휘발성 패스인지요?
아니면 다른 java 파일을 컴파일 할때까지 기억되는 패스인가요?

뽀너스~ 질문하나만 더 드립니다. ^^*
* 클래스와 자바빈즈와 어떤차이가 있나요?
패키지 > 클래스 > 자바빈즈? 이런 의미인가요? ^^;;;


1. classpath의 역할은 class의 path입니다. class파일을 찾는 경로를 지정해주는 것이죠. 마치 path환경변수처럼.
2. javac -classpath c:/tomcat/common/lib/servlet.jar HelloServlet.java

set CLASSPATH=c:/tomcat/common/lib/servlet.jar
javac HelloServlet.java
는 같습니다.
3. 누가 그러던가요? class의 path를 지정해주지 않았는데, 어떻게 찾을 수 있을까요?
4. 클래스패스는 set 또는 env 명령어로 확인할 수 있습니다. 시스템 환경변수에 설정해 놓으면 영구적이고, command 나 cmd 창에서 지정한 경우 해당 창 내에서만 효력이 있습니다.

자바빈즈는 클래스의 형태를 갖고 있습니다.

  • kenu
  • 2003-03-19 02:42:07

     

     

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

     

    • .java 는 소스 파일(혹은 원시 파일)
      .class 는 클래스 파일이라고 부릅니다.
      혹시 JRE(즉, J2SE JRE)를 설치하신 것은 아닌지...
      JDK(즉, J2SE JDK)를 설치하셨다면
      bin 디렉토리 및에 javac.exe 와 java.exe 가 있을 것입니다.
      javac.exe 는 .java ===> .class (즉, 컴파일) 과정에 쓰이는 도구이고,
      java.exe 는 컴파일된 클래스 파일(.class 파일)중에 특히
      public static void main(String[] args) 라는 메소드가
      있는 클래스 파일(즉, 자바에서 애플리케이션이라고 부르는 것)을
      실행시키는데 쓰이는 도구입니다.

      컴파일할 때는 JAVA_HOME, CLASSPATH, PATH 같은 환경변수들이 미리 설정되어 있어야 합니다.
    • javaclue
    • 2004-08-09 17:06:20
    • x
    • 리플 감사드립니다.
      JDK 설치한건 맞는데, CLASSPATH설정은 안했답니다.
      어떻게 설정해야 하는 건지 모르겠거든요.
      그래서 모든 것을 uninstalling 하고
      한단계씩 낮은 버젼의 JDK와 TOMCAT를 깔았는데
      이젠 Tomcat 자체도 실행이 안되네요.
      ㅠ.ㅠ 환경 설정도 새로 깔린 것으로 바꿔줬는데
      이게 웬 날벼락인지...혹시 os를 새로 깔아야 할까요?
    • 버들
    • 2004-08-09 17:26:56
    • x
    • 환경 변수 때문에 os새로 까는건 방이 맘에 안들어서 집을 새로 짓는 결과아닐까요..??..ㅎㅎ;;;;...
      환경설정에서..시스템 변수에서 새로만들기 클릭하시고
      변수이름 : JAVA_HOME
      변수 값 : ....\jdk

      변수이름 : CATALINA_HOME
      변수 값 : ....\tomcat

      그리고 path변수의 값으로 다음을 추가 합니다.
      (기존설정된변수값들);%JAVA_HOME%\bin;%CATALINA_HOME%\bin
    • nevermind
    • 2004-08-10 03:45:53
    • x
    • 아..글쿤요. 리플 감사 드려요.
      javaclue님,nevermind님
      무지 무지 행복하세요~~꼭이요~~
    • 버들
    • 2004-08-10 10:43:46
    • x
    • 어..저기..근데..."%"표시는 무슨 뜻인가요?
      그리고..-.-;;..CLASSPATH는 어떻게 설정해야 하나요..
      강좌를 봐도 그게 잘 안나와 있어서..
    • 버들
    • 2004-08-10 10:49:40
    • x
    • 환경설정에서 변수 값은 절대 경로 또는 %변수명%을 적어 주시면 됩니다.
      %-%는 경로에 대한 변수를 표시합니다.
      위와 같이 등록하신후 프롬프트 창에서 "c:\>cd %JAVA_HOME%"이라고 치고 엔터 치면 그 경로로 이동합니다.
    • nevermind
    • 2004-08-11 01:49:21
    • x
    • 아~~! 글쿤요~~
      감사합니다요 nevermind님. *^^*
    • 버들
    • 2004-08-11 16:25:11
    • x

     

    출처 : okjsp.pe.kr

     

     

    예)

    CLASS_PATH - %JAVA_HOME%\jre\lib\rt.jar;%JAVA_HOME%\lib\tools.jar;
    JAVA_HOME - C:\Eclipse\JDK
    Path - %JAVA_HOME%\bin;D:\oracle\product\10.2.0\client_2\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;C:\Program Files\ESTsoft\ALZip

  • + Recent posts