Queue [2] ผู้สอน อาจารย์ ยืนยง กันทะเนตร สาขาวิชาเทคโนโลยีคอมพิวเตอร์เคลื่อนที่ คณะเทคโนโลยีสารสนเทศและการสื่อสาร Website : ict.up.ac.th/yeunyong
หัวข้อวันนี้ Performance of Queue Circular Queue How to implement ? Priority Queue Application of Queue
Performance of Queue จากโครงสร้างคิวที่ได้เรียน ยังไม่มีประสิทธิภาพมากนัก เช็คคิวเต็มโดยเงื่อนไข (rear == (MAXQUEUE - 1)) แต่ในความเป็นจริง อาจมีช่องว่างเหลืออยู่ทางด้านหน้าของคิว empty A front rear
คิวแบบวงกลม (Circular Queue) พัฒนาเพื่อให้ใช้พื้นที่อาร์เรย์ได้ประสิทธิภาพมากขึ้น นำส่วนท้ายของคิวที่ตำแหน่ง data[MAXQUEUE-1] ไปต่อกับส่วนหน้าที่ตำแหน่ง data[0] เมื่อ rear = MAXQUEUE-1 แต่ช่องด้านหน้าว่าง และต้องการใส่ข้อมูลเพิ่มลงในคิว จะใส่ข้อมูลลงในอาร์เรย์ตำแหน่งที่ 0 แทน เหมือนกับเอาช่องแรกมาต่อกับช่องสุดท้าย
Implementation of Circular queue โครงสร้างหลักของคิวยังคงเดิม (การประกาศตัวแปรแบบโครงสร้างเหมือนเดิม) #define MAXQUEUE 10 typedef struct { int data[MAXQUEUE]; int front; int rear; } QUEUE; QUEUE Q;
Implementation of Circular queue ฟังก์ชันทั้ง 5 บางฟังก์ชันอาจต้องมีการเปลี่ยนแปลง enqueue() – นำข้อมูลใส่ลงคิว dequeue() – ดึงข้อมูลออกจากคิว initQueue() – กำหนดค่าเริ่มต้นให้กับคิว isEmpty() – ตรวจสอบว่าคิวว่างหรือไม่ isFull() – ตรวจสอบว่าคิวเต็มหรือไม่
ฟังก์ชัน enqueue() parameter , return value -> คงเดิม body of function ตรวจสอบว่าคิวว่างหรือไม่ ถ้าใช่ -> กำหนดให้ front , rear ชี้ที่ array ช่องแรก ถ้าไม่ใช่ -> ตรวจสอบว่า rear อยู่ที่ array ช่องสุดท้ายหรือไม่ ถ้าใช่ -> กำหนดให้ rear มาชี้ที่ช่องแรก ถ้าไม่ใช่ -> เลื่อน rear ไป 1 ตำแหน่ง นำข้อมูลใส่อาร์เรย์ ณ ตำแหน่ง rear
ฟังก์ชัน dequeue() parameter , return value -> คงเดิม body of function return ข้อมูลจากอาร์เรย์ ณ ตำแหน่ง front ตรวจสอบว่าคิวมีข้อมูลอยู่ตัวเดียวหรือไม่ ถ้าใช่ -> กำหนดให้ front , rear มีสถานะเป็นคิวว่าง ถ้าไม่ใช่ -> ตรวจสอบว่า front อยู่ที่ array ช่องสุดท้ายหรือไม่ ถ้าใช่ -> กำหนดให้ front มาชี้ที่ช่องแรก ถ้าไม่ใช่ -> เลื่อน front ไป 1 ตำแหน่ง
ฟังก์ชัน isFull() front front rear rear front front rear rear B C D A สิ่งที่ต้องพิจารณาเพิ่มเติมอีกอย่างจากคิวธรรมดาคือ สถานะใดคือสถานะที่คิวเต็ม B C D A rear front A B C D front rear D A B C front rear C D A B rear front
ฟังก์ชัน isFull() parameter , return value -> คงเดิม body of function ตรวจสอบว่าคิวเต็มหรือไม่ (ในทุกเงื่อนไข) (((rear+1) mod MAXQUEUE) == front) ถ้าใช่ return 1 , ถ้าไม่ใช่ return 0
คิวลำดับความสำคัญ (Priority Queue) ข้อมูลทุกตัวจะมี “ลำดับความสำคัญ” กำกับไว้ ถ้าข้อมูลใดมีลำดับความสำคัญสูงกว่า จะเป็นข้อมูลที่ถูกนำออกจากคิวเป็นลำดับก่อนหน้า ไม่สนว่าข้อมูลนั้นจะเข้าคิวก่อนหรือหลัง ถ้าข้อมูลใดมีความสำคัญเท่ากัน จะถูกนำออกจากคิวตามลำดับคิว เข้าก่อนออกก่อน
ดังนั้น ข้อมูลที่จะเก็บอยู่ในคิวลำดับความสำคัญแต่ละตัวจะประกอบไปด้วย 2 ส่วน คือ data priority data=A priority=1 data=C data=G priority=2 data=I priority=3 data=K priority=5 Q [5] 3 2 1 4
Implementation of priority queue อาจประกาศเป็นอาร์เรย์อีก 1 ตัวก็ได้ #define MAXQUEUE 10 typedef struct { int data[MAXQUEUE]; int priority[MAXQUEUE]; int front; int rear; } QUEUE; QUEUE Q;
Implementation of priority queue จริงๆ แล้วนิยมตรวจสอบความสำคัญตั้งแต่ enqueue ถ้าข้อมูลที่นำเข้ามีความสำคัญสูงกว่า จะสลับที่กับข้อมูลตัวสุดท้ายในคิว เปรียบเทียบกับข้อมูลตัวถัดไปเรื่อยๆ จนกระทั่งอยู่ในตำแหน่งที่ถูกต้อง อยู่ต่อจากข้อมูลที่มีความสำคัญสูงกว่าหรือเท่ากับตัวมันเอง การ dequeue ทำเหมือนปกติทั่วๆ ไป
Implementation of priority queue ฟังก์ชันทั้ง 5 บางฟังก์ชันอาจต้องมีการเปลี่ยนแปลง enqueue() – นำข้อมูลใส่ลงคิว dequeue() – ดึงข้อมูลออกจากคิว initQueue() – กำหนดค่าเริ่มต้นให้กับคิว isEmpty() – ตรวจสอบว่าคิวว่างหรือไม่ isFull() – ตรวจสอบว่าคิวเต็มหรือไม่
ฟังก์ชัน enqueue() return value -> คงเดิม parameter -> เพิ่มตัวแปรเพื่อเก็บค่า priority ของข้อมูลที่ จะ insert อีก 1 รวมเป็น 3 ตัวแปร body of function การตรวจสอบต่างๆ คงเดิม ไม่ว่าจะเลือก implement แบบคิวธรรมดาหรือคิววงกลม แต่ต้องเปลี่ยนแปลงในส่วนการนำข้อมูลใส่ในอาร์เรย์ ต้องตรวจสอบลำดับความสำคัญกับข้อมูลตั้งแต่ท้ายแถวไปเรื่อยๆ เพื่อหาตำแหน่งที่เหมาะสมที่จะนำข้อมูลใส่
การนำข้อมูลใส่ (กรณีสร้างจากคิวธรรมดา) นำข้อมูลใส่ ณ ตำแหน่ง rear ตราบใดที่ข้อมูลไม่ได้อยู่ตำแหน่งแรก และ ความสำคัญของข้อมูลมีความสำคัญมากกว่าข้อมูลลำดับก่อนหน้า สลับที่ข้อมูลกับข้อมูลลำดับก่อนหน้า ย้อนกลับไปทำขั้นตอนที่ 2
ฟังก์ชัน enqueue() - เดิม void enqueue ( int x , QUEUE *q ) { if ( q->front == -1 ) // คิวว่าง q->front = q->rear = 0 ; else q->rear = q->rear + 1 ; q->data [ q->rear ] = x ; … }
การนำข้อมูลใส่ (กรณีสร้างจากคิววงกลม) นำข้อมูลใส่ ณ ตำแหน่ง rear ตราบใดที่ข้อมูลไม่ได้อยู่ตำแหน่งแรก และ ความสำคัญของข้อมูลมีค่ามากกว่าข้อมูลลำดับก่อนหน้า สลับที่ข้อมูลกับข้อมูลลำดับก่อนหน้า ย้อนกลับไปทำขั้นตอนที่ 2 สิ่งที่แตกต่างคือ ตำแหน่งของข้อมูลลำดับก่อนหน้า (position+MAXQUEUE-1) mod MAXQUEUE
ฟังก์ชัน enqueue() - เดิม void enqueue ( int x , QUEUE *q ) { if ( q->front == -1 ) // คิวว่าง q->front = q->rear = 0 ; else if ( q->rear == MAXQUEUE - 1 ) q->rear = 0 ; else q->rear = q->rear + 1 ; q->data [ q->rear ] = x ; … }
Application of Queue โครงสร้างข้อมูลแบบคิวถูกนำไปใช้ในการแก้ปัญหาลำดับการทำงาน งานที่ถูกเรียกใช้งานก่อนต้องถูกประมวลผลก่อน งานที่ถูกเรียกใช้งานทีหลังก็ต้องรอตามลำดับ (คิว) แต่ถ้างานไหนมีความสำคัญกว่าก็สามารถแทรกมาประมวลผลก่อนได้ (คิวลำดับความสำคัญ) ตัวอย่างเช่น printer spooling , การประมวลผลแบบ multiple task ฯลฯ
homework ให้เขียนโปรแกรมแสดงการทำงานของคิวแบบวงกลม โดยกำหนดให้ จองเนื้อที่ array of int มีขนาด 5 ช่อง โปรแกรมมีเมนูอย่างน้อย 3 เมนู คือ enqueue, dequeue , exit โปรแกรมต้องมีการตรวจสอบปัญหา overflow, underflow ด้วย
เมนู enqueue เป็นการใส่ข้อมูลเข้าคิว หลังจากใส่แล้ว ให้แสดงผลลัพธ์ของค่า front , rear และ array ที่แทนโครงสร้างคิว เมนู dequeue เป็นการดึงข้อมูลออกจากคิว หลังจากดึงข้อมูลออกมาแล้ว ให้แสดงว่าข้อมูลอะไรที่ถูกดึงออกมา และแสดงผลลัพธ์ของค่า front , rear และ array