2017년 9월 25일 월요일

Hanoi Tower with discription

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include<iostream>
using namespace std;
#define TOWERSIZE 5
class blocks { //하노이탑의 각 블록의 클래스화 입니다.
private:
    int blockSize; //해당 블록이 몇칸짜리인지 이 변수를 통해 알아냅니다.
public:
    void setBlockSize(int num) 
    {
        blockSize = num;
    }
    int getBlockSize() 
    {
        return blockSize;
    }
};
class lists { //from,tmp,to 탑을 클래스화 시켰습니다.
private:
    int top = -1; //stack을 위해 top변수를 만들었습니다.
    blocks blockslist[TOWERSIZE];//각 탑의 층수 입니다.
public:
    int getTop() 
    {
        return top;
    }
    void pushBlock(blocks in) 
    {
        blockslist[++top] = in;
    }
    blocks popBlock() 
    {
        return blockslist[top--];
    }
    int peekBlock() 
    {
        return (blockslist[top]).getBlockSize();
    }
    int peekSelectBlock(int selectedSize) //특정 위치를 peek하기위한 함수
    {
        return (blockslist[selectedSize]).getBlockSize();
    }
};
void printTower(lists *forPrint) {//탑 출력 함수, 세 탑을 인자값으로 받음
    int i = TOWERSIZE-1; //타워의 꼭대기부터 시작합니다. 
    while (i > -1) //1층까지 반복
    {
        cout << " ";
        if (forPrint[0].getTop() >= i) //탑의 꼭대기가, 현제층보다 같거나 클때 
        {
            int j = 0;
            for (; j < forPrint[0].peekSelectBlock(i); j++) //블럭의 사이즈만큼 *을 찍습니다.
                cout << "*";
            if (j != 5) //5칸을 다 못찍었다면
            {
                while (j != 5)  //남은칸은 whitespace
                {
                    cout << " ";
                    j++;
                }
            }
        }
        else //현제층이, 탑의 꼭대기보다 높으면
        {
            cout << "     ";//해당 층에는 아무 블럭도 없습니다.
        }
        cout << " ";
        if (forPrint[1].getTop() >= i)  // 두번째 탑
        {
            int j = 0;
            for (; j < forPrint[1].peekSelectBlock(i); j++) 
                cout << "*";
            if (j != 5) 
            {
                while (j != 5) 
                {
                    cout << " ";
                    j++;
                }
            }
        }
        else 
        {
            cout << "     ";
        }
        cout << " ";
        if (forPrint[2].getTop() >= i) //세번째 탑
        {
            int j = 0;
            for (; j < forPrint[2].peekSelectBlock(i); j++)
                cout << "*";
            if (j != 5) 
            {
                while (j != 5) 
                {
                    cout << " ";
                    j++;
                }
            }
        }
        else 
        {    
            cout << "     ";    
        }
        cout << endl;
        i -= 1; //다음층의 계산을 시작합니다.
    }
    cout << " ----- ----- -----" << endl; // 바닥.
}
void calcHanoi(int num, lists *from, lists *tmp, lists *to, lists *forprint)
{//하노이 계산 함수
    if (num == 1)
    {
        to->pushBlock(from->popBlock());
        printTower(forprint);
        return;//기존과는 달리, 블럭 클래스들을 stack을 이용해 list클래스에 붙혀줍니다.
    }        //118번줄은 이 작업을 담당합니다. 이동후 타워를 출력합니다.
    calcHanoi(num - 1, from, to, tmp, forprint);
    calcHanoi(1, from, tmp, to, forprint);
    calcHanoi(num - 1, tmp, from, to, forprint);
}
void main() {
    int num = TOWERSIZE;
    blocks block[TOWERSIZE]; //블럭 클래스를 생성합니다.
    lists list[3];            //타워 클래스를 생성합니다.
    for (int i = 0; i < num; i++) {
        block[i].setBlockSize(num - i);//블럭을 순서대로 초기화 합니다.
        list[0].pushBlock(block[i]);//from 탑에 순서대로 생성한 블럭을 쌓습니다.
    }
    //여기까지 초기화 작업
    calcHanoi(num, &list[0], &list[1], &list[2], &*list);
    
   cout<<"DONE"<<endl;
}
/*
    Sep,18 2017 19:21
    Creater        : Changwon J.
    Title        : HanoiTower 
    Version        : Ver 1.0
    Discription    : print HanoiTower as ordered, comment added
*/

