0Pricing
Java Academy · درس

PriorityQueue للمعالجة المرتبة

استخدم PriorityQueue مع الترتيب الطبيعي والمقارنات المخصصة في سيناريوهات جدولة المهام

PriorityQueue للمعالجة المرتبة درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 معكوس

لإنشاء كومة عظمى، بحيث يأتي العنصر الأكبر أولًا، مرّر 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 مثالية لمحاكاة جدولة وحدة المعالجة المركزية، حيث تكون للمهام أولويات مختلفة:

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

نمط خوارزمية Dijkstra

تعتمد خوارزمية Dijkstra لإيجاد أقصر مسار على كومة صغرى، لتوسّع دائمًا العقدة غير المُزارة الأقل تكلفة أولًا:

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 العناصر بترتيب الأولوية، بل تفعل ذلك poll() فقط. للحصول على خرج مرتب، نفّذ poll بشكل متكرر بدلًا من استخدام for-each.

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 باستخدام حلقة for-each؟

مراجعة: PriorityQueue

أهم النقاط:

  • PriorityQueue كومة صغرى: يُستخرج العنصر الأصغر أولًا
  • استخدم Comparator.reverseOrder() لإنشاء كومة عظمى
  • تعقيد offer وpoll هو O(log n)، وتعقيد peek هو O(1)
  • من حالات الاستخدام الشائعة: إيجاد العنصر الأكبر/الأصغر رقم K، وخوارزمية Dijkstra، وجدولة المهام
  • لا يوفّر for-each ترتيب الأولوية؛ استخدم poll()

الأسئلة الشائعة

هل درس «PriorityQueue للمعالجة المرتبة» مجاني؟

نعم — نص درس «PriorityQueue للمعالجة المرتبة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «PriorityQueue للمعالجة المرتبة»؟

استخدم PriorityQueue مع الترتيب الطبيعي والمقارنات المخصصة في سيناريوهات جدولة المهام تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «PriorityQueue للمعالجة المرتبة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. البنية الداخلية لـ LinkedList
  2. عمليات Deque: المكدس والطابور
  3. المفاضلة بين LinkedList وArrayList
  4. PriorityQueue للمعالجة المرتبة
← العودة إلى Java Academy