Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C/C++ Q/A
[2404] Re:Re:[중급자용 해답]가장 짧고 빠르게 푸는 방법: 힙(heap)을 써야 합니다.
임문환 [mhlim] 1168 읽음    2003-04-15 12:25
우선, 다양한 해결 방법을 제시해주시고 코드의 효율성까지 염두하며 프로그래밍해야 함을 일깨워 주신 김백일 님에게 감사를 드립니다.

예로 드신 마지막 코드에 버그가 있군요.
배열에 있는 기존 값 중 가장 큰 값과 input 값 간에 상호 대/소 비교 없이
pop_heap과 push_heap를 하게 되면
추가로 입력한 값이 더 큰 경우 문제가 발생합니다.
현재 예에서는 추가로 입력한 값들(1,2,3,4)이 기존에 배열에 있던 값 중 큰 것 네개(7,7,8,9)보다 작기 때문에 오류가 현실화 되지는 않았지만
만약 10,11,2,6... 이런 식으로 추가로 입력한다면 오류가 현실화 되어 나타납니다.


예에서 모든 pop_heap과 push_heap를 제거한 다음
아래와 같이 해야 하지 않을까요?
   
    while (cin >> input) { 
        if(heap[0]>input){
         pop_heap( &heap[0], &heap[heap_size]);
         heap[heap_size - 1] = input;   
         push_heap(&heap[0], &heap[heap_size]);
        }
     .
     .
     .
   }
   .
   .
   .