간만에 코드짜니깐 겁나 더러운것.
혹시 과제 빼낄친구들이 있을수도 있으니,
9월 25일 이후에 공개할것.

2017년 9월 24일 일요일

MsSQL2012 설치

교수가 설치법을 몰라서 당황..

당연하게도 MS사의 sql은 비쌈. 넘나비싼것.

그래서 평가판이 있다능.

https://www.microsoft.com/ko-kr/download/details.aspx?id=29062


...

걍 받고설치하면 되는데? 왜 그렇게 당황했는지 아무도 몰라..

2017년 9월 19일 화요일

c+ 다수의 소스나 헤더 적용법과 에러

오늘 배운 수업중 하낙가, 다수의 소스와 헤더파일의 구동법이었는데, 일전에 언리얼 코드를 뜯어본 기억이 새록새록 돋아나 흥미롭게 들었습니다.

겪어 본 이후로 더욱 더 실감하지만, 하나의 프로잭트에 여러명이 붙는순, 학생들이 배우는 방식의 코드작업은 지옥을 초래하게 됩니다.

(하나의 소스파일로 두세명이 작업하는것도 무리인데, 회사의 경우는 두세명이 아닐태니깐!)

그러한 이유로 우리는 여러개의 소스 파일과 헤더들을 이용하여 쉽게 지옥을 물리칠 수 있습니다.

우선적으로 우리가 컴파일을 시작하면, 프로잭트의 모든 Source 파일들을 읽기 시작하죠.

그 중 #include 문이 있다면,include가 가리키는 라이브러리, 혹은 헤더파일을 방문하여 읽게 됩니다.

미리 define된 라이브러리 함수들은 꺽쇠인 < > 로 include를 합니다.

하지만 우리가 만드는 사용자정의 Header는, 보통 하나의 프로젝트 내에 있기 때문에, 단순히 #include "Header이름.h" 를 사용하면 됩니다.

이렇게 선언된 글을 컴파일러가 읽게되면, 만든 header로 방문하게 되어, 선언문들을 읽은뒤, 마저 Source들을 읽게 됩니다.

저와 같은 기초반을 들었던 사람들이라면 흔히 봤을 광경입니다.


기초과정이기도 하고, 중점 교과과목은 자바였기 때문에, 깊게 파고들지 않아서 하나의 예제당 하나의 프로젝트를 만드는게 아닌, 이렇게 소스파일만 새로 만들어서, 이전 예제는 컴파일 재외를 했었습니다.

저는 개인적으로 하면서, 왜 제외해야하나몹시 궁금했었고, 고급과정을 하는동안 까마득히 잊고있었습니다.

정답은 프로젝트를 컴파일하면, 내부의 모든 소스파일들을 컴파일러가 읽어버리기 때문이었습니다.

유일하게 하나이어야만 하는 main 함수, 하나의 프로젝트에 여러번 나오게 될 경우 당연히 문제가 발생했기 때문에, 우리는 귀찮게도 이전 예제 소스파일들을 하나하나 컴파일 예외  시켰습니다.

그럼 이제 여러개의 소스파일을 컴파일 하는방법이 감이 오네요! 여태까지 안하게 막고있었으니, 그 작업만 한하면 되는거였네 ㅎㅎ;

그럼 간단한 stack 을 만들어 봅니다.
목표는
1. 클래스로 두개의 스택구조를 만들것,
2. int타입을 100개 stack 가능하며,
3. 메인 소스파일과, 함수 소스파일은 별개로 만들 것 입니다.

클래스 선언은 Header에서 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Stack
{
private : 
    int arr[100];
    int top;
public  :
    Stack() {
        for (int i = 0; i < 100; i++) 
            arr[i] = 0;
        top = -1;
    }
    void push(int value);
    int pop();
};

클래스에서는 push와 pop함수를 내장하고 있습니다. 두개의 동일한 stack구조를 만들것 이기때문에, 하나의 클래스에 모조리 넣었습니다.
하지만, 함수를 선언만 가능하며, 함수의 내용은 Header에서 함수의 내용을 적지는 않습니다.


 

