شرح قوائم انتظار الأولوية في Java بأمثلة

يتم استخدام قوائم انتظار الأولوية كثيرًا في تطبيقات الحياة الواقعية. في هذه المقالة سنتعرف على قوائم الانتظار ذات الأولوية وكيف يمكننا استخدامها في Java.

قبل أن نناقش ماهية قائمة انتظار الأولوية ، دعنا نرى ما هي قائمة الانتظار العادية.

قائمة الانتظار العادية تتبع هيكل ما يرد أولاً يصرف أولاً (FIFO). هذا يعني أنه إذا دخلت 3 رسائل - m1 و m2 و m3 - في قائمة الانتظار بهذا الترتيب ، فإنها تخرج من قائمة الانتظار بنفس الترتيب بالضبط.

لماذا نحتاج قوائم الانتظار؟

لنفترض أن لدينا منتجي البيانات (على سبيل المثال ، عندما ينقر المستخدم على صفحة ويب) وهي سريعة للغاية. ولكن بعد ذلك نريد استهلاك هذه البيانات بوتيرة أبطأ لاحقًا.

في هذه الحالة ، سيدفع المنتج جميع الرسائل إلى قائمة الانتظار ، وسيستهلك المستهلك هذه الرسائل لاحقًا من قائمة الانتظار بوتيرة أبطأ.

ما هو طابور الأولوية؟

كما ذكرنا سابقًا ، تحتوي قائمة الانتظار العادية على بنية أول ما يرد أولاً. ولكن في بعض السيناريوهات ، نريد معالجة الرسائل في قائمة الانتظار بناءً على أولويتها وليس بناءً على وقت دخول الرسالة إلى قائمة الانتظار.

تساعد قوائم الانتظار ذات الأولوية المستهلكين على استهلاك الرسائل ذات الأولوية الأعلى أولاً متبوعة بالرسائل ذات الأولوية الأقل.

قوائم انتظار الأولوية في Java

الآن دعنا نرى بعض كود Java الفعلي الذي سيوضح لنا كيفية استخدام قوائم الانتظار ذات الأولوية.

قوائم الانتظار ذات الأولوية بالترتيب الطبيعي

إليك بعض التعليمات البرمجية التي توضح كيفية إنشاء قائمة انتظار بسيطة لأولويات السلاسل

private static void testStringsNaturalOrdering() { Queue testStringsPQ = new PriorityQueue(); testStringsPQ.add("abcd"); testStringsPQ.add("1234"); testStringsPQ.add("23bc"); testStringsPQ.add("zzxx"); testStringsPQ.add("abxy"); System.out.println("Strings Stored in Natural Ordering in a Priority Queue\n"); while (!testStringsPQ.isEmpty()) { System.out.println(testStringsPQ.poll()); } }

يخبرنا السطر الأول أننا نقوم بإنشاء قائمة انتظار ذات أولوية:

Queue testStringsPQ = new PriorityQueue();

يتوفر PriorityQueue في حزمة java.util.

بعد ذلك سنضيف 5 سلاسل بترتيب عشوائي إلى قائمة انتظار الأولوية. لهذا نستخدم الوظيفة add () كما هو موضح أدناه:

testStringsPQ.add("abcd"); testStringsPQ.add("1234"); testStringsPQ.add("23bc"); testStringsPQ.add("zzxx"); testStringsPQ.add("abxy");

من أجل الحصول على أحدث عنصر من قائمة الانتظار ، نستخدم وظيفة الاستطلاع () كما هو موضح أدناه:

testStringsPQ.poll()

الاستطلاع () سيعطينا أحدث عنصر وإزالته أيضًا من قائمة الانتظار. إذا أردنا الحصول على أحدث عنصر في قائمة الانتظار دون إزالته ، فيمكننا استخدام وظيفة peek () :

testStringsPQ.peek()

أخيرًا ، نقوم بطباعة جميع العناصر من قائمة الانتظار باستخدام وظيفة الاستطلاع () كما هو موضح أدناه:

while (!testStringsPQ.isEmpty()) { System.out.println(testStringsPQ.poll()); }

هنا هو إخراج البرنامج أعلاه:

1234 23bc abcd abxy zzxx

