'프로그래밍'에 해당되는 글 105건

  1. 2011.11.03 [자료구조] 히프 정렬(heap sort)... 2
  2. 2011.11.02 [자료구조]기수 정렬(radix sort)....
  3. 2011.11.02 [자료구조] 병합 정렬(merge sort)....
  4. 2011.10.31 [자료구조] 셸 정렬(shell sort)...
  5. 2011.10.30 [자료구조] 삽입 정렬(insert sort)...
  6. 2011.10.28 [자료구조] 퀵 정렬(quick sort )... 3
  7. 2011.10.19 [자료구조] 버블 정렬 ( bubble sort )...
  8. 2011.10.19 [MFC] XP 스타일 컨트롤.. 2
  9. 2011.10.18 [MFC] CBrowseFolderDialog, 폴더 다이얼로그 사용하기....
  10. 2011.10.18 [MFC] CFileDialog, 파일 다이얼로그 사용법... 1
  11. 2011.10.17 [자료구조] 선택 정렬 ( Selection Sort )...
  12. 2011.10.17 [자료구조] 정렬
  13. 2011.10.17 [자료구조] 이진 트리의 순회
  14. 2011.10.15 [MFC] Picture control 사용하기... 5
  15. 2011.10.15 [MFC] 트리 컨트롤(Tree control ) 만들기... 2
  16. 2011.10.12 [C, C++] 문자열 관련 함수 ( strlen, strcpy, strcat, strcmp ) 2
  17. 2011.10.12 [자료구조] 이진 트리..
  18. 2011.10.11 [C,C++] memset, memcpy 함수 사용법! 6
  19. 2011.10.10 [자료구조] 트리란...
  20. 2011.10.05 [C,C++] 더블버퍼링..
  21. 2011.10.04 [자료구조] 큐의 응용..
  22. 2011.10.04 [자료구조] 연결 자료구조를 이용한 큐의 구현..
  23. 2011.10.04 [자료구조] 순차 자료구조를 이용한 큐의 구현.
  24. 2011.09.29 [자료구조] 큐(Queue)란...
  25. 2011.09.27 [자료구조] 스택의 응용
  26. 2011.09.27 [MFC] 콤보박스의 아이템(항목)이 보이지 않을 때! 2
  27. 2011.09.23 [MFC] 메인프레임을 얻어와서 View에 접근하기.
  28. 2011.09.21 [자료구조] 스택 ( stack ) 의 구현. 연결 자료구조.
  29. 2011.09.21 [자료구조] 스택 ( stack ) 의 구현. 순차 자료구조.
  30. 2011.09.21 [MFC] mfc로 툴만들기( 탭 컨트롤 ) - 2 2
히프 정렬은 히프 자료구조를 이용하여 정렬하는 방법이다. 히프에서는 항상 가장 큰 원소가 루트 노드가 되고, 삭제 연산을 수행하면 항상 루트 노드의 원소를 삭제하여 반환하는 성질이 있다. 그러므로 최대 히프에 대해서 원소의 개수만큼 삭제 연산을 수행하면 내림차순으로 정렬된 원소를 얻을 수 있다. 
 
 히프 정렬은 정렬할 원소들을 입력하여 최대 히프를 구성한다. 그리고 히프에 대해서 삭제 연산을 수행하여 얻은 원소를 마지막 자리에 배치하고 히프를 다시 최대 히프가 되도록 재구성하는 작업을 원소의 개수만큼 반복하면 오름차순의 정렬을 완성할 수 있다.

 히프에 삭제 연산을 반복 수행하여 오름차순의 정렬된 원소를 구하기는 쉽지만, 삭제 연산을 수행한 후에 히프를 재구성하는 연산 수행 시간이 필요하다. n개의 노드에 대해서 완전 이진 트리는 log₂(n+1)의 레벨을 가지므로 완전 이진 트리를 히프로 구성하는 평균 시간은 O(log₂n) 이 된다. 따라서 n개의 노드에 대해서 히프의 평균 재구성 시간은 O(nlog₂n)가 된다.  

아래의 동영상을 참고하면 이해가 편하다.


Posted by 바람처럼..
|
기수정렬 기수정렬 기수정렬 기수정렬 기수정렬 기수정렬 기수정렬

기수 정렬은 분배 방식의 정렬 방법으로 정렬할 원소의 키값에 해당하는 버킷에 원소를 분배하였다가 버킷의 순서대로 원소를 꺼내는 방법을 반복한다. 기수 정렬은 원소의 키를 표현하는 값의 기수만큼의 버킷이 필요하고, 키값의 자릿수만큼 기수 정렬을 반복한다. 10진수로 표현된 키값을 가진 원소들을 정렬할 때는 0부터 9까지 10개의 버킷을 사용한다. 

 먼저 키값의 일의 자리에 대해서 기수 정렬을 수행하고, 다음 단계에서는 키값의 십의 자리에 대해 그리고 그 다음 단계에서는 백의 자리에 대해서 기수 정렬을 수행한다. 한 단계가 끝날 때마다 버킷에 분배된 원소들을 버킷의 순서대로 꺼내서 다음 단계의 기수 정렬을 수행해야 하므로 큐를 사용하여 버킷을 만든다.

기수 정렬의 수행 시간은 정렬할 원소의 수 n과 키값의 자릿수 d와 버킷의 수를 결정하는 기수 r에 따라 달라진다. 정렬할 원소 n개를 r개의 버킷에 분배하는 작업이 n+r이고, 이 작업을 자릿수 d만큼 반복해야 하므로 수행할 작업은 d(n+r)이 된다. 따라서 시간복잡도는 O(d(n+r))이 된다.

기수정렬 기수정렬 기수정렬 기수정렬 기수정렬 기수정렬 기수정렬

Posted by 바람처럼..
|

[자료구조] 병합정렬(merge sort)[자료구조] 병합정렬(merge sort)
병합 정렬은 여러 개의 정렬된 자료의 집합을 결합하여 한 개의 정렬된 집합으로 만드는 방법이다. 병합 정렬은 전체 원소들에 대해서 수행하지 않고 부분집합으로 분할하고 각 부분집합에 대해서 정렬 작업을 완성한 후에 정렬된 부분집합을 다시 결합하는 분할 정복 기법을 사용한다. 
 
 2개의 정렬된 자료의 집합을 결합하여 하나의 집합으로 만드는 병합 방법을 2-way 병합이라 하고, n개의 정렬된 자료의 집합을 결합하여 하나의 집합으로 만드는 병합 방법을 n-way 병합이라고 한다. 2-way 병합 정렬은 다음과 같은 작업을 반복 수행하면서 완성한다.

(1) 분할 : 입력 자료를 같은 크기의 부분집합 2개로 분할한다.

(2) 정복 ; 부분집합의 원소들을 정렬한다. 부분집합의 크기가 충분히 작지 않으면 순환 호출을 이용하여 다시 분할 정복 기법을 적용한다.

(3) 결합 : 정렬된 부분집합들을 하나의 집합으로 통합한다.

병합 정렬은 각 단계에서 새로 병합하여 만든 부분집합을 저장할 공간이 추가로 필요하기 때문에 정렬할 원소 n개에 대해서 2xn개의 메모리 공간을 사용한다. n개의 원소를 분할하기 위해서 log₂n번의 단계를 수행하고, 부분집합의 원소를 비교하면서 병합하는 단계에서 최대 n번의 비교 연산을 수행하므로 전체 병합 정렬의 시간 복잡도는 O(nlog₂n )이 된다.

아래의 동영상을 보면 이해하기 쉬울 것이다.


[자료구조] 병합정렬(merge sort)[자료구조] 병합정렬(merge sort)

Posted by 바람처럼..
|
[자료구조] 셸 정렬(shell sort)...[자료구조] 셸 정렬(shell sort)...

셸 정렬은 일정한 간격으로 떨어져 있는 자료들끼리 부분집합을 구성하고 각 부분집합에 있는 원소들에 대해서 삽입 정렬을 수행하는 작업을 반복하면서 전체 원소들을 정렬하는 방법이다. 전체 원소에 대해서 삽입 정렬을 수행하는 것보다 부분 집합으로 나누어 정렬하게 되면 비교 연산과 교환 연산의 횟수를 줄일 수 있다.

셸 정렬에서 부분집합을 만드는 기준이 되는 간격을 매개변수 h에 저장하고 한 단계가 수행될 때마다 h의 값을 감소시키고 셸 정렬을 순환 호출하는데, 결국 h가 1이 될 때 까지 반복한다. 셸 정렬의 성능은 매개변수 h의 값에 따라 달라진다. 일반적으로 사용하는 h의 값은 원소 개수의 ½을 사용하고 한 단계 수행될 때마다 h의 값을 반으로 감소시키면서 반복 수행된다.

셸 정렬은 n개의 자료에 대한 메모리 공간과 매개변수를 저장할 공간을 사용한다. 비교횟수는 처음 원소의 상태에 상관없이 매개변수 h에 의해 영향을 받기 때문에 알고리즘의 성능을 분석하기가 쉽지 않은데, 일반적으로 셸 정렬의 시간복잡도를 O(n¹¼)로 측정한다.

아래의 동영상을 참고하면 이해가 훨씬 쉬울 것이다.