헤더의 사용 이유는 이러합니다.
SourceA.cpp
----------
void FuncA(){
 FuncB();
}
-----------

SourceB.cpp
-----------
void FuncB(){
}
-----------
의 케이스에서, 우리 기대와는 달리 SourceA에 FuncB() 는 인식하지 않습니다.
이를 해결하기 위해서는

SourceA.cpp
----------
void FuncB();
...

void FuncA(){
 FuncB();
}
-----------
요로코럼 Forward declaration을 해야만 합니다.

이 작업이 수많은 소스파일들도 다 해주어야만 하면, 끔찍하고 지루한 반복작업이 되기떄문에, 이를 해결하기 위해 나온것이 헤더인 것 입니다.

선언을 돕는거죠.



2017년 9월 7일 목요일

Callback Function과 Iterator

재귀함수와 이터레이터는 일찍이 알았습니다만, 재귀함수를 자주 이용하지는 않았습니다.

처음으로 재귀함수를 응용했던것이 C 자료구조 수업에서 quick sort를 만들때 였으며,
그때 정말 눈 돌아갈 정도로 복잡했었기 때문에 사용을 꺼려하고 있었습니다.

재귀함수와 이터레이터는 같은 기능을 제공합니다.특정 기능을 반복하는 행위이지요.

하지만 두 기능은 상황에 따라 작업속도의 차이가 생기게 됩니다.
간단한 예를 들어 피보나치 수열 계산일때 :

반복문을 이용했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int itrway(int var)
{
    if(var<3) return 1;
    else
    {
        int cur=1,prev=1,tmp=0;
        for(int i=2;i<var;i++)
        {
            tmp=cur;
            cur+=prev;
            prev=tmp;
        }
        return cur;
    }
}
재귀함수를 이용했습니다.
1
2
3
4
5
6
7
int functionway(int var){
    
    if(var<=2) return 1;
    else return functionway(var-2)+functionway(var-1);
    
}














같은 기능을 수행하지만, 동작시간은 상이합니다.

number input : 45

1 . function call
 result :1134903170
 exec time :19.725

2 . Iterator call
 result: 1134903170
 exec time :4.724

반복문의 경우에는, 단순하게 수열을 순서대로 더했습니다. 아마..44번 계산이 전부이죠.

반면, 재귀함수의 경우에는 하나의 함수에서 2번의 함수 호출을 합니다.인자값이 1과 2가 아닌이상 또 2번 호출을 하게되고요. 불필요하게 같은 수를호출하게 될 것 입니다.

고작 45라는 숫자이기에 커다란 차이는 없지만, 숫자가 커질수록 작업 횟수와 시간은 기하급수적으로 늘어날 것 입니다.

그렇다고 재귀함수가 항상 안좋은 것은 아닙니다.
대표적인 예로, 검색 알고리즘에서는,
이터레이터 방식의 검색인 버블소트는, 굉장히 쉽게 설계가 되지만, 제가 사용했던 퀵 소트를 비교한다면, 엄청난 수준의 시간 차이가 발생했습니다.

예제를 찍어내는건 담에 하고 ㅠ

이러한 이유로, 수월하고 가벼운 프로그램을 짜기 위해서는, 우리는 최대한 경량화 작업, 그러니깐 좋은 알고리즘을 짜는 방식을 만들기 위해 반복문과 재귀함수중 어느것이 상황에 따라 더 유리한지 찾아야 할 것 입니다.


9월 08일

오랫동안 업데이트가 되지 못했습니다.
작업의 마무리를 위해 눈만뜨면 컴퓨터위로 기어올라가는 일상을 보냈기 때문이라고 변명합니다..

마무리는 거의 끝났습니다.
그 무엇보다 모델링의 부재로 인해 결국 계획됬던 많은 기능들이 사라졌습니다.
만족스럽지 못하지만, 현실적으로 봐야죠.

아직까지 모델링 부분은 끝마치지 못했습니다.
남은 일주일간 건물 모델링에 투자가 될 것 입니다.

그나마 만족스러운 결과물을 얻길 바라며..