«کپه» مجموعهای است که همیشه کوچکترین عنصرش را میشناسد و به شما اجازه میدهد آن عنصر را بهسرعت بیرون بیاورید. این ابزار طبیعی برای یک «صف اولویت» است، یعنی صفی که در آن نوبت به مهمترین عنصر میرسد، نه به عنصری که بیشتر از همه منتظر مانده است. کپهها در واژگان 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 فوریترین است). یک «هیپ کمینه» صف انتظار ایدهآل است.
new-queue را تعریف کنید؛ این تابع چیزی نمیگیرد و یک صف اولویتدار تازه و خالی برمیگرداند.
new-queue
! => an empty priority queue
join-queue را تعریف کنید؛ این تابع اسم مشتری، یک شمارهی اولویت و یک صف میگیرد. مشتری را به صف اضافه میکند و صف را برمیگرداند، بنابراین میتوان مشتریها را یکی پس از دیگری اضافه کرد.
new-queue "alice" 5 rot join-queue "bob" 2 rot join-queue
! => the queue, now holding alice (5) and bob (2)
next-name را تعریف کنید؛ این تابع یک صف میگیرد و اسم مشتریای را برمیگرداند که باید بعدی به او رسیدگی شود (کسی که کمترین شمارهی اولویت را دارد)، بدون این که او را از صف حذف کند.
new-queue "alice" 5 rot join-queue "bob" 2 rot join-queue next-name .
! => "bob"
serve-all را تعریف کنید؛ این تابع یک صف میگیرد و اسم همهی مشتریان منتظر را به همان ترتیبی برمیگرداند که به آنها رسیدگی میشود.
new-queue "alice" 5 rot join-queue "bob" 2 rot join-queue
"carol" 9 rot join-queue serve-all .
! => { "bob" "alice" "carol" }