บทที่ 9: คิวแบบมีเงื่อนไข (Priority Queue)

วัตถุประสงค์

ในบางครั้งการใช้งานคิวตามปกติ ถึงแม้จะเป็นธรรม ให้บริการเท่าเทียมกัน แต่บางครั้งก็ขาดประสิทธิภาพ เช่นการเข้าคิวจ่ายเงินตามซุปเปอร์มาร์เก็ต หรือคิวรับฝากเงินของธนาคาร หรือคิวการจ่ายเงินค่าใช้ทางด่วนพิเศษ หรือคิวพิมพ์งานของเครื่องพิมพ์ ถ้าคนแรกๆของคิวมีการทำงานที่นานหลายๆรายการ แต่คนหลังมีพียงรายการเดียว การให้บริการจะขาดประสิทธิภาพ เพราะคนที่มีการทำงานสั้นต้องคอยคนที่ทำงานยาวๆเป็นเวลานาน ปริมาณงานที่สำเร็จต่อเวลาจะน้อยลง ดังนั้นการปรับปรุงระบบคิวตามเงื่อนไข เช่นการมีช่องทางด่วนไม่เกินสองรายการในการรับฝากเงินที่ธนาคาร หรือช่องทางด่วนคิดเงินไม่เกินสิบรายการตามซุปเปอร์มาร์เก็ต หรือช่องทางพิเศษสำหรับรถที่จ่ายเงินด้วยบัตรอัตโนมัติในการใช้ทางด่วนพิเศษ จะช่วยเพิ่มประสิทธิภาพในการทำงานของระบบโดยรวมได้ ซึ่งการสร้างคิวแบบมีเงื่อนไขนี้เราสามารถสร้างได้ด้วยโครงสร้างข้อมูลแบบไบนารีฮีป (Binary Heap) และไบโนเมียลคิว (Binomial Queue)

สำหรับเงื่อนไขในการสร้างคิวแบบนี้ เราจะใช้ค่าต่สุดหรือสูงสุดเป็นตัวกำหนดเงื่อนๆไข ขึ้นอยู่กับปัญหานั้นๆ แต่ส่วนใหญ่จะใช้ค่าต่ำสุดเป็นหลักตามตัวอย่างที่กล่าวมาด้านบน โดยข้อมูลที่มีค่าต่ำสุด จะถูกนำออกมาจากคิวเป็นลำดับแรกเสมอ ด้วยคำสั่ง deleteMins ซึ่งมีค่า Big O = O(1) หรือ O(log N) โดยใช้ Binary Heap หรือ Binomial Queue



ตัวอย่างไบนารีฮีป

Placeholder image
การสร้างไบนารีฮีป (Binary Heap) -->> Top

ไบนารีฮีป คือต้นไม้คู่สมบูรณ์ แต่โหนดใบในระดับล่างสุดอาจจะไม่เต็ม เพราะเราต้องทำการสร้างต้นไม้คู่สมบูรณ์ทีละโหนดตามลำดับจากบนลงล่าง จากซ้ายไปขวา และมีเงื่อนไขว่า โหนดด้านบนต้องมีค่าคีย์น้อยกว่าโหนดด้านล่างเสมอ และโหนดรากจะมีค่าคีย์ต่ำสุด ซึ่งจะเป็นโหนดแรกที่ถูกนำมาใช้งานก่อนเสมอ ดังนี้

1. เริ่มต้นฮีปจะว่าง โหนดแรกของต้นไม้ที่สร้างจะเป็นราก
Placeholder image
2. โหนดที่สองจะเป็นลูกทางซ้ายของราก และโหนดที่สามเป็นลูกทางขวาของราก
Placeholder image
3. โหนดต่อไปก็เติมให้เต็มในแต่ละชั้นจากซ้ายไปขวา
Placeholder image
4. แต่ละโหนดในฮีป จะมีคีย์สำหรับเปปรียบเทียบกับโหนดอื่นเพื่อการสลับตำแหน่งและคงคุณสมบัติของไบนารีฮีป
Placeholder image

คุณสมบัติลำดับของฮีปคือคีย์ของโหนดด้านบนต้องมีค่าน้อยกว่าโหนดด้านล่างเสมอ

Placeholder image
การสร้างฮีปด้วยอารเรย์ -->> Top

เพื่อความสะดวกในการสลับลำดับโหนดด้านบนและโหนดด้านล่างให้คงคุณสมบัติลำดับของฮีป เราจำเป็นต้องรู้ตำแหน่งดัชนีของโหนดด้านบน และด้านล่าง จากตัวอย่างฮีปด้านบน การใช้อาร์เรย์สร้างฮีปทำให้เรารู้ตำแหน่งดัชนีของแต่ละโหนดในฮีป

Placeholder image



ให้ดูรูปโครงสร้างต้นไม้ของฮีปและอาร์เรย์ของฮีปประกอบการคำนวณหาตำแหน่งขงแต่ละโหนด ดังนี้

1. รากจะเก็บอยู่ที่ดัชนี [1] เสมอ (โหนด 13) สังเกตว่าเราจะไม่ใช้ดัชนี [0] ของอาร์เรย์ในการสร้างฮีป ทั้งนี้เพื่อให้การคำนวณตำแหน่งดัชนีของแต่ละโหนดในฮีปทำได้รวดเร็วและถูกต้อง