김백일.cedar 님이 쓰신 글 :
: 이글은 STL에 대해서 조금이라도 알고 계신 분들을 위한 설명입니다.
:
: 김지혜 님이 쓰신 글 :
: : 10개 이상의 수를 사용자 임의로 입력받아서 그 중 크기 순으로 작은 수 10개를 출력하는 
: : 프로그램인데요.
:
: 만약, 문제가 여기까지라면, 이 문제를 푸는 것은 정말 쉽겠죠?
: 그냥 배열이나 vector에 전부 때려 넣은 후, partial_sort 알고리듬을 쓰면 간단합니다.
:
: int main()
: {
:     const int sort_end = 10;
:     cout << "Enter more numbers. Press [Ctrl+Z] and Enter to quit.\n";
:     vector<int> v((istream_iterator<int>(cin)), istream_iterator<int>());
:     partial_sort(v.begin(), v.begin() + sort_end, v.end());
:     copy(v.begin(), v.begin() + sort_end, ostream_iterator<int>(cout, " "));
:     cout.put('\n');
:
:     return 0 ;
: }
:
: : (단, 10보다 큰 사이즈의 배열을 사용하면 안된다.)
:
: 그런데 문제는 이와 같이 크기가 10으로 고정된 배열을 사용해야 한다는 겁니다.
: 배열이 아닌 다른 컨테이너를 쓸 수 있다면, 연관 컨테이너인 multiset을 사용하는 방법이 있습니다.
:
: int main()
: {
:     const int set_size = 10;
:     multiset<int> ms;
:     int input;
:
:     cout << "Enter 10 numbers: ";
:     for (int i = 0; i < set_size; ++i) {
:            cin >> input;
:         ms.insert(input);
:     }
:
:     cout << "Enter more numbers. Press [Ctrl+Z] and Enter to quit.\n";
:
:     multiset<int>::reverse_iterator ri;
:     while (cin >> input) {              // 주의: 컨테이너의 마지막 원소의 위치는
:         ri = ms.rbegin();               // end()가 아니라,rbegin()입니다.
:         if (input < *ri) {
:             ms.erase((++ri).base());    // ri가 가리키는 요소를 삭제하는 방법
:             ms.insert(input);
:         }
:     }
:
:     copy(ms.begin(), ms.end(), ostream_iterator<int>(cout, " "));
:     cout.put('\n');
:
:     return 0 ;
: }
:
: 또는 이와 유사한 방법으로서, list를 sort 멤버함수로 정렬한 후,
: 원소를 삽입할 위치를 이진 검색 알고리듬인 lower_bound 나 upper_bound 또는 equal_range으로 검색하여 새 원소를 삽입/삭제하는 방법도 있습니다.
: 이상의 방법의 복잡도는 O(N log N)으로서 상당히 빠릅니다.
:
: 그러나 여기서는 배열을 써야 한다는 조건이 있으므로, 다르게 구현해야 합니다.
: 임문환님의 방법과 같이 새 값을 삽입할 때마다 max_element() 알고리듬으로 위치를 검색해야 한다면, O(N^2)의 복잡도를 갖게 되므로 효율이 떨어지는 방법입니다.
:
: 즉, 배열을 multiset과 같이 원소의 삽입, 삭제에 O(log N)이 걸리도록 하는 방법을 사용해야 합니다. 이러한 자료구조를 힙(heap)라고 합니다. 힙 자체에 대한 자세한 설명은 모든 자료구조 책에 다 나와있습니다.
:
: STL에서도 일반적인 시퀀스 컨테이너를 힙으로 사용할 수 있게하는 알고리듬을 제공합니다.
: 이에 대해서는 제가 C/C++ Tip'N Tricks에 간단한 소개를 올렸습니다.
: http://www.borlandforum.com/impboard/impboard.dll?action=read&db=cpp_tip&no=21
: 여기서는 이들 네가지 STL 힙 알고리듬을 이 문제에 적용하여 풀어보겠습니다.
:
: int main()
: {
:     const int heap_size = 10;
:     int input, heap[heap_size];
:     ostream_iterator<int> out(cout, " ");   // 출력 반복자 정의
:
:     cout << "Enter 10 numbers: ";
:     // heap[0..9]까지 입력받음
:     for (int i = 0; i < heap_size; ++i) {
:            cin >> input;
:         heap[i] = input;
:     }
:
:     // heap[0..9]를 힙으로 만듦: O(N) 복잡도
:     make_heap(&heap[0], &heap[heap_size]);
:     #ifdef _DEBUG // 디버그 모드에서는 힙의 내용 출력
:     cout << "After make_heap : ";
:     copy(&heap[0], &heap[heap_size], out); cout.put('\n');
:     #endif
:     pop_heap( &heap[0], &heap[heap_size]); // 가장 큰 값을 pop: O(log N)
:     #ifdef _DEBUG
:     cout << "After  pop_heap : ";
:     copy(&heap[0], &heap[heap_size], out); cout.put('\n');
:     #endif
:
:     cout << "Enter more numbers. Press [Ctrl+Z] and Enter to quit.\n";
:     while (cin >> input) {
:         heap[heap_size - 1] = input;    // push할 원소를 마지막에 놓음
:         push_heap(&heap[0], &heap[heap_size]); // 힙에 push: O(log N)
:         #ifdef _DEBUG
:         cout << "After push_heap : ";
:         copy(&heap[0], &heap[heap_size], out); cout.put('\n');
:         #endif
:         pop_heap( &heap[0], &heap[heap_size]); // 가장 큰 값을 pop: O(log N)
:         #ifdef _DEBUG
:         cout << "After  pop_heap : ";
:         copy(&heap[0], &heap[heap_size], out); cout.put('\n');
:         #endif
:     }
:
:     // 힙 전용 정렬 알고리듬: sort보다 상수배 만큼 빠릅니다. 그러므로 O(N log N)
:     sort_heap(&heap[0], &heap[heap_size]);
:     cout << "After sort_heap : "; // 당연히 sort_heap 후에는 더이상 힙이 아닙니다.
:     copy(&heap[0], &heap[heap_size], out); cout.put('\n');
:
:     return 0 ;
: }
:
: 결과는 다음과 같습니다.
:
: Enter 10 numbers: 3 4 5 6 7 5 6 7 8 9
: After make_heap : 9 8 6 7 7 5 5 3 6 4
: After  pop_heap : 8 7 6 7 4 5 5 3 6 9
: Enter more numbers. Press [Ctrl+Z] and Enter to quit.
: 1
: After push_heap : 8 7 6 7 4 5 5 3 6 1
: After  pop_heap : 7 7 6 6 4 5 5 3 1 8
: 2
: After push_heap : 7 7 6 6 4 5 5 3 1 2
: After  pop_heap : 7 6 6 3 4 5 5 2 1 7
: 3
: After push_heap : 7 6 6 3 4 5 5 2 1 3
: After  pop_heap : 6 6 5 3 4 5 3 2 1 7
: 4
: After push_heap : 6 6 5 3 4 5 3 2 1 4
: After  pop_heap : 6 4 5 3 4 5 3 2 1 6
: ^Z
: After sort_heap : 1 2 3 3 4 4 5 5 6 6

: 참고로, partial_sort도 힙 정렬 알고리듬을 사용하여 구현되어 있습니다.
: 이와 같이 사용할 수 있는 공간이 제한될 때는 힙이 유용하게 사용됩니다.

+ -

관련 글 리스트
2364 숫자를 입력받아서 크기 순으로 작은 수 10개를 출력하는 프로그램인데요..짧거든요.. 한번만..봐주세요.. 김지혜 1309 2003/04/11
2397     [답변] 대충 답변 드려서 최송....ㅋㅋ...컴파일 해보구 다시 올립니다.. 정성훈.해미 1295 2003/04/14
2388     Re:[중급자용 해답]가장 짧고 빠르게 푸는 방법: 힙(heap)을 써야 합니다. 김백일.cedar 1267 2003/04/14
2404         Re:Re:[중급자용 해답]가장 짧고 빠르게 푸는 방법: 힙(heap)을 써야 합니다. 임문환 1168 2003/04/15
2405             Re:Re:Re: 버그로군요. 좋은 지적 감사합니다. ^^ 김백일.cedar 1247 2003/04/15
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.