트랙
/
Factor
Factor
/
연습 문제
/
창구 직원의 분류
창구 직원의 분류

창구 직원의 분류

학습 연습 문제

소개

힙은 항상 가장 작은 항목이 무엇인지 알고 있고, 그 항목을 빠르게 꺼낼 수 있는 컬렉션이에요. 우선순위 큐에 딱 맞는 도구죠. 우선순위 큐는 가장 오래 기다린 항목이 아니라 가장 중요한 항목이 먼저 처리되는 대기 줄이에요. 힙은 heaps 보캐뷸러리에 들어 있어요.

힙 만들기

<min-heap>은 가장 작은 키가 먼저 나오는 빈 힙을 만들어요. <max-heap>은 그 반대고요.

<min-heap> ( -- min-heap )
<max-heap> ( -- max-heap )

항목 추가하기

각 항목은 값과 키를 함께 묶어 저장해요. 키는 Factor가 순서를 정할 때 기준으로 삼는 우선순위예요. heap-push로 항목 하나를 추가해요.

heap-push ( value key heap -- )
USING: heaps ;

<min-heap>
"alice" 5 pick heap-push   ! value "alice", priority 5
"bob"   2 pick heap-push   ! value "bob",   priority 2

힙은 변경 가능해요. heap-push는 새 힙을 반환하는 대신 원래 힙을 그 자리에서 바꿔요. heap-push가 힙을 소비한 뒤에 힙을 다시 스택에 올려놓고 싶을 때 keep이 편리해요.

맨 앞 항목 살펴보고 꺼내기

heap-peek은 맨 앞 항목, 즉 키가 가장 작은 값을 제거하지 않고 반환해요. heap-pop은 그 항목을 반환하면서 제거도 하고요. heap-empty?는 남은 항목이 있는지 알려줘요. 언제 꺼내기를 멈춰야 하는지 알 수 있죠. heap-pop-all은 모든 항목을 한 번에 제거하고, 우선순위 순서대로 { key value } 쌍의 연관 리스트를 반환해요.

heap-peek    ( heap -- value key )
heap-pop     ( heap -- value key )
heap-empty?  ( heap -- ? )
heap-pop-all ( heap -- alist )
USING: assocs heaps kernel prettyprint ;

<min-heap>
"alice" 5 pick heap-push
"bob"   2 pick heap-push
dup heap-empty? .        ! => f      (two items waiting)
dup heap-peek drop .     ! => "bob"  (smallest key, still in the heap)
dup heap-pop drop .      ! => "bob"  (smallest key, now removed)
heap-pop-all .           ! => { { 5 "alice" } }

heap-pop과 heap-empty?는 항목을 하나씩 처리할 때 쓰는 기본 재료예요. 맨 앞을 살펴보거나 꺼내서 필요한 작업을 하고, heap-empty?가 t를 반환하면 멈춰요. 아래 과제에서는 heap-pop-all로 큐 전체를 한 번에 비우지만, 힙이 빌 때까지 꺼내도 같은 순서가 나와요.

heap-pop-all이 돌려주는 쌍은 연관 리스트예요. assocs에 있는 values를 쓰면 키는 버리고 값만 남길 수 있어요.

지침

바쁜 은행에서는 기다리는 고객을 도착한 순서가 아니라 우선순위에 따라 응대해요. 고객은 번호표를 뽑을 때 우선순위 번호를 받고, 창구 직원은 언제나 가장 낮은 번호를 가진 고객을 다음 순서로 응대해요(1이 가장 급해요). 최소 힙은 이런 대기 줄에 딱 맞아요.

1. 큐 열기

new-queue를 정의해요. 아무것도 받지 않고, 비어 있는 새 우선순위 큐를 반환해요.

new-queue
! => an empty priority queue

2. 고객 추가하기

join-queue를 정의해요. 고객 이름, 우선순위 번호, 큐를 받아요. 고객을 큐에 추가하고 그 큐를 반환해서, 고객을 차례로 추가할 수 있어요.

new-queue "alice" 5 rot join-queue "bob" 2 rot join-queue
! => the queue, now holding alice (5) and bob (2)

3. 다음은 누구?

next-name을 정의해요. 큐를 받아서 다음에 응대해야 할 고객, 즉 가장 낮은 우선순위 번호를 가진 고객의 이름을 반환해요. 단, 그 고객을 큐에서 꺼내지는 않아요.

new-queue "alice" 5 rot join-queue "bob" 2 rot join-queue next-name .
! => "bob"

4. 모두 응대하기

serve-all을 정의해요. 큐를 받아서 기다리는 모든 고객의 이름을, 응대되는 순서대로 반환해요.

new-queue "alice" 5 rot join-queue "bob" 2 rot join-queue
"carol" 9 rot join-queue serve-all .
! => { "bob" "alice" "carol" }
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Factor Exercism

창구 직원의 분류 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Factor 트랙을 개념 47개연습 문제 163개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.