2. โหนดด้านล่างทางซ้ายจะเก็บอยู่ที่ดัชนี 2i เมื่อ i คือดัชนีของโหนดด้านบน เช่นโหนดทางซ้ายของโหนดดัชนี [4] (โหนด 19) จะอยู่ที่ดัชนี 2*4=[8] (โหนด 65)

3. โหนดด้านล่างทางขวา จะเก็บอยู่ที่ดัชนี 2i+1 เมื่อ i คือดัชนีของโหนดด้านบน เช่นโหนดทางขวาของโหนดดัชนี [4] (โหนด 19) จะอยู่ที่ดัชนี (2*4)+1=[9] (โหนด 26)

4. โหนดด้านบนจะอยู่ที่ดัชนี i/2 เมื่อ i คือดัชนีของโหนดด้านล่าง เช่น โหนดดัชนี [9] (โหนด 26)จะมีโหนดด้านบนอยู่ที่ดัชนี 9/2=[4] (โหนด 19) เป็นต้น

5. การสร้างฮีปด้วยอาร์เรย์ ทำให้เราไม่จำเป็นต้องใช้ตัวชี้ด้านซ้ายและด้านขวาของต้นไม้ และการค้นหาในฮีปสำหรับการเพิ่มข้อมูลและการนำข้อมูลไปใช้ ถึงแม้ว่าจะมีค่า Big O = O(log N) เหมือนกัน แต่ทำได้ง่ายและรวดเร็วกว่า
การดำเนินการของฮีป (Heap Operations) -->> Top

หลักๆจะมีสองคำสั่งคือ Insert() และ DeleteMin() ดังนี้
Insert()
1. ในการเพิ่มข้อมูลใหม่เข้าไปในฮีป คือการสร้างโหนดใหม่ในต้นไม้คู้สมบูรณ์ โดยการวางโหนดใหม่ในลำดับที่ต้อจากโหนดสุดท้ายในฮีป จากนั้นก็ให้ให้ปรียบเทียบคีย์กับโหนดด้านบน ถ้าคีย์ของโหนดใหม่มีค่ามากกว่าโหนดด้านบน ก็จบการเพิ่มข้อมูล Big O = O(1)

Placeholder image

2. แต่ถ้าคีย์ของโหนดใหม่น้อยกว่าโหนดด้านบนก็ให้สลับตำแหน่งของโหนดทั้งสอง แล้วทำการเปรียบเทียบคีย์ของโหนดใหม่กับโหนดด้านบนไปเรื่อยๆ จนกว่าจะเจอตำแหน่งที่ถูกต้อง ในกรณีนี้ Big O = O (log N) และวิธีในการขยับโหนดใหม่ขึ้นข้างบนจนกว่าจะได้ตำแหน่งที่ถูกต้อง เราเรียกว่า percolate up

Placeholder image

ตัวอย่างการ Insert 9
ก่อน Insert 9

Placeholder image

หลัง Insert 9

Placeholder image
DeleteMin() -->> Top

ในการเอาโหนดออกไปใช้งาน โหนดรากจะถูกนำออกไปก่อนเสมอ ทำให้ต้นไม้แตกเป็นสองส่วน ฮีปถูกทำลาย ดังนั้นเราต้องหาวิธีการในการนำรากออกไปแต่ต้นไม้ยังคงสภาพคุณสบัติเดิมของฮีป ซึ่งมีวิธีการดังนี้

1. เอาโหนดรากออกไปใช้งาน แล้วเอาข้อมูลของโหนดสุดท้ายมาแทนที่ราก และลบโหนดสุดท้ายออกไป

Placeholder image

2. จากนั้นก็เปรียบเทียบคีย์ของรากอันใหม่ว่าน้อยกว่าคีย์ของโหนดด้านล่างหรือไม่ ถ้าน้อยกว่าก็จบ ฮีปยังคงคุณสมบัติเดิม และ Big O = O(1)

Placeholder image

3. แต่ถ้าคีย์ของรากอันใหม่มากกว่าคีย์ของโหนดด้านล่าง ให้สลับข้อมูลของโหนดด้านบนกับโหนดด้านล่างที่มีค่าคีย์น้อยกว่า จากนั้นก็ให้เปรียบเทียบคีย์กับโหนดด้านล่างไปเรื่อยๆจนกว่าจะได้ตำแหน่งที่ถูกต้อง ในกรณีนี้ Big O = O (log N) และวิธีในการขยับโหนดสุดท้ายลงข้างล่างเรื่อยๆจนกว่าจะได้ตำแหน่งที่ถูกต้อง เราเรียกว่า percolate down

Placeholder image
Placeholder image

ตัวอย่างการ DeleteMin

ก่อน DeleteMin

Placeholder image

หลัง DeleteMin

Placeholder image
ไบโนเมียลคิว (Binimial Queues) -->> Top
ไบโนเมียลคิว (Binimial Queues)
การเพิ่มข้อมูลในไบนารีฮีบ ต้องทำ ครั้ง ดังนั้นค่า Big O คือ O(1)
การลบข้อมูลในไบนารีฮีบ ทำเพียงครั้งเดียว ดังนั้นค่า Big O คือ O(1) แต่ในกรณีที่มีการชนกันของค่าแฮช ก็ต้องเลื่อนไปยังตำแหน่งที่ว่าง จำนวน c ครั้ง ดังนั้นค่า Big O คือ O(c)
สรุป -->> Top

2020. mnet50.com