نظرًا لأننا لم نخبر قائمة انتظار الأولوية بكيفية تحديد أولويات محتواها ، فقد استخدمت ترتيبًا طبيعيًا افتراضيًا. في هذه الحالة ، أعادتنا البيانات بالترتيب التصاعدي للسلاسل. هذا ليس نفس الترتيب الذي تمت إضافة العناصر به إلى قائمة الانتظار.

ماذا عن وجود طلب مخصص؟

هذا ممكن أيضًا ، ويمكننا القيام به بمساعدة عامل المقارنة.

لنقم بإنشاء قائمة انتظار ذات أولوية عدد صحيح الآن. لكن هذه المرة دعونا نحصل على النتيجة بترتيب تنازلي للقيمة.

لتحقيق ذلك ، نحتاج أولاً إلى إنشاء مقارن عدد صحيح:

 static class CustomIntegerComparator implements Comparator { @Override public int compare(Integer o1, Integer o2) { return o1 < o2 ? 1 : -1; } }

من أجل إنشاء مقارنة ، نقوم بتنفيذ واجهة المقارنة وتجاوز طريقة المقارنة .

باستخدام o1 <o2؟ 1: -1 سنحصل على النتيجة بترتيب تنازلي. إذا استخدمنا o1> o2؟ 1: -1 ، إذن كنا سنحصل على النتيجة بترتيب تصاعدي

الآن بعد أن أصبح لدينا المقارنة ، نحتاج إلى إضافة هذا المقارنة إلى قائمة انتظار الأولوية. يمكننا القيام بهذا على النحو التالي:

Queue testIntegersPQ = new PriorityQueue(new CustomIntegerComparator());

فيما يلي بقية الكود الذي يضيف عناصر إلى قائمة انتظار الأولوية ويطبعها:

 testIntegersPQ.add(11); testIntegersPQ.add(5); testIntegersPQ.add(-1); testIntegersPQ.add(12); testIntegersPQ.add(6); System.out.println("Integers stored in reverse order of priority in a Priority Queue\n"); while (!testIntegersPQ.isEmpty()) { System.out.println(testIntegersPQ.poll()); }

ناتج البرنامج أعلاه معطى أدناه:

12 11 6 5 -1

يمكننا أن نرى أن المقارنة قامت بعملها بشكل جيد. الآن قائمة انتظار الأولوية تعطينا الأعداد الصحيحة بترتيب تنازلي.

قائمة انتظار الأولوية مع كائنات Java

حتى هذه النقطة ، رأينا كيف يمكننا استخدام السلاسل والأعداد الصحيحة مع قوائم الانتظار ذات الأولوية.

في تطبيقات الحياة الواقعية ، سنستخدم عمومًا قوائم انتظار ذات أولوية مع كائنات Java مخصصة.

لنقم أولاً بإنشاء فئة تسمى CustomerOrder تُستخدم لتخزين تفاصيل طلب العميل:

public class CustomerOrder implements Comparable { private int orderId; private double orderAmount; private String customerName; public CustomerOrder(int orderId, double orderAmount, String customerName) { this.orderId = orderId; this.orderAmount = orderAmount; this.customerName = customerName; } @Override public int compareTo(CustomerOrder o) { return o.orderId > this.orderId ? 1 : -1; } @Override public String toString() { return "orderId:" + this.orderId + ", orderAmount:" + this.orderAmount + ", customerName:" + customerName; } public double getOrderAmount() { return orderAmount; } }

هذه فئة Java بسيطة لتخزين طلبات العملاء. تطبق هذه الفئة واجهة قابلة للمقارنة ، حتى نتمكن من تحديد الأساس الذي يحتاج إليه هذا الكائن في الترتيب في قائمة انتظار الأولوية.

يتم تحديد الترتيب من خلال وظيفة المقارنة في الكود أعلاه. السطر o.orderId> this.orderId؟ 1: -1 يوجه بضرورة فرز الطلبات بناءً على الترتيب التنازلي لحقل معرف الطلب

يوجد أدناه الكود الذي ينشئ قائمة انتظار ذات أولوية لكائن CustomerOrder:

CustomerOrder c1 = new CustomerOrder(1, 100.0, "customer1"); CustomerOrder c2 = new CustomerOrder(3, 50.0, "customer3"); CustomerOrder c3 = new CustomerOrder(2, 300.0, "customer2"); Queue customerOrders = new PriorityQueue(); customerOrders.add(c1); customerOrders.add(c2); customerOrders.add(c3); while (!customerOrders.isEmpty()) { System.out.println(customerOrders.poll()); }

في الكود أعلاه ، تم إنشاء ثلاثة طلبات عملاء وإضافتها إلى قائمة انتظار الأولوية.

عند تشغيل هذا الكود نحصل على المخرجات التالية:

orderId:3, orderAmount:50.0, customerName:customer3 orderId:2, orderAmount:300.0, customerName:customer2 orderId:1, orderAmount:100.0, customerName:customer1

كما هو متوقع ، تأتي النتيجة بترتيب تنازلي لمعرّف الأمر .

ماذا لو أردنا تحديد الأولويات بناءً على OrderAmount؟

هذا مرة أخرى سيناريو واقع الحياة. دعنا نقول أنه بشكل افتراضي يتم إعطاء الأولوية لكائن CustomerOrder بواسطة معرف الطلب. ولكن بعد ذلك نحتاج إلى طريقة يمكننا من خلالها تحديد الأولويات بناءً على مبلغ النظام.

قد تعتقد على الفور أنه يمكننا تعديل وظيفة المقارنة في طلب العميل للطلب بناءً على مبلغ الطلب.

ولكن يمكن استخدام CustomerOrder c lass في أماكن متعددة في التطبيق ، وقد يتداخل مع بقية التطبيق إذا قمنا بتعديل وظيفة المقارنة مباشرة.

الحل بسيط للغاية: يمكننا إنشاء مقارن مخصص جديد لفئة CustomerOrder واستخدامه جنبًا إلى جنب مع قائمة انتظار الأولوية

يوجد أدناه رمز المقارنة المخصصة:

 static class CustomerOrderComparator implements Comparator { @Override public int compare(CustomerOrder o1, CustomerOrder o2) { return o1.getOrderAmount() < o2.getOrderAmount() ? 1 : -1; } }

هذا مشابه جدًا لمقارنة الأعداد الصحيحة المخصصة التي رأيناها سابقًا.

o1.getOrderAmount() < o2.getOrderAmount() ? 1 : -1;يشير السطر إلى أننا بحاجة إلى تحديد الأولويات بناءً على الترتيب التنازلي لمبلغ الطلب .

يوجد أدناه الكود الذي ينشئ قائمة انتظار الأولوية:

 CustomerOrder c1 = new CustomerOrder(1, 100.0, "customer1"); CustomerOrder c2 = new CustomerOrder(3, 50.0, "customer3"); CustomerOrder c3 = new CustomerOrder(2, 300.0, "customer2"); Queue customerOrders = new PriorityQueue(new CustomerOrderComparator()); customerOrders.add(c1); customerOrders.add(c2); customerOrders.add(c3); while (!customerOrders.isEmpty()) { System.out.println(customerOrders.poll()); }

في الكود أعلاه ، نقوم بتمرير المقارنة إلى قائمة انتظار الأولوية في السطر التالي من الكود:

Queue customerOrders = new PriorityQueue(new CustomerOrderComparator());

فيما يلي النتيجة عند تشغيل هذا الرمز:

orderId:2, orderAmount:300.0, customerName:customer2 orderId:1, orderAmount:100.0, customerName:customer1 orderId:3, orderAmount:50.0, customerName:customer3

يمكننا أن نرى أن البيانات تأتي بترتيب تنازلي حسب ترتيب المبلغ.

الشفرة

يمكن العثور على جميع الأكواد التي تمت مناقشتها في هذه المقالة في GitHub repo.

مبروك ؟

أنت تعرف الآن كيفية استخدام قوائم الانتظار ذات الأولوية في Java.

عن المؤلف

أحب التكنولوجيا وأتابع التطورات في هذا المجال. أحب أيضًا مساعدة الآخرين بمعرفي التكنولوجي.

لا تتردد في الاتصال بي على حسابي على LinkedIn //www.linkedin.com/in/aditya1811/

يمكنك أيضًا متابعتي على twitter //twitter.com/adityasridhar18

لا تتردد في قراءة المزيد من مقالاتي على مدونتي على adityasridhar.com.