[자료구조] 셸정렬(shell sort)...[자료구조] 셸정렬(shell sort)...
Posted by 바람처럼..
|


삽입 정렬은 정렬되어 있는 부분집합에 정렬할 새로운 원소의 위치를 찾아 삽입하는 방법이다. 삽입 정렬에서는 정렬할 자료가 두 개의 부분집합 S와 U로 나뉘어 있다고 생각하면 이해가 쉽다. 
 앞부분 원소부터 정렬을 수행하는데, 정렬된 앞부분의 원소들은 부분집합 S가되고, 아직 정렬되지 않은 나머지 원소들은 부분집합 U가 된다. 정렬되지 않은 부분집합 U의 원소를 하나씩 꺼내서 이미 정렬되어 있는 부분집합 S의 마지막 원소부터 비교하면서 위치를 찾아 삽입하여 부분집합 S의 원소는 하나씩 늘리고 부분집합 U의 원소는 하나씩 줄인다.
 U의 원소를 모두 삽입하여 공집합이 되면 삽입 정렬이 완성된다.

n개의 자료를 정렬하는 삽입 정렬에서 사용하는 메모리 공간은 n개가 된다. 삽입 정렬에서 원소들을 비교하는 횟수가 최소인 경우는 이미 원소들이 정렬되어 있는 경우다. 이미 정렬되어 있는 경우에는 바로 앞자리 원소와 비교하는 연산이 한번만 필요하다.
 따라서 최소의 비교 횟수는 n-1이 되어 시간 복잡도가 O(n)이 된다. 그리고 모든 원소가 역순으로 되어 있는 경우에는 비교 횟수가 최대가 되어 시간 복잡도가 O(n²)가 된다.

 따라서 삽입 정렬의 평균 시간 복잡도는 O(n²)이 된다.

다음은 간단한 삽입정렬 알고리즘이다..

void insertSort(int a[], int n)
{
 int j, temp ;
 for(int i = 0 ; i < n ; ++i )
 {
  temp = a[i] ;
  j = i ;
  while ((j>0) && (a[j-1]>temp))
  {
   a[j] = a[j-1] ;
   j = j-1 ;
  }
  a[j] = temp ;
 }
}

그리고 다음은 삽입정렬에 대해서 쉽게 이해할 수 있는 동영상이다.


Posted by 바람처럼..
|


퀵 정렬(quick sort )은 정렬할 전체 원소에 대해서 정렬을 수행하지 않고 기준값을 중심으로 왼쪽 부분집합과 오른쪽 부분집합으로 분할한다. 왼쪽 부분 집합에는 기준값보다 작은 원소들을 이동시키고, 오른쪽 부분집합에는 기준값보다 큰 원소들을 이동시킨다.
 이 때 사용하는 기준값을 피봇(pivot)이라고 하는데, 일반적으로 전체 원소 중에서 가운데에 위치한 원소를 피봇으로 선택한다.
 퀵 정렬은 다음의 두 가지 기본 작업을 반복 수행하여 완성한다.

(1)분할(divide): 정렬할 자료들을 기준값을 중심으로 2개의 부분집합으로 분할 한다.

(2)정복(conquer) : 부분집합의 원소들 중에서 기준값보다 작은 원소들은 왼쪽 부분집합으로, 기준값보다 큰 원소들은 오른쪽 부분집합으로 정렬한다. 부분집합의 크기가 1 이하로 충분히 작지 않으면 순환 호출을 이용하여 다시 분할한다.

분할 작업을 순환적으로 반복하면서 피봇의 왼쪽 부분집합과 오른쪽 부분집합을 정렬하는 방법으로 전체 원소들을 정렬한다. 부분집합으로 분할하기 위해서는 L과 R을 사용한다. 왼쪽 끝에서 오른쪽으로 움직이면서 크기를 비교하여 피봇보다 크거나 같은 원소를 찾아 L로 표시하고, 오른쪽 끝에서 왼쪽으로 움직이면서 피봇보다 작은 원소를 찾아 R로 표시한 후에 두 원소를 서로 교환한다. L과 R이 만나면 피봇과 R의 원소를 서로 교환하여 피봇의 위치를 확정한다.
 피봇의 확정된 위치를 기준으로 만들어진 왼쪽 부분집합과 오른쪽 부분집합에 대해서 퀵 정렬을 순환적으로 반복 수행하는데, 부분집합의 크기가 1 이하가 되면 퀵정렬을 종료한다.

간단한 퀵정렬 소스 이다.

int partition(int a[], int begin, int end)
{
 int pivot, temp, L, R ;
 L = begin ;
 R = end ;
 pivot = (begin+end)/2 ;

 while(L<R)
 {
  while((a[L]<a[pivot]) && (L<R)) L++ ;
  while((a[R]>=a[pivot]) && (L<R)) R-- ;
  if(L<R)
  {
   temp = a[L] ;
   a[L] = a[R] ;
   a[R] = temp ;
  }
 }

 temp = a[pivot] ;
 a[pivot] = a[R] ;
 a[R] = temp ;

 return L ;  
}

void quickSort(int a[], int begin, int end)
{
 if(begin<end)
 {
  int p ;
  p = partition(a, begin, end) ;
  quickSort(a, begin, p-1) ;
  quickSort(a, p+1, end) ;
 }
}

그리고 아래의 동영상을 참고 하면 퀵정렬을 이해하기 좀더 쉬울것이다.

Posted by 바람처럼..
|
[자료구조] 버블 정렬 ( bubble sort )...

버블 정렬 (bubble sort )은 인접한 두개의 원소를 비교하여 자리를 교환하는

방식으로, 첫 번째 원소부터마지막 원소까지 반복하면 가장 큰 원소가 마지막

자리에 온다. 첫 번째 원소부터 인접한 원소끼리 계속 자리를 교환하면서 맨 마

지막 자리로 이동하는 모습이 물 속에서 물 위로 올라오는 물방울 모양과 같다

고 해서 버블 정렬이라고 한다.

버블 정렬을 함수로 구현하면 다음과 같다.

void bubbleSort(int a[], int n )
{
   int i, j, temp ;
   for ( i = n-1; i >=0; --i )
   {
      for ( j= 0 ; j <= i; ++j)
      {
         if ( a[j-1] >a [j] )
         {
            temp = a [j-1] ;
            a[j-1] = a [j] ;
            a[j] = temp ;
         }
     }
   }
}

버블 정렬에서 사용하는 메모리의 크기는 정렬할 원소의 개수 n이 된다. 버블

정렬에서 연산 시간이 가장 짧은 최선의 경우는 자료들이 이미 정렬되어있는

경우다. 이런 경우에는 i 번째 원소는 n - i 번 비교하게 되므로 비교 횟수는

n(n-1)/2가 된다. 그리고 이 경우에 원소의 자리 교환은 발생하지 않는다. 

버블 정렬에서 비교 횟수가 가장 많은 경우는 역순으로 정렬되어 있는 경우인

데 이 경우에도 i 번째 원소는 n-i번 비교하게 되므로 비교 횟수는 n(n-1)/2 이

되고, 자리 교환을 n-i번 하게 되므로 교환 횟수도 n(n-1)/2이 된다. 

버블 정렬에서 비교 횟수에 대한 시간 복잡도는 O(n²)이 된다.  

아래의 동영상을 보면.. 확실히 이해가 될 것이다..



Posted by 바람처럼..
|


MFC로 툴을 만들다보면.. 좀 .. 어색한 느낌이 든다...


위는 리소스 창에서의 컨트롤 모습...


자세히 보면.. 리소스창에서 만드는 컨트롤들의 모습과 실제 컴파일 됫을 때의 모습이 다르다...

(물론 아닐수도 있다. 하지만, 내가 쓰는 2008, 2010 에서는 그렇다. )

그래서 검색해보니.. xp 스타일의 버튼을 만들려면 따로 설정을 해주어야 한다고 한다..

검색해보면.. 머 리소스에 무엇을 추가하고, 어떤 xml을 붙이고... 흠.. 머 저렇게 해도 되긴 되었다..

하지만.. 컴파일 때 마다 해줘야 하지만.. 한번에 되는 아주 쉬운 방법을 찾았다...

단점은 말그대로.. 컴파일 때 마다 리셋이 되어버려서 좀 짜증은 나지만...

모든 개발을 완료한 후에.. 마지막 컴파일에 딱.. 적용시키면.. 쓸만하다...

방법은.. 흔히 인터넷에 돌아다니는 xml 파일을 검색하면.. 안에 내용이 있다..

그 내용이 머냐면.. 바로 매니페스트에 적용되는 내용인데...

<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="X86"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>

이런 부분이 있다.. 실제로 이부분이 컨트롤의 모양을 바꾸어주는 것이다..

저기 이름이나 설정만 바꾸면 다른모양도 가능하지 않을까 생각된다.

이 상태에서.. obj 파일이 있는 Release 폴더로 간다.. 그리고


매니페스트 파일을 연다..


그리고 제일 아래에.. 위의 소스를 붙인다...

그리고 컴파일을 하면..


짜쟌~ 위의 그냥 기본과는 버튼 모양도 바뀌엇다..

머.. 별차이 없을 수도 있다...

