0Pricing
Java Academy · บทเรียน

PriorityQueue สำหรับการประมวลผลตามลำดับ

ใช้ PriorityQueue ร่วมกับการเรียงลำดับตามธรรมชาติและ comparator แบบกำหนดเองในสถานการณ์การจัดตารางงาน

PriorityQueue สำหรับการประมวลผลตามลำดับ เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

PriorityQueue คืออะไร

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

import java.util.PriorityQueue;

PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(30);
pq.offer(10);
pq.offer(20);

System.out.println(pq.poll()); // 10 (min)
System.out.println(pq.poll()); // 20
System.out.println(pq.poll()); // 30

โครงสร้างฮีปภายใน

PriorityQueue ใช้ฮีปค่าต่ำสุดแบบทวิภาคที่จัดเก็บอยู่ในอาร์เรย์ โหนดแม่ที่ดัชนี i จะมีค่าน้อยกว่าหรือเท่ากับโหนดลูกที่ 2i+1 และ 2i+2 เสมอ จึงรับประกันว่าการดำเนินการ offer/poll ใช้เวลา O(log n) และ peek ใช้เวลา O(1)

ฮีปค่าสูงสุดด้วยตัวเปรียบเทียบแบบย้อนกลับ

หากต้องการสร้างฮีปค่าสูงสุด (สมาชิกที่มีค่ามากที่สุดอยู่ก่อน) ให้ส่ง Comparator.reverseOrder():

PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Comparator.reverseOrder());
maxPQ.offer(10);
maxPQ.offer(50);
maxPQ.offer(30);

System.out.println(maxPQ.poll()); // 50 (max)
System.out.println(maxPQ.poll()); // 30

PriorityQueue กับอ็อบเจ็กต์แบบกำหนดเอง

ใช้ตัวเปรียบเทียบเพื่อจัดลำดับระเบียนหรือคลาสแบบกำหนดเอง:

record Job(String name, int priority) {}

PriorityQueue<Job> queue = new PriorityQueue<>(
    Comparator.comparingInt(Job::priority) // ascending priority
);
queue.offer(new Job("Backup", 5));
queue.offer(new Job("Alert", 1));
queue.offer(new Job("Report", 3));

System.out.println(queue.poll().name()); // Alert (priority 1)

Peek เทียบกับ Poll

peek() คืนสมาชิกที่อยู่ส่วนหัวโดยไม่ลบออก ส่วน poll() จะลบและคืนสมาชิกนั้น ทั้งสองเมธอดคืนค่า null เมื่อคิวว่าง (ต่างจาก element()/remove() ที่จะโยนข้อยกเว้น)

PriorityQueue<String> pq = new PriorityQueue<>();
pq.offer("banana");
pq.offer("apple");

System.out.println(pq.peek()); // apple (not removed)
System.out.println(pq.peek()); // apple (still there)
System.out.println(pq.poll()); // apple (removed)
System.out.println(pq.peek()); // banana

ตัวอย่างการจัดตารางงาน

PriorityQueue เหมาะอย่างยิ่งสำหรับการจำลองการจัดตารางงานของ CPU ซึ่งงานแต่ละงานมีลำดับความสำคัญแตกต่างกัน:

record Task(String name, int priority) {}

PriorityQueue<Task> scheduler = new PriorityQueue<>(
    Comparator.comparingInt(Task::priority).reversed() // highest first
);
scheduler.offer(new Task("Low", 1));
scheduler.offer(new Task("Critical", 10));
scheduler.offer(new Task("Normal", 5));

while (!scheduler.isEmpty()) {
    System.out.println("Processing: " + scheduler.poll().name());
}
// Critical, Normal, Low

สมาชิกที่มีค่าน้อยที่สุด K รายการ

PriorityQueue เป็นเครื่องมือคลาสสิกสำหรับค้นหาสมาชิกที่มีค่าน้อยที่สุด K รายการ โดยไม่ต้องเรียงลำดับอาร์เรย์ทั้งหมด:

int[] nums = {7, 2, 5, 1, 9, 3, 8};
int k = 3;

PriorityQueue<Integer> pq = new PriorityQueue<>();
for (int n : nums) pq.offer(n);

for (int i = 0; i < k; i++) {
    System.out.print(pq.poll() + " ");
}
// 1 2 3

สมาชิกที่มีค่ามากที่สุด K รายการด้วยฮีปค่าสูงสุด

อีกทางเลือกหนึ่งคือ รักษาฮีปค่าต่ำสุดที่มีขนาด K ขณะวนซ้ำ เพื่อค้นหาสมาชิกที่มีค่ามากที่สุด K รายการ:

int[] nums = {7, 2, 5, 1, 9, 3, 8};
int k = 3;

PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int n : nums) {
    minHeap.offer(n);
    if (minHeap.size() > k) minHeap.poll(); // remove smallest
}
// minHeap now contains the 3 largest: [7, 8, 9]
System.out.println(minHeap); // order may vary

รูปแบบอัลกอริทึมของไดก์สตรา

อัลกอริทึมเส้นทางที่สั้นที่สุดของไดก์สตราอาศัยฮีปค่าต่ำสุด เพื่อขยายโหนดที่ยังไม่เยี่ยมชมและมีต้นทุนต่ำที่สุดก่อนเสมอ:

record Entry(int node, int cost) {}

PriorityQueue<Entry> pq = new PriorityQueue<>(
    Comparator.comparingInt(Entry::cost)
);
pq.offer(new Entry(0, 0)); // start node, cost 0

while (!pq.isEmpty()) {
    Entry curr = pq.poll();
    System.out.println("Visit node " + curr.node() + " cost=" + curr.cost());
    // expand neighbors...
}

การวนซ้ำไม่มีการจัดลำดับ

การวนซ้ำผ่าน PriorityQueue จะ NOT คืนสมาชิกตามลำดับความสำคัญ — มีเพียง poll() เท่านั้นที่ทำเช่นนั้น หากต้องการผลลัพธ์ที่เรียงลำดับ ให้เรียก poll ซ้ำ ๆ แทนการใช้การวนซ้ำแบบสมาชิกต่อสมาชิก

PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.addAll(List.of(5,3,1,4,2));

// WRONG for sorted output:
for (int n : pq) System.out.print(n+" "); // unordered!

// CORRECT:
while (!pq.isEmpty()) System.out.print(pq.poll()+" "); // 1 2 3 4 5

สรุปประสิทธิภาพ

ความซับซ้อนของการดำเนินการใน PriorityQueue:

  • offer(e): O(log n)
  • poll(): O(log n)
  • peek(): O(1)
  • contains(e): O(n)
  • remove(e): O(n)

ไม่ปลอดภัยต่อการทำงานหลายเธรด — ให้ใช้ PriorityBlockingQueue สำหรับการเข้าถึงพร้อมกัน

ตรวจสอบความเข้าใจ

การวนซ้ำ PriorityQueue ด้วยลูปแบบสมาชิกต่อสมาชิกให้การรับประกันอย่างไรเกี่ยวกับลำดับของสมาชิก

สรุป: PriorityQueue

ประเด็นสำคัญ:

  • PriorityQueue เป็นฮีปค่าต่ำสุด: สมาชิกที่มีค่าน้อยที่สุดจะถูกนำออกก่อนด้วย poll
  • ใช้ Comparator.reverseOrder() สำหรับฮีปค่าสูงสุด
  • offer/poll ใช้เวลา O(log n) ส่วน peek ใช้เวลา O(1)
  • กรณีใช้งานคลาสสิก: สมาชิกที่มีค่ามากที่สุด/น้อยที่สุดลำดับที่ K, ไดก์สตรา และการจัดตารางงาน
  • การวนซ้ำแบบสมาชิกต่อสมาชิกไม่ได้ให้ลำดับตามความสำคัญ — ให้ใช้ poll()

คำถามที่พบบ่อย

บทเรียน “PriorityQueue สำหรับการประมวลผลตามลำดับ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “PriorityQueue สำหรับการประมวลผลตามลำดับ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “PriorityQueue สำหรับการประมวลผลตามลำดับ”

ใช้ PriorityQueue ร่วมกับการเรียงลำดับตามธรรมชาติและ comparator แบบกำหนดเองในสถานการณ์การจัดตารางงาน คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “PriorityQueue สำหรับการประมวลผลตามลำดับ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. โครงสร้างภายในของ LinkedList
  2. การทำงานของ Deque: สแตกและคิว
  3. ข้อแลกเปลี่ยนระหว่าง LinkedList กับ ArrayList
  4. PriorityQueue สำหรับการประมวลผลตามลำดับ
← กลับไปที่ Java Academy