轨道
/
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 返回的这些对是一个关联列表:values(位于 assocs 中)只保留值,丢弃键。

说明

一家忙碌的银行按优先级为等候的顾客办理业务,而不是按他们到达的顺序。每位顾客取号时都会得到一个优先级数字,柜员接下来总是服务数字最小的那位(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,借助 47 个概念163 个练习 和真人导师指导,学习并掌握 Factor,全部免费。