하지만.. 디자인에 신경쓰는 사람이라면 꼭 버튼 디자인을 xp 스타일로 바꾸는

게 훨씬 보기는 좋다..



Posted by 바람처럼..
|
[MFC] CBrowseFolderDialog, 폴더 다이얼로그 사용하기....

이전 포스팅을 보면 파일 다이얼로그에 대한 것이 있다.

이전 포스팅 바로가기

그런데 꼭 파일 하나만 열지 않는 상황이 올 수도 있다.. 바로.. 폴더를 여는 상

황이다..

예를들면 폴더 내에 있는 모든 파일을 읽어서 트리 컨트롤이나 콤보 박스, 리스

트 박스 등에 저장을 하려고 한다면 말이다..


위의 2 파일은 인터넷에 떠돌아 다니는 폴더 다이얼로그 클래스이다.

일단 사용법은 2 파일을 다운 받아서..

폴더에 추가를 한다.. 그리고 헤더파일을 포함시키고...

CBrowseFolderDialog dlg; //선언 
 
 if(dlg.DoModal() == IDOK){  
 
 }

이렇게 사용하면 된다.. FileDialog랑 크게 차이점이 없다...

하지만.. 이제 값은 얻었지만.. 그걸 사용하는 방법을 보자...

먼저 저 if 내부에서..

CString str ;
dlg.GetSelectStr(str) ;

이렇게 해서 현재 경로를 얻어온다..

SetCurrentDirectory(str) ;

그리고 현재 가리키고 있던 경로를 현재 선택된 경로로 바꾼다..

CFileFind ffind ; 
if(!ffind.FindFile()) 
{
   
}

그리고 FileFind 클래스를 선언하고 위와 같이 사용한다.

그 후에는.. 

int res = 1 ;

while(res)
{
   res = ffind.FindNextFile() ;
}

이렇게 while문을 돌면.. 파일을 하나씩 읽어 드려서 처리를 해주면된다...

단, 주의해야 할 것은 저렇게 find 해서 찾은 내용을 보면,  . 과  .. 이 포함되어

있다.

'.' , '..' << 이 2가지는 제거 하고, 원하는 처리를 하면 되겠다..

[MFC] CBrowseFolderDialog, 폴더 다이얼로그 사용하기....





Posted by 바람처럼..
|
[MFC] CFileDialog, 파일 다이얼로그 사용법...

mfc로 툴을 만들다보면, 분명히 파일을 읽어오고 저장하고 해야한다..

그때 사용하는 것이 바로  CFileDialog 이다...

CFileDialog는 mfc에서 이미 만들어 놓은 클래스기 때문에 그냥 바로 사용하면
된다.

흔히 우리가 보던 파일열기 창이 바로 이 것이다.. 사용법도 엄청 간단하다...

CFileDialog dlg( true, "*.*", NULL, OFN_HIDEREADONLY , "All Files(*.*)|*.*|", NULL );

이렇게 선언하면 모든 파일이 다 보인다... 하지만 하나의 포멧만 보고 싶다면...

CFileDialog dlg( true, "*.bmp", NULL, OFN_HIDEREADONLY , "bmp Files(*.bmp|*.bmp|", NULL );

이렇게 선언을 한다.

대충 봐도 알 듯이.. 첫 파라미터의 true는 열기 일 때 쓴다.. 이 것을 false로 바

꾸면 바로 save 창이 열린다. 그리고 뒤의 확장자들만 필요한 방식으로 바꾸면

된다..

그런데 이렇게 선언만 하면 창이 생기지를 않는다..

창을 만들려면 DoModal() 함수를 불러야 하는데..

if( dlg.DoModal() == IDOK )
{
}

보통 이렇게 많이 사용을 한다..

이렇게 사용을 하면 창이 생겨서 확인을 누르면 저 if문 안으로 들어오고 취소를
누르면 밖으로 나간다.. 혹은 else 문을 추가하면 취소 되었을 때 추가적인 작

업을 해줄 수 도 있다.

그리고 혹시 작업을 하다보면 폴더를 열어야 할 일이 있을 수 있다...

아래의 경로로 들어가면 확인할 수 있다.

폴더 열기에 관한 포스팅 바로가기

[MFC] CFileDialog, 파일 다이얼로그 사용법...



Posted by 바람처럼..
|
[자료구조] 선택 정렬...
선택 정렬(selection sort)은 전체 원소들 중에서 기준 위치에 맞는 원소를 선택

하여 자리를 교환하는 방식으로 정렬한다. 전체 원소 중에서 가장 작은 원소를

찾아서 선택하고 첫번째 원소와 자리를 교환한다. 그 다음 두번 째로 작은 원소

를 찾아서 두번째 원소와 자리를 교환하고, 그 다음에는 세 번째로 작은 원소를
찾아서 세 번째 원소와 자리를 교환한다. 이 과정을 반복하면서 정렬을 완성한다.
 
정확한 자료의 값 이동은 맨 아래의 동영상을 참고하면 된다.

(유투브에서 검색하면 바로 나오는 거라서 일단 퍼왓는데 문제가 된다면 삭제

하겠다.)

간단한 선택정렬 함수이다.

void selectionSort(int a[], int n )
{
   int i, j, min, temp ;
   for( i =0 ; i < n-1; ++i )
   {
      min = i ;
      for ( j= i+1; j < n; ++j )
      {
         if ( a[j] < a[min] ) min = j ;
      }
      temp = a [i] ;
      a [i] = a [min] ;
      a[min] = temp ;
   }
}

n 개의 원소에 대한 선택 정렬은 n개의 메모리를 사용한다. 선택 정렬에서의 비

교 횟수를 구해보면, 1단계에서는 첫 번째 원소를 기준으로 n개의 원소를 비교

하고, 2단계에서는 두 번째 원소를 기준으로 마지막 원소까지 n-1개의 원소를

비교하고, 3단계에서는 세 번째 원소를 기준으로 마지막 원소까지 n-2개의 원

소를 비교한다. 이러한 방법으로 i단계에서는 i번째 원소를 기준으로 n-i개의 원

소를 비교하게 되므로 전체 비교 횟수는 n(n-1)/2 와 같다. 

선택정렬에서는 어떤 경우에서나 비교 횟수가 같으므로 시간 복잡도는 O(n²)이
된다. 




  
Posted by 바람처럼..
|

[자료구조] 정렬

정렬이란 순서 없이 배열되어 있는 자료들을 작은 것부터 큰 것 순서의 오름차

순이나 큰 것부터 작은 것 순서의 내림차순으로 재배열 하는 것이다. 할일을 순

서대로 정하는 것이나 가게에서 음식을 유통기한 순서대로 냉장고에 진열하는

것, 도서관에서 도서번호 순서대로 책들을 정리하는 것, 이름 순서로 기록되어

있는 전화번호부 등 일상 생활에서 정렬을 사용하고 있다.

자료를 정렬하는데 사용하는 기준이 되는 특정 값을 키라고 한다. 특정 이름이

라던지, 수치 등을 이용할 수 있는데 중복되는 값이 여서는 안된다.

정렬 방법은 실행하는 방법과 정렬이 수행되는 장소에 따라서 분류될 수 있다.


실행 방법에 따른 분류

정렬은 실행하는 방법에 따라 비교식 정렬과 분산식 정렬로 구분할 수가 있다.

비교식 정렬은 비교하고자 하는 각 키값들을 한번에 두개씩 비교하여 교환함으

로써 정렬을 실행하는 방식이다. 그리고 분산식 정렬은 키값을 기준으로 하여

자료를 여러 개의 부분집합으로 분해하고, 각 부분집합을 정렬함으로써 전체를
정렬하는 방식이다.


정렬 장소에 따른 분류

컴퓨터에서 수행되는 정렬은 컴퓨터 메모리 내부에서 정렬하는 내부정렬과 메

모리의 외부인 보조 기억 장치에서 정렬하는 외부 정렬로 분류할 수 있다.

Posted by 바람처럼..
|

트리를 통해 자료를 계층적인 구조로 저장하고 사용하기 위해서는 트리에 있는
모든 노드를 방문하는 방법이 필요하다. 이진 트리에있는 모든 노드를 한번씩

모두 방문하여 노드가 가지고 있는 데이터를 처리하는 것을 순회 라고 한다. 리

스트나 스택, 큐와 같은 선형 자료구조는 순회하는 방법이 한 가지 였지만, 트

리는 계층구조를 가지고 있기 때문에 여러가지 순회 방법이 있을 수 있다. 현재
노드를 방문하는 순서에 따라 전위 순회, 중위 순회, 후위 순회로 나눌 수 있다.
1. 전위 순회

(1) 현재 노드 n을 방문한다. ( 그 위치의 자료를 가져오거나 확인한다. )

(2) 현재 노드 n의 왼쪽 서브 트리로 이동한다.

(3) 현재 노드 n의 오른쪽 서브 트리로 이동한다.

이렇게 만 놓고 보면 왼쪽으로 갔다가 다시 바로 오른쪽으로 갈 것 같지만, 실

제 구현된 기능은 왼쪽으로 쭉 타고 내려간다. 그리고 더이상 왼쪽으로 갈 수

없다면 오른쪽, 오른쪽이 없다면 다시 부모 노드로, 그리고 다시 오른쪽을 확인
혹시 오른쪽에 노드가 있다면 거기로 갔다가 다시 왼쪽을 확인.. 이런식의 반복

이다..

코드로 구현하자면, 재귀호출을 이용하여 구현하면 간단하다.

2. 중위 순회

(1) 현재 노드 n의 왼쪽 서브 트리로 이동한다.

(2) 현재 노드 n을 방문한다.

(3) 현재 노드 n의 오른쪽 서브 트리로 이동한다.

중위 순회는 현재 노드를 방문하는 작업을 L과 R 노드 작업 중간에 수행하는 것

이다. 이 것은 일단 왼쪽 노드를 쭉 찾아내려간다.. 그리고 최종적인 왼쪽 노드

로 가면, 값을 읽고, 부모 노드로 돌아와서 값을 읽는다. 그 후에 다시 오른쪽노

드로 가서.. 또 왼쪽 노드부터 값을 읽는다.. 이 것의 반복인 것이다.

3. 후위 순회

(1) 현재 노드 n의 왼쪽 서브 트리로 이동한다.

(2) 현재 노드 n의 오른쪽 서브 트리로 이동한다.

(3) 현재 노드 n을 방문한다.

후위 순회도 일단 위의 순회들과 마찬가지로 왼쪽으로 쭉 노드를 찾아내려간

다. 그 후에 다시 부모로 돌아왔다가 오른쪽 노드를 확인을 하고, 그 오른쪽에

값이 있다면 또 왼쪽으로 가다가 최종적으로 돌아와서 자기의 값을 확인하고

또 돌아가고를 반복한다.

이렇게 글로만 보면 헷갈릴 수 있는데, 실제로 이진 트리를 하나 그려놓고, 전

위, 중위, 후위의 순서로 데이터를 읽어보고 방법이 맞는지 다시 검토해 보면

쉽게 이해가 될 것이라 생각된다.











'프로그래밍 > 자료구조' 카테고리의 다른 글

[자료구조] 선택 정렬 ( Selection Sort )...  (0) 2011.10.17
[자료구조] 정렬  (0) 2011.10.17
[자료구조] 이진 트리..  (0) 2011.10.12
[자료구조] 트리란...  (0) 2011.10.10
[자료구조] 큐의 응용..  (0) 2011.10.04
Posted by 바람처럼..
|

mfc에 다이얼로그에 그림을 넣을 때 가장 쉬운방법은,


Picture control을 사용하는 것이다...

일단 Picture control의 간단한 사용방법을 알아보자..


일단 다이얼로그에 픽쳐 컨트롤을 만든다..


그리고 ID의 static 부분을 임의의 이름으로 바꾼다...


그리고 변수를 추가한다.

 

변수명도 임의로 넣는다..

 

그리고 이것은 dc를 얻어와서 그냥 뭐든 그리는 방법인데...

사실, 다이얼로그의 dc를 얻어오면 다이얼로그에 그릴 수는 있다..

이 것은 그냥 dc를 얻는 방법을 알아보려고 해본 방법이다...

OnPaint() 함수에서 위처럼 입력하고 컴파일하면,


이렇게 선이 그어진다.

그림을 넣으려면,


리소스에..



비트맵을 추가한다. ( 다른방식으로 그림파일을 불러와도 된다. )



이렇게 파일을 하나 추가하고,


picture control에 속성에서 Type을 Bitmap으로 바꾼다..


그러면 위와 같이 변한다.. bitmap 상태일때는 크기 조절이 안된다..


테스트용 버튼을 하나 추가하고,

 

함수를 생성한다... 그리고,


HBITMAP hbit;
 hbit = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1));

 m_ctlPic1.SetBitmap(hbit) ;

위와 같이 입력한다.. 그리고 컴파일하면,

이렇게 나오는데 Button1을 누르면...

짠.. 위와 같이 그림이 나오게 된다..

머 버튼을 안눌려고 되도록 하려면, 그냥 기본 초기화 함수에 넣어도 되고...

여러가지 응용을 하여 사용하면 된다.

Posted by 바람처럼..
|
[MFC] 트리 컨트롤(Tree control ) 만들기...

여러가지 항목을 묶어서 보려고 하니, 트리 컨트롤이 가장 적합해 보였다..

그래서 트리 컨트롤을 사용하기 위해 테스트를 해 보았다...


먼저 테스트용 다이얼로그 프로젝트를 만들었다.

그 후 트리 컨트롤을 선택하고,


다이얼 로그에다가 추가하였다..

여기까지는 정말 쉽다.


그리고 컴파일을 하면 이렇게 된다..  아직은 내용이 없기 때문에..

내용을 추가해보자..


트리컨트롤을 선택하고,


변수를 추가하자..

 


변수명만 적고 마침을 누른다...


그러면 헤더파일에 다음과 같은 변수가 추가된다..


그리고 cpp의 OnInitDialog() 함수로 간다. 그 곳의 초기화 작업부분에...


HTREEITEM  hRoot;

 hRoot = m_ctlTreeControl.InsertItem(L"root", 0/* nImage */, 1/* nSelectedImage */, TVI_ROOT, TVI_LAST ) ;

 HTREEITEM  hChild;

 hChild = m_ctlTreeControl.InsertItem(L"image", 1/* nImage */, 1/* nSelectedImage */, hRoot, TVI_LAST ) ;

소스를 추가한다.

그리고 컴파일을 다시 하면,

이렇게 root가 나와있고,


root를 더블클릭하면 image가 나온다..

하지만.. 먼가 아무런 연결선이 없으니.. 어색하다..

트리 컨트롤의 속성창을 보자...

 


Has Buttons가 False로 되어있는데 True로 바꾸자..


 Has Lines도 True로 바꾸고,


Lines At Root도 True로 바꾼다..

그리고 컴파일을 하면,

 

이렇게 + 와 선도 생기고,


클릭하면 아래의 image가 나온다...

트리 컨트롤을 이용하면서 가장 유의해야 할 점은 트리 컨트롤은 아이템하나당
독립적이라기 보다는 상위 부모에 속하기 때문에, 추가나 삭제를 할 때 꼭 주의

해서 해야한다.

트리컨트롤에 값을 클릭하였을 때 그 처리를 해주고 싶으면,

컨트롤 이벤트에서 TVN_SELCHANGED 이벤트의 함수를 정의하고,

그 내부에서..

CString strItem = m_ctlTreeCtrl1.GetItemText(pNMTreeView->itemNew.hItem);

이렇게 사용하여 얻어 올 수 있다.
Posted by 바람처럼..
|

[C, C++] 문자열 관련 함수 ( strlen, strcpy, strcat, strcmp )

지난 번에 메모리 관련 함수 들에 이어서 이번엔 문자열 관련 함수를 알아보자.

메모리 관련 포스팅 바로 가기
 
먼저 strlen 이다.. 말그대로 str , length 길이 라는 뜻이다.

return 형은 int 이다.

쓰는 방법은

char* str = "abcde" ;

int nlength = strlen(str ) ;

이렇게 쓰고 출력해보면 5라는 값이 나온다.

다음은 strcpy 이다.

이 것은 지난번 memcpy 처럼 문자열을 복사하는 함수이다.

char* src = "abcde" ;
char dst[20] = { 0, } ;
 
strcpy( dst, src ) ; 

이렇게 쓰면 abcde가 dst에 복사가 된다.

strcat은 문자를 합치는? 붙이는? 함수이다.

사용방법은

char dst[20] = "abcde" ;
char* src= "fghij"  ;

strcat(dst, src ) ;

처럼 하면 abcdefghij 가 쭉 붙은 문자열이 된다.

dst + src 라고 보면 된다.

strcmp는 비교 함수로 A 와 B 가 같은지 본다.

사용 방법은..

 char* dst = "abcde" ;
 char* src = "abcde"  ;

 int nResult = strcmp(dst, src ) ;

처럼 쓰면 된다..

strcmp(A, B ) ;

라고 봤을 때 A가 크면 1을 리턴하고 B가 더 크면 -1, 두개가 같다면 0을 리턴

한다.

0은 if 문을 만나면 false로 인식되므로,

if(!strcmp(dst, src ) )

같은 문으로 써도 되고,

switch(strcmp(dst, src))
{
        case -1:
              break ; 

        case 0:
              break ;

        case 1:
             break ;
}

이렇게 사용해도 된다.





Posted by 바람처럼..
|
[자료구조] 이진 트리..[자료구조] 이진 트리..[자료구조] 이진 트리..
이진 트리란...


트리의 노드 구조를 일정하게 정의하면 트리의 연산이 쉬워진다. 그래서 모든

노드의 차수를 2 이하로 정하여 전체 트리의 차수가 2 이하가 되도록 만든 것이
이진 트리다.

이진 트리는 구별된 2개의 왼쪽, 오른쪽 자식 노드만을 가질 수 있으며, 공백 노

드도 이진 트리의 노드로 취급한다.

이진 트리에 있는 모든 노드는 왼쪽 자식 노드를 루트로 하는 왼쪽 서브 트리와
오른쪽 자식 노드를 루트로 하는 오른쪽 서브 트리를 갖는다. 그리고 이진 트리

의 서브 트리들 역시 모두 이진 트리여야 한다.



이진 트리의 특징...



1. n개의 노드를 가진 이진 트리는 항상 (n-1)개의 간선을 가진다.

2. 높이가 n인 이진 트리가 가질 수 있는 노드의 최소 개수는 (n+1)개가 되며,

최대 개수는 (2ⁿ+¹ - 1)  개 이다.


이진 트리의 분류....


포화 이진 트리 : 포화 이진 트리는 모든 레벨에 노드가 꽉 차서 포화 상태인 이

진 트리를 의미한다. 즉 포화 이진 트리는 최대 노드수를 갖는 이진 트리다.


완전 이진 트리: 완전 이진 트리는 높이가 h 노드의 갯수가 n 이라면, 높이가 h

인 포화 이진트리의 노드 순서와 n 개 까지가 동일한 이진 트리이다. 

쉽게 얘기하면, n 개 까지의 순서는 포화 이진 트리와 똑 같지만 그 이후의 나머

지 노드는 공백 노드인 이진 트리가 완전 이진 트리이다.  


편향 이진 트리 : 이진 트리 중에서 최소 개수의 노드를 가지면서 왼쪽이나 오

른쪽 서브 트리만 가지고 있는 트리를 편향 이진 트리라고 한다.

[자료구조] 이진 트리..[자료구조] 이진 트리..[자료구조] 이진 트리..
Posted by 바람처럼..
|
[C,C++] memset, memcpy 함수 사용법!

mem- 이라는 접두사가 붙은 함수는 메모리 관련 함수라는 의미이다.

memset은 메모리를 초기화 하는 함수이고, memcpy는 메모리를 복사하는 함

수이다.

얼마전 sprintf() 로 512크기의 char배열의 값을 받아서 넣은 적이 있다..

그런데, 500크기일때 까지는 제대로 값이 들어와서 새로운 배열에 값이 잘 써졌

는데, 512가 되니... 이상하게 값이 짤리고, 날라가고 쓰레기 값이 들어왔다..

그래서 알아보니 크기가 큰 배열인 경우에 sprintf를 사용하면, 이렇게 값이 제

대로 안들어오는 경우가 종종 있다고 한다..

그래서 사용한 방법이 memcpy 이다.

그러니 정상적으로 복사가 되었다..

일단 먼저 memset 부터 알아보자..

void *  __cdecl memset(_Out_opt_bytecapcount_(_Size) void * _Dst, _In_ int _Val, _In_ size_t _Size);

이 것이 memset의 함수 원형이다.

1번 파라미터는 값을 복사할 곳이고, 2번 파라미터는 초기화할 값, 마지막은 얼

마만큼의 메모리를 초기화 할 것인지 하는 크기이다.

단, char 값이 아니라면, 0, -1로만 초기화 하는 것이 좋다.

(다른 값은 쓰레기 값이 들어가는 경우가 많다. )
---------------------------------------------------------------------
수정사항... 다른 분의 지적이 있으셔서 확인해보니.. 그 말이 맞아 수정합니다.

먼저.. 쓰레기 값이 들어가는 것이 아니라.. 1바이트 기준으로 값이 들어가기 때문에 char를 제외한 다른 1바이트가 넘는 (예를 들면 인트라면..) 변수에 값을 넣으면 그 바이트 수 만큼 모두 1 숫자로 초기화를 합니다.

int를 예로 들어보면 4바이트 모두를 1로 초기화 하기때문에 메모리가 각바이트가 모두 1로 초기화 되어있습니다. 원래 4바이트가 0000 이라면 0001 이 되어야 출력시 1로 표시되는데 1111이 되기 때문에 출력을 해보면 원하는 값이 들어 가지 않네요...

----------------------------------------------------------------------

 


위의 출력 창은 1로 memset 한 경우인데.. 다른 값이 들어가 있는 것을 확인

할 수 있다.

int test1[5] ;

memset( test1, 0, 5 * sizeof(int) ) ;

이렇게 사용하면되는데,  int 형의 크기가 5인 배열에 값을 0으로 초기화 하는

것이다.

다음은 memcpy 이다.

void *  __cdecl memcpy(_Out_opt_bytecapcount_(_Size) void * _Dst, _In_opt_bytecount_(_Size) const void * _Src, _In_ size_t _Size);

memcpy의 함수 원형이다.

첫번째 파라미터는, 역시 복사될 메모리 주소고, 다음은 복사할 메모리 주소,

마지막은, 복사할 사이즈다.

사용법은

int test1[5], test2[5] ;

memset( test1, 0, 5 * sizeof(int) ) ;
memset( test2, -1, 5 * sizeof(int) ) ;

memcpy( test1, test2, 5 * sizeof(int) ) ;

이러고 test1의 값을 차례로 출력하면 모두 -1로 변해 있는 것을 알 수 있다.


출력 결과 이다.

요즘은 잘 사용하지 않고 있다가, 이번에 sprintf 문제 때문에 다시 알아보게 되

었지만, 속도상의 이득도 많다고 한다.

긴 크기의 배열이나, 값은 이렇게 메모리 자체를 복사하여 쓰는 것이 훨씬 이득

이라고 하니, 앞으로 코딩할 때 많이 고려해 봐야할 것 같다.

[C,C++] memset, memcpy 함수 사용법!


Posted by 바람처럼..
|
[자료구조] 트리란...[자료구조] 트리란...[자료구조] 트리란...

리스트와 스택, 큐는 자료들이 선의 형태로 나열되어 있는 구조를 가진 선형 자

료구조였다. 자료들이 나열된 구조가 선형이 아닌 자료구조를 비선형 자료구조

라고 하는데, 트리(tree)는 비선형 자료구조 중에서 자료들간에 계층관계를 가

진 계층형 자료구조다. 흔히 우리가 알고있는 가계도가 바로 계층형 자료구조

이다.

가계도에서 가족 구성원을 연결하는 선은 부보 자식 관계를 나타낸다. 가계도

의 시작을 루트로 보고, 그 아래 자식노드는 1세대(레벨1)그 아래의 자식노드들

은 2세대(레벨 2) 라고 볼 수 있다.

트리를 구성하는 원소는 노드라고 하고 노드를 연결하는 선을 간선(edge)이라

고 한다. 같은 부모 노드의 자식 노드들은 서로 형제 노드가 된다. 한 노드에서

간선을 따라 루트 노드까지 이르는 경로에 있는 노드들은 모두 그 노드의 조상

노드가 된다. 자식 노드들은 각각 독립하여 새로운 트리를 구성할 수 있으므로

각 노드의 자식 노드 수만큼의 서브 트리를 갖는다. 한 노드의 자손 노드들은

그 노드의 서브 트리에 있는 노드들이 된다.

한 노드가 가지는 서브 트리의 수, 즉 자식 노드의 수를 그 노드의 차수라 한다.
한 노드의 높이는 루트에서 그 노드에 이르는 경로에 있는 간선의 수가 되고,

노드의 높이 중에서 가장 큰 값, 즉 최대 레벨이 그 트리의 높이가 된다.

나무가 모이면 숲이 되듯이 여러 트리들의 집합을 포레스트 라고 한다. n개의

서브트리를 가진 루트 노드를 제거하면 n개의 분리된 트리가 생겨서 포레스트

를 이룬다.

[자료구조] 트리란...[자료구조] 트리란...[자료구조] 트리란...
Posted by 바람처럼..
|

[C,C++] 더블버퍼링..

더블 버퍼링이라는 개념은 흔히 게임과 관련되거나, 실시간으로 화면 처리가

필요할 떄 사용된다..

쉽게 설명하면, 그림이나 도형 하나 하나를 그릴 때 보여지는 화면에 바로바로

그려버리면, 흔히 얘기하는 깜빡이는 현상이 생긴다.

그 것을 방지 하기 위해서는 더블 버퍼링을 사용하는데 말 그대로 버퍼가 2개

(더블) 이라는 의미이다.

즉, 화면에 보여지는 버퍼 하나와 화면에 보이지는 않지만 실제로 그림이 찍히

는 백버퍼 2개의 버퍼가 존재하는데 일단 백버퍼에 모든 그림을 그리고, 마지막

에 화면 버퍼에 백 버퍼를 복사하는 방식이다.

(물론, 2개의 버퍼를 클리핑 하면서 사용할 수도 있다. 개념적으로는 같은 방식

이다.)

개념자체도 어렵지 않은 만큼 소스도 어렵지 않다...

아래의 소스는 mfc에서 테스트 했지만, hdc를 사용하기 때문에, c++환경의 api

든 mfc든 모두 사용할 수 있을 것이다.

HDC backMemDC ;
 
backMemDC = CreateCompatibleDC(pDC->GetSafeHdc());

위와 같이 백버퍼를 하나 선언한다... 물론 기본적으로 프론트 버퍼도 있어야

하는데, mfc에서 지원하는 pDC에서 hdc를 받아온다.

그 후에..

RECT rect ;
GetClientRect(&rect) ;


HBITMAP MemBmp;
MemBmp = CreateCompatibleBitmap(pDC->GetSafeHdc(),rect.right,rect.bottom);

SelectObject(backMemDC,MemBmp);

화면의 크기를 얻기 위해 rect를 선언하였고,

비트맵을 하나 만들고, 2개를 연결 시킨다...

오랜만에.. 더블버퍼링에 대해서 개념만 가지고 그냥 코딩했더니.....

저 비트맵 부분을 빼먹었었다.. 아무런 오류없이 컴파일이 끝났지만,

실제 화면에는 아무것도 찍히지 않았다 ;;

그래서 검색해보니 저 비트맵을 누군가 도화지라고 표현해놓았는데..

그 것을 보고 비트맵을 추가했더니, 역시나 제대로 나온다...

즉, 더블버퍼링에 필요한 것은 백버퍼와 그 곳에 그림이 그려질 도화지 역할을

하는 비트맵이 필요했다..

이제 저 이후에,

MoveToEx(backMemDC, 100, 100, NULL ) ;
LineTo(backMemDC, 300, 300) ;

이런식으로 선을 긋든, 원, 사각형을 그리고, 마지막으로...

BitBlt(pDC->GetSafeHdc(),0,0, rect.right, rect.bottom, backMemDC, 0,0, SRCCOPY);

으로 화면을 백버퍼에 있던 내용을 프론트로 복사하면 된다...

DeleteDC(backMemDC);
DeleteObject(MemBmp);

그리고 잊지말고, 해제도 꼭 하기!

[C,C++] 더블버퍼링..[C,C++] 더블버퍼링..[C,C++] 더블버퍼링..




Posted by 바람처럼..
|
[자료구조] 큐의 응용..
컴퓨터의 여러 분야에서 발생한 순서대로 문제를 해결하는 경우에 선입선출 운

영 구조의 큐를 사용한다. 컴퓨터 운영체제에서 실행을 요청한 작업들을 순서

대로 처리하기 위해서 버퍼 큐와 프로세스 스케줄링 큐를 사용하고, 산업공학

등의 분야에서는 최적의 시스템을 설계하기 위한 시뮬레이션에서 대기 행렬 큐

를 사용한다.

1. 운영체제의 작업 큐

큐는 각기 다른 속도로 실행되는 작업의 처리 시간을 조화시키기 위해 사용할

수 있다. 프린터를 사용하여 출력하는 경우를 생각해보자. cpu에서 데이터를

내보내는 출력속도는 프린터의 출력 속도보다 훨씬 빠르다. 만약 cpu가 프린터

의 출력이 끝날때까지 기다렸다가 다음 데이터를 내보낸다면 기다리는 시간만

큼 cpu도 다른 작업을 수행 할 수 없게 되어 작업 효율이 떨어지게 된다. 그래

서 운영체제에서 프린터 버퍼 큐 를 사용하게 한다. cpu는 출력으로 내보네는

데이터를 프린터 버퍼 큐에 삽입하고 프린터가 버퍼 큐에 있는 작업을 순서대

로 처리하면서 처리가 끝난 작업은 버퍼 큐에서 삭제한다. 이처럼 처리 속도가

다른 처리기 사이에서 처리 속도를 맞추기 위해 큐를 사용하는데, 이를 버퍼 큐

라고 한다.

컴퓨터 운영체제에서는 cpu를 사용하고자 하는 프로세스들에 대해 cpu 사용

스케줄을 관리하기 위해서 스케줄링 큐를 사용한다. 스케줄링 큐는 준비 큐

와 대기 큐로 구성한다. cpu를 사용하고자 하는 프로세슫르을 준비 큐에 삽이

하면순서대로 준비큐에서 꺼내서cpu를 사용하게 한다. cpu를 사용하던 프로세

스가다른 처리를 기다리는 대기 상태가 되면 대기 큐에 삽이하여 대기 상태의

프로세스들을 순서대로 관리한다.

2. 시뮬레이션에서의 큐잉 시스템

시뮬레이션이란 실제로 일을 실행하기 전에 미리 실험해보는 것이다. 시뮬레이

션을 하려면 먼저 시스템에 대한 수학적인 모델링 작업을 해야한다. 예를 들어,

공항을 새로 만들면서 입국심사 창구를 몇개 만들어야 할지를 시뮬레이션한다

고 하면 "비행기가 몇 분마다 도착하는가?", "한 명을 심사하는데 시간이 얼마나
소요되는가?", "어느 때에 가장 입국자가 많은가?"등을 모델링해야 하는데,

이러한 모델링에 사용되는 통계적인 이론이 큐잉 이론 이다. 큐잉 이론에서는

서비스를 받기 위해 기다리는 대기 행렬과 대기 시간을 실험하는데 큐를 사용

한다. 공항에 도착하는 입국자는 큐로 만든 대기 행렬에 순서대로 들어가고,

입국 심사관은 큐에 있는 입국자들을 순서대로 처리하게 된다. 모든 서비스가

끝나서 대기 행렬 큐가 공백이 되기까지의 평균 대기 시간을 여러 상황에 대해

시뮬레이션 하여 최적의 시스템을 설계 한다.

[자료구조] 큐의 응용..[자료구조] 큐의 응용..[자료구조] 큐의 응용..
Posted by 바람처럼..
|

[자료구조] 연결 자료구조를 이용한 큐의 구현..
순차 자료구조를 이용하여 구현한 큐에는 몇 가지 단점이 있다. 사용 크기가 제

한되어 큐의 길이를 마음대로 사용할 수 없고, 원소가 없을 때에도 항상 그 크

기를 유지하고 있어야 하므로 메모리도 낭비 된다는 점이다. 이와 같은 문제를

극복하기 위해 연결 자료구조를 이용하여 크기 제한이 없는 연결 큐(Linked

Queue)를 구현해 보자.

연결 큐에서 원소는 데이터 필드와 링크 필드를 가진 노드로 구성하며, 첫 번째
노드를 가리키는 front 포인터와 마지막 노드를 가리키는 rear 포인터를 사용한

다. 연결 큐의 초기 상태(공백 큐)는 front와 rear를 NULL 포인터로 설정하여 표

현한다.

다음은 간단히 구현한 소스 이다.

#include <stdio.h>
#include <malloc.h>

typedef struct QNode{
 char data ;
 struct QNode *link ;
} QNode;

typedef struct {
 QNode *front, *rear ;
} LQueueType ;

LQueueType* createLinkedQueue()
{
 LQueueType *LQ ;
 LQ = (LQueueType*)malloc(sizeof(LQueueType)) ;
 LQ->front = NULL ;
 LQ->rear = NULL ;

 return LQ ;
}

bool isEmpty(LQueueType* LQ)
{
 if(LQ->front == NULL)
 {
  printf("\n Linked Queue is empty! \n") ;
  return true ;
 }else
  return false ;
}

void enQueue(LQueueType* LQ, char item )
{
 QNode* newNode = (QNode*)malloc(sizeof(QNode)) ;
 newNode->data = item ;
 newNode->link = NULL ;

 if(LQ->front == NULL)
 {
  LQ->front = newNode ;
  LQ->rear = newNode ;
 }else
 {
  LQ->rear->link = newNode ;
  LQ->rear = newNode ;

 }
}

char deQueue(LQueueType* LQ)
{
 QNode* old = LQ->front ;
 char item ;

 if(isEmpty(LQ)) return 0 ;
 else
 {
  item = old->data ;
  LQ->front = LQ->front->link ;

  if(LQ->front == NULL )
   LQ->rear = NULL ;

  free(old) ;

  return item ;
 }
}

void printfLQ(LQueueType* LQ)
{
 QNode* temp = LQ->front ;
 printf("\n Linked Queue : [") ;

 while(temp){
  printf("%3c", temp->data) ;
  temp = temp->link ;
 }
 printf("]") ;
}

void main()
{
 LQueueType* LQ1 = createLinkedQueue() ;
 
 enQueue(LQ1, 'a') ;
 printfLQ(LQ1) ;

 enQueue(LQ1, 'b') ;
 printfLQ(LQ1) ;

 deQueue(LQ1) ;
 printfLQ(LQ1) ;

 enQueue(LQ1, 'c') ;
 printfLQ(LQ1) ;

 deQueue(LQ1) ;
 printfLQ(LQ1) ;

 deQueue(LQ1) ;
 printfLQ(LQ1) ;
}


이전의 선형구조로 소스를 짯을 때랑 화면상으로는 큰차이는 없다..

하지만 선형구조가 크기의 한계가 있다면, 연결 구조는 크기의 구애 받지 않고,
계속 늘었다, 줄었다 할 수 있기 때문에, 훨씬 여러곳에서 활용할 수 있다.

[자료구조] 연결 자료구조를 이용한 큐의 구현..
Posted by 바람처럼..
|

[자료구조] 순차 자료구조를 이용한 큐의 구현.

1. 선형 큐

1차원 배열을 사용하는 순차 자료구조로 큐를 구현해보자. 이때 배열의 크기는

큐의 크기, 즉 큐에 저장할 수 있는 최대 원소 갯수가 된다. 그리고 배열에 저장

된 원소 중에서, 첫 번째 원소의 인덱스를 저장할 front 변수와 저장된 마지막

원소의 인덱스를 저장할 rear 변수를 사용한다. 초기 공백 큐의 상태는 front 변

수와 rear 변수의 값을 -1로 설정한다.

정리된 소스는 아래와 같다... ( 정말 간단히 구현만 했다. )

#include <stdio.h>
#include <stdlib.h>

#define Q_SIZE 100

char queue[Q_SIZE] ;

int front, rear ;

void enQueue( char item)
{
 if(rear == Q_SIZE -1 )
 {
  printf("\nQueue is full!\n" ) ;
  return ;
 }else
 {
  rear++ ;
  queue[rear] = item ;
 }
}

void deQueue()
{
 if( front == rear )
 {
  printf("\nQueue is empty!\n" ) ;
  return ;
 }else
 {
  front++ ;
 }
}

void printfQueue()
{
 printf("Queue : [") ;
 for(int i = front+1; i <= rear ; ++i )
  printf("%3c", queue[i]) ;

 printf(" ] \n") ;
}

void main()
{
 front = -1 ;
 rear = -1 ;

 enQueue('a') ;
 printfQueue() ;

 enQueue('b') ;
 printfQueue() ;

 deQueue() ;
 printfQueue() ;

 enQueue('c') ;
 printfQueue() ;

 deQueue() ;
 printfQueue() ;

 deQueue() ;
 printfQueue() ;
}

실행해 보면..

위와 같은 결과가 나온다...

하지만 위와 같은 소스는, 배열에 모든 정보가 꽉 찬 이후에는 동작을 하지 않

는다.. 바로 그 것을 해결하기 위해 나온 것이 원형 큐다..

2. 원형 큐

위의 선형 큐와 같은 경우는 rear가 배열의 마지막 위치에 있게 되면 큐에 빈자

리가 있는데도 포화 상태로 인식하고 삽입연산을 수행하지 않는다.

원형 큐는 선형 큐와 마찬가지로 1차원 배열을 사용하는데, 논리적으로 배열의

처음과 끝이 연결되어 있다고, 생각하는 것이다.

원형 큐에서는 초기 공백 상태일 때 front와 rear의 값이 0이 되고, 공백 상태와

포화 상태를 쉽게 구분하기 위해서 자리 하나를 항상 비워둔다. 원형 큐에서의

공백 상태는 front = rear 가 된다. rear가 앞으로 이동하면서 원소를 삽입하고,

front는 rear가 이동한 방향으로 따라가면서 원소를 삭제한다. 원형 큐에서는 배

열의 인덱스가 n-1 다음에 다시 0이 되어야 하므로 사용할 인덱스를 정하기 위

해서 나머지 연산자 mod를 사용한다.

원형 큐는 위의 소스를 바탕으로 직접 해보길 바란다.

[자료구조] 순차 자료구조를 이용한 큐의 구현.


Posted by 바람처럼..
|


큐는 스택과 마찬가지로 삽입과 삭제의 위치와 방법이 제한된 유한 순서 리스

트지만, 스택과 달리 리스트의 한쪽 끝에서는 삽입 작업이 이루어지고 반대쪽

끝에서는 삭제 작업이 이루어져서, 삽입된 순서대로 삭제되는 선입선출(FIFO,

First In Fiirst Out ) 의 구조로 이루어져있다.

예를 들면, 은행에 들어온 순서대로 번호표를 뽑게 하고 번호표 순서대로 일을

처리해주는 운영방식이 큐라고 볼 수 있다.

큐는 한쪽 끝을 프런트(front)로 정하여 삭제 연산만 수행하도록 하고, 다른쪽

끝을 리어(rear)로 정하여 삽입 연산만 수행하도록한다. 큐에서 프런트 원소는

가장 먼저 큐에 들어온 첫번재 원소고, 리어 원소는 큐에 가장 늦게 들어온 마

지막 원소가 된다. 가장 먼저 들어온 프런트 원소가 가장 먼저 삭제된다. 

큐의 리어에서 이루어지는 삽입 연산을 인큐(enQueue)라고 하고, 프런트에서

이루어지는 삭제 연산을 디큐(deQueue)라고 한다.  
Posted by 바람처럼..
|
[자료구조] 스택의 응용

스택은 알고 보면, 상당히 활용 할 곳이 많은 자료구조이다.

몇가지 스택을 응용하여 사용하는 것을 알아보자.

1. 역순 문자열 만들기.

스택의 LIFO 성질을 이용하여 문자열에 대한 역순 문자열을 간단히 만들 수 있

다. 문자열을 처음부터 순서대로 스택에 삽입한다. 
 
그 후 스택에 있는 원소들을 공백 스택이 될 때 까지 삭제하면서 반환된 문자를
나열하면 원래 문자열의 역순 문자열이 된다.

2. 시스템 스택

프로그램간의 호출과 복귀에 따른 수행 순서를 보면 호출한 순서와 복귀하는

순서는 반대기 때문에 가장 나중(last)에 호출된 함수가 가장 먼저(First) 실행

을 완료하고 복귀한다. 따라서 함수의 호출과 복귀 순서는 스택의 구조를 응용

하여 관리할 수 있다. 이 때 사용하는 스택을 시스템 스택이라 한다.

함수나 서브프로그램이 호출되면 일단 호출한 함수 수행에 필요한 지역변수,

매개변수 및 수행 후 복귀할 주소 등의 정보를 스택 프레임에 저장하여 시스템

스택에 삽입한다. 시스템 스택의 top은 항상 현재 실행중인 함수에 대한 스택

프레임이 된다. 함수의 실행이 끝나면 시스템 스택의 top원소를 삭제하면서 프

레임에 저장되어 있던 복귀 주소를 확인하고 복귀한다. 함수 호출과 복귀에 따

라 이 과정을 반복하여, 전체 프로그램 수행이 종료되면 시스템 스택은 공백 스

택이 된다.

3. 수식의 괄호 검사.

수식은 일반적으로 연산자와 피연산자로 구성되어 있으며, 왼쪽에서 오른쪽 순

서로 처리한다. 수식에 사용한 연산자의 우선순위가 다를경우에는 우선순위가

높은 연산자를 먼저 처리하는데, 괄호를 사용하여 우선순위를 표현하기도 한

다. 이 때 괄호는 일반괄호, 중괄호, 대괄호 를 사용한다. 괄호는 왼쪽 괄호와

오른쪽 괄호가 반드시 쌍을 이루어야 하며, 여러 개의 괄호가 중첩된 경우에는

가장 안쪽의 괄호를 먼저 처리한다.

괄호가 포함된 수식에서 괄호의 쌍이 제대로 사용되었는지를 검사하기 위해서

스택을 사용할 수 있다. 수식을 읽으면서 왼쪽 괄호를 만나면 스택에 push하고
오른쪽 괄호를 만나면 스택을 pop한다. 현재의 오른쪽 괄호와 pop한 왼쪽 괄호

가 같은 종류의 괄호면 괄호의 쌍이 맞는 것이고, 수식의 처리가 모두 끝났을

때 스택이공백 스택이 되면 왼쪽 괄호와 오른쪽 괄호의 갯수가 맞는 것이다.

4. 수식의 후위 표기법 변환.

연산자와 피연산자로 구성된 수식을 표기하는 방법은 연산자의 위치에 따라 다

음의 세가지로 나눌 수 있다.

◀ 전위 표기법
 
연산자를 앞에 표기하고 그 다음에 피 연산자를 표기하는 방법 예) +AB

◀ 중위 표기법

연산자를 피연산자의 가운데에 표기하는 방법 예) A+B

◀ 후위 표기법

연산자를 피연산자 뒤에 표기하는 방법 예) AB+

중위표기법의 수식을 후위표기법으로 변환하는 방법을 알아보자.

수식 A*B-C/D를 후위 표기법으로 변환하면,

1) 수식의 각 연산자에 대해서 우선순위에 따라 괄호를 사용하여 다시 표현한다.

((A*B)-(C/D)

2) 각 연산자를 그에 대응하는 오른쪽 괄호의 뒤로 이동시킨다.

((AB)*(CD)/)-

3) 괄호를 제거한다..

AB*CD/-

우리가 일반적으로 사용하는 표기법은 중위 표기법이지만, 컴퓨터 내부에서 수

식을 처리하기에 가장 효율적인 방법은 후위 표기법이다. 후위 표기법을 사용

하면 괄호나 연산자 우선순위를 따로 처리하지 않고 왼쪽에서 오른쪽으로 표기

된 순서대로 처리할 수 있다. 우리가 컴퓨터에 중위 표기법 형태의 수식을 입력

하면 컴퓨터 내부에서는 효율적인 처리를 위해 스택을 사용하여 입력된 수식을
후위 표기법으로 변환하게 된다.

5. 후위 표기 수식의 연산.

컴퓨터 내부에서 후위 표기법의 수식을 연산할 때도 스택을 사용할 수 있다. 스

택을 사용하여 수식을 계산하는 방법은,

1) 피연산자를 만나면 스택에 삽입한다.

(2) 연산자를 만나면 필요한 만큼의 피연산자를 스택에서 pop하여 연산하고,

연산 결과를 다시 스택에 삽입한다.

(3) 수식이 끝나면, 마지막으로 스택을 pop하여 출력한다.

Posted by 바람처럼..
|

콤보박스의 아이템이 보이지 않을 때!


툴 작업을 하다보면 콤보 박스를 사용할 때도 많다..

그래서 콤보 박스를 추가하고,

컴파일을 했다....


그래서 위의 화면처럼 나왔는데...

옆의 화살표를 클릭해보니..


음... 지금 이 화면이 클릭한 화면인데... 아래로 창이 보이질 않는다..

아무런 아이템이 추가 되지 않아서 그렇다고 생각할 수 있지만, 이 것은 항목이
추가 되어도 마찬가지다.. 다시 다이얼로그 창으로 돌아가서..


위와 같은 상태이면 그냥 화면이 움직일 뿐이다.. 좌우의 네모가 색이 칠해져

있다..


그 상태에서 오른쪽 화살표를 클릭하면, 색이 칠해진 네모가 아랫쪽 가운데로

변하게 된다.

 


그 상태에서 네모에 커서를 가져다 덴 후에 아래로 쭉 끌어내리면,


이렇게 범위가 생긴다. 그러고 다시 컴파일을 한 후 화살표를 클릭하면.


이렇게 아무 항목이 없어도 아래까지 내려오는 콤보 박스를 확인할 수 있다..

콤보박스의 아이템이 보이지 않을 때!


Posted by 바람처럼..
|

지금까지 툴 만들기를 따라왔다면, 이제 값을 넣어볼 차례인데...

mfc는 구조가 특이하게 클래스 별로 각자 역할을 분리하고 있다...

우리가 보는 왼쪽 화면은 View 클래스에서 담당하고 있는데..

화면에 무언가를 그리고 싶다면 이 View 클래스를 이용해야한다..

일단 간단한 그림을 띄워보려 했으나.. 실패하였다...

View 접근하기 위해서는

값을 변경할 다이얼로그에 cpp에 메인프레임의 헤더와 뷰 헤더를 추가하고,

CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();

CmapToolView* pView = (CmapToolView*)pFrame->GetActiveView();

이렇게 얻어와서 pView를 이용해서 접근하면 된다고.. 검색해 보면 나온다..

그래서 그렇게 했는데 값이 제대로 들어가지를 않는다 -_ -;;;

내가 잘못넣었는지는 몰라도.. 메인 프레임 값은 잘 가져오는 것 같은데..

GetActiveView()에서 제대로 View 포인터를 리턴하지 않는 듯 했다...

난감한 상황에서 예전에 한번.. 분할 창으로 쓸때... 스플리터로 접근한 방법이

생각났다.. 

MFC는 구조가 언뜻보면 꼬여있는 듯 보이듯이.. 서로 참조할 방법을 여러가지

가지고 있다...

그래서 해결한 방법은.. .메인프레임에서..

CUItoolView* pView = (CUItoolView*)m_wndSplitter.GetPane(0,0) ;

이 한줄로 값을 얻어왔다....

휴.... 스플리터로 분리하면서 0번과 1번으로 분리되었으므로,

0번 윈도우를 참조하면.. 그 것이 바로 View 클래스 인 것이다...

헤매지말고 바로 얻어서 사용하도록 하자...


Posted by 바람처럼..
|


이전 포스팅의 순차 자료구조를 이용한 스택은 구현하기는 쉽지만, 물리적으로
크기가 고정된 배열을 사용하기 때문에 스택의 크기를 변경하기가 어렵고 메모

리의 낭비가 생길 수 있다는 문제가 있다. 이러한 순차 자료구조의 문제는 연결
자료구조를 사용함으로써 해결할 수 있다.

연결 자료 구조 중에서 단순 연결 리스트를 이용하여 스택을 구현하면 스택의

원소는 연결리스트의 노드가 된다. 스택에 원소를 삽입할 때 마다 연결 리스트

에 노드를 하나씩 연결한다. 그리고 스택 원소의 순서는 연결 리스트 노드의 링

크를 사용하여 표현한다. 스택의 top을 표현하기 위해서 노드에 포인터 top을

사용한다. 스택의 초기 상태는 포인터 top을 NULL 포인터로 설정하여 표현한

다.

다음은 간단히 구현해본 연결 자료구조 스택 소스 이다...

#include <stdio.h>

typedef struct stackNode{

 int data ;
 struct stackNode *link ;

}stackNode ;

stackNode* top ;

void push(int Num)
{
 stackNode* temp = new stackNode ;
 temp->data = Num ;
 temp->link = top ;
 top = temp ;
}

int pop()
{
 int Num ;
 stackNode* temp = top ;

 if(top == NULL )
  return 0 ;
 else
 {
  Num = temp->data ;
  top = temp->link ;
  delete temp ;
  return Num ;
 }
}

void printStack()
{
 stackNode* p = top ;
 
 printf("STACK [") ;

 while(p)
 {
  printf(" %d ", p->data ) ;
  p = p->link ;
 }
 printf(" ] \n ") ;
}

void main()
{
 top = NULL ;
 
 printStack() ;

 push(1) ;

 printStack() ;

 push(2) ;

 printStack() ;

 push(3) ;

 printStack() ;

 pop() ;

 printStack() ;

 pop() ;

 printStack() ;

 pop() ;

 printStack() ;
}

순차 구조와 거의 비슷하지만, 각 함수별로 저장하는 방식만 조금 다를 뿐이

다... 그리고 할당된 메모리를 해제하는 부분이 값을 빼는 부분에만 있기 때문

에 값을 많이 넣고, 그냥 종료해버리면 메모리누수가 생길 것이다..

이 것은 조금만 고민하면 알 수 있는 것이니 소스를 조금씩 개인적으로 수정해

서 쓰길 바란다..

Posted by 바람처럼..
|


스택은 수차 자료구조인 1차원 배열을 이용하여 스택을 구현할 수 있다. 1차원

배열인 stack[n]을 사용할 때 n은 배열 크기로서 배열원소의 갯수를 나타내는

데, 이것이 스택의 크기다. 스택에 원소가 쌓이는 순서는 배열의 인덱스로 표현

한다. 따라서 스택의 첫 번째 원소는 stack[0]에 저장되고, 스택의 두 번째 원

소는 stack[1]에 저장되고, 스택의 i번째 원소는 stack[i-1]에 저장된다.

스택이 top을 표현하기 위해서 배열 stack의 마지막 원소의 인덱스를 변수 top

에 저장한다. 변수 top에 0부터 n-1까지의 인덱스를 저장하게 되므로 스택의 초

기 상태에는 -1을 저장한다..

아래는 간단히 구현한 스택의 소스 이다.

#include <stdio.h>

#define STACK_SIZE 100

int stack[STACK_SIZE] ;

int top = -1 ;

void push(int Num)
{
 if( top >= STACK_SIZE - 1)
  return ;
 else stack[++top] = Num ;
}

int pop()
{

 if( top == -1)
  return 0 ;
 else return stack[top--] ;
}

void printStack()
{
 printf("Stack [ ") ;
 
 for( int i = 0 ; i <= top ; ++i )
  printf("%d ", stack[i]) ;
 
 printf("] \n") ;

}


void main()
{
 printStack() ;

 push(1) ;

 printStack() ;

 push(2) ;

 printStack() ;

 push(3) ;

 printStack() ;

 pop() ;

 printStack() ;

 pop() ;

 printStack() ;

 pop() ;

 printStack() ;
}

정말 간단한 구조이기 때문에 그냥 스택이 이런거구나 하는데만 쓰면 된다..

Posted by 바람처럼..
|

1에 이어서 계속...

이전 포스팅 보기

이전 포스팅의 마지막에서 OnInitialUpdate 함수를 추가하고, 내용을 입력하면

서 끝이 났다.. 그 이후에는...


리소스 뷰에 가서 IDD_CONTROLVIEW 다이얼 로그를 클릭하고, 저기 번개모

양인 컨트롤 이벤트 항목을 클릭하면 위와 같은 화면이 나온다...


그 중에서 TCN_SELCHANGE 함수를 만든다...


그러면 이런 함수가 추가되는데.. 여기서 값을 넣어주면, 탭의 상태가 변한다..


위의 select는 현재 클릭된 컨트롤의 값인데.. 그 값에 따라서 각 다이얼로그를

SHOW, HIDE 시켜주는 부분이다..


여기까지 완료하고 컴파일 하면.. 탭 컨트롤이 추가된 모습을 볼 수 있다..


텍스쳐 부분을 클릭하면 옆의 탭을 보여준다..

이 사진만 가지고는 티가 잘 안나니.. 컨트롤들을 추가해 보겠다..


1번 다이얼 로그에는 버튼과 스태틱 컨트롤을....

 


2번 다이얼로그에는 리스트 박스와 에디트 박스를 추가하였다..

그리고 다시 컴파일을 해보면..


1번 다이얼로그 ( Setting ) 이 선택되었을 때는 버튼과 스태틱 컨트롤이..

 


2번 다이얼로그 ( 텍스쳐 ) 에서는 리스트 박스와 에디트 박스가 나오는 것을

확인할 수 있다..

이제 진짜로 툴만들기의 기본이 끝났다고 할 수 있다..

이제부터는 왼쪽화면에서 무언가 화면을 그리고, 오른쪽 컨트롤 부분에서 값을
입력하면 실시간 대입되도록 연결만 시키면.. 멋진 툴이 될 수 있을 것이다...
Posted by 바람처럼..
|