Java مجموعة الخوارزميات في جافا

مقدمة

الكلاس Collections يحتوي على دوال ثابتة نوعها static. هذه الدوال تساعد كثيراً في الوصول إلى العناصر و التلاعب بها سواء كنت تتعامل مع الكلاسات التي ترث من الإنترفيس Collections أو مع الكلاسات التي ترث من الإنترفيس Map.

إذاً هذه الدوال تغنيك عن كتابة خوارزميات صعبة و معقدة, لذلك سميت مجموعة الخوارزميات ( Algorithms Collection ).

ميزة أخرى يقدمها لك الكلاس Collections هي المزامنة ( Synchronization), ستعرف أهمية المزامنة لاحقاً في هذا الدرس.


أخطاء محتملة

  • بعض الدوال التي يملكها ترمي الإستثناء UnsupportedOperationException إذا تم استخدامهم بطريقة خاطئة.
  • يرمى الإستثناء ClassCastException في حال كان لا يمكن تحويل نوع الكائن إلى نوع آخر.

طريقة التعامل مع مجموعة الخوارزميات

للتعامل مع الدوال الموجودة في مجموعة الخوارزميات عليك إتباع الخطوات التالية:

  1. إستدعاء الكلاس Collections, أي يجب أن تفعل له import.
  2. إستدعاء أي دالة تريد منه بشكل مباشر, أي ضع الكلمة Collections تليها نقطة, تليها إسم الدالة التي تريد.

دوال الكلاس Collections

الجدول التالي يحتوي على دوال الكلاس Collections الثابتة و التي تمثل مجموعة الخوارزميات.

الدالة مع تعريفها
public static int binarySearch(list, Object value) ترجع رقم index يمثل أول عنصر يملك القيمة value في الكائن list.
ترجع 1- في حال عدم إيجاد القيمة المطلوبة.
public static int binarySearch(list, Object value, Comparator c) ترجع رقم index يمثل أول عنصر يملك القيمة value في الكائن list.
الكائن c يحدد الطريقة التي ستعتمدها الدالة في البحث.
ترجع 1- في حال عدم إيجاد القيمة المطلوبة.
public static void copy(list1,2) تنسخ عناصر الكائن list2 في آخر الكائن list1.
public static Enumeration enumeration(Collection c) ترجع كائن نوعه Enumeration يحتوي على جميع عناصر الكائن c.
public static void fill(list, Object obj) تضع الكائن obj كقيمة لجميع عناصر الكائن list.
public static int indexOfSubList(list, subList) تبحث في الكائن list عن أول مكان يحتوي على جميع عناصر الكائن subList و بنفس الترتيب فيه.
في حال وجدت جميع عناصر الكائن subList بنفس الترتيب في الكائن list, ترجع رقم يمثل index أول عنصر بدء عنده إيجاد عناصر الكائن subList في الكائن list.
ترجع 1- في حال عدم إيجاد القيمة المطلوبة.
public static int lastIndexOfSubList(list, subList) تبحث في الكائن list عن آخر مكان يحتوي على جميع عناصر الكائن subList و بنفس الترتيب فيه.
في حال وجدت جميع عناصر الكائن subList بنفس الترتيب في الكائن list, ترجع رقم يمثل index آخر عنصر بدء عنده إيجاد عناصر الكائن subList في الكائن list.
ترجع 1- في حال عدم إيجاد القيمة المطلوبة.
public static Arraylist(Enumeration enum) ترجع كائن نوعه ArrayList يحتوي على جميع عناصر الكائن enum.
public static Object max(Collection c) ترجع أكبر عنصر موجود في الكائن c.
public static Object max(Collection c, Comparator comp) ترجع أكبر عنصر موجود في الكائن c.
الكائن comp يحدد الطريقة التي تعتمدها الدالة في مقارنة العناصر.
public static Object min(Collection c) ترجع أصغر عنصر موجود في الكائن c.
public static Object min(Collection c, Comparator comp) ترجع أصغر عنصر موجود في الكائن c.
الكائن comp يحدد الطريقة التي تعتمدها الدالة في مقارنة العناصر.
public static nCopies(int num, Object obj) ترجع كائن نوعه List يحتوي على نسخ من الكائن obj.
المتغير num يمثل عدد النسخ التي سيتم إنشاءها من الكائن obj. قيمة المتغير num يجب أن تكون أكبر أو تساوي صفر.
إذاً هنا عدد عناصر الكائن list الذي ترجعه الدالة يمثل عدد عناصر الكائن obj الموجودة فيه.
public static boolean replaceAll(list, Object oldValue, Object newValue) تبدل قيمة كل عنصر موجود في الكائن list في حال كانت تساوي قيمة الكائن oldValue بقيمة الكائن newValue.
ترجع true في حال تم تبديل قيمة عنصر واحد على الأقل, غير ذلك ترجع false.
public static void reverse(list) تعكس ترتيب عناصر الكائن list.
public static Comparator reverseOrder() ترجع كائن نوعه Comparator يمثل الكائن المستخدم في عكس ترتيب عناصر الكائنات.
public static void rotate(list, int n) تغير طريقة ترتيب عناصر الكائن list.
الباراميتر N يحدد كيف سيتم تبديل أماكن عناصر الكائن list.
ضع قيمة أصغر من صفر دائماً مكان الباراميتر N.
فمثلاً إذا وضعنا القيمة 2- مكان الباراميتر N, سيتم وضع آخر عنصرين موجودين في الكائن list في أوله.
public static void shuffle(list) تقوم بتبديل أمكان عناصر الكائن list بشكل عشوائي مرة واحدة.
public static void shuffle(list, Random rnd) تقوم بتبديل أمكان عناصر الكائن list بشكل عشوائي عدة مرات.
الكائن rnd يحدد كم مرة سيتم تبديل أماكنهم.
public static Set singleton(Object obj) ترجع نسخة من الكائن obj نوعها Set لا يمكن إجراء أي تعديل مباشر عليها لأنها تعتبر immutable.

إنتبه: هنا أي تعديل تفعله على الكائن الأصلي الذي قمت بتمريره مكان الباراميتر obj يطبق على النسخة التي أرجعتها الدالة أيضاً.
أي تعديل تحاول فعله على النسخة التي أرجعتها الدالة من هذا الكائن لا تؤثر عليها أو على الكائن الأصلي بتاتاً.
public static singletonList(Object obj) ترجع نسخة من الكائن obj نوعها List لا يمكن إجراء أي تعديل مباشر عليها لأنها تعتبر immutable.

إنتبه: هنا أي تعديل تفعله على الكائن الأصلي الذي قمت بتمريره مكان الباراميتر obj يطبق على النسخة التي أرجعتها الدالة أيضاً.
أي تعديل تحاول فعله على النسخة التي أرجعتها الدالة من هذا الكائن لا تؤثر عليها أو على الكائن الأصلي بتاتاً.
public static Map singletonMap(Object keys, Object values) ترجع نسخة من الكائنات keys و values في كائن واحد نوعه Map لا يمكن إجراء أي تعديل مباشر عليه لأنه يعتبر immutable.
الكائن keys يمثل جميع المفاتيح التي ستحتويها النسخة Map التي سترجعها الدالة.
الكائن values يمثل جميع القيم التي ستحتويها النسخة Map التي سترجعها الدالة.

إنتبه: هنا أي تعديل تفعله على الكائنات الأصلية الذي قمت بتمريرها مكان الباراميترات keys و values يطبق على النسخة التي أرجعتها الدالة أيضاً.
أي تعديل تحاول فعله على النسخة التي أرجعتها الدالة من هذه الكائنات لا تؤثر عليها أو على الكائنات الأصلية بتاتاً.
public static void sort(list, Comparator comp) ترتب العناصر الموجودة في الكائن list حسب طريقة المقارنة التي يعتمدها الكائن comp.
public static void sort(list) ترتب العناصر الموجودة في الكائن list حسب طريقة المقارنة التي يعتمدها كائن الـ Comparator الذي يستخدمه الكائن list إفتراضياً.
public static void swap(list, int index1, int index2) تبدل قيم العناصر الموجودة على الـ index1 و الـ index2.
public static Collection synchronizedCollection(Collection c) ترجع الكائن c ككائن متزامن نوعه Collections.
public static synchronizedList(list) ترجع الكائن list ككائن متزامن نوعه List.
public static Map synchronizedMap(Map m) ترجع الكائن m ككائن متزامن نوعه Map.
public static Set synchronizedSet(Set s) ترجع الكائن S ككائن متزامن نوعه Set.
public static SortedMap synchronizedSortedMap(SortedMap sm) ترجع الكائن sm ككائن متزامن نوعه SortedMap.
public static SortedSet synchronizedSortedSet(SortedSet ss) ترجع الكائن ss ككائن متزامن نوعه SortedSet.
public static Collection unmodifiableCollection(Collection c) ترجع الكائن c ككائن نوعه Collections غير قابل للتعديل.
public static unmodifiableList(list) ترجع الكائن list ككائن نوعه List غير قابل للتعديل.
public static Map unmodifiableMap(Map m) ترجع الكائن m ككائن نوعه Map غير قابل للتعديل.
public static Set unmodifiableSet(Set s) ترجع الكائن S ككائن نوعه Set غير قابل للتعديل.
public static SortedMap unmodifiableSortedMap(SortedMap sm) ترجع الكائن sm ككائن نوعه SortedMap غير قابل للتعديل.
public static SortedSet unmodifiableSortedSet(SortedSet ss) ترجع الكائن ss ككائن نوعه SortedSet غير قابل للتعديل.

المزامنة ( Synchronization )

في جميع الأمثلة التي وضعناها سابقاً لم نتطرق لفكرة المزامنة لأننا كنا نريدك أن تركز على فكرة و أهمية كل كلاس موجود ضمن كلاسات الـ Data Structure فقط.
في الحقيقة لم نضطر إلى مزامنة الكود أصلاً لأننا كنا نضع أمثلة صغيرة لا تحتوي على أوامر متزامنة, و بالتالي لا حاجة أصلاً للمزامنة.

تحتاج إلى مزامنة الكائن المستخدم في تخزين البيانات في حال كان البرنامج يحتوي على عدة أوامر تعمل بشكل متزامن, أي في حال وجود Thread آخر شغال في نفس الوقت الذي نحاول فيه المرور على عناصر الكائن.

إذاً من المهم جداً التأكد أن الكائن الذي تريد المرور على عناصره هو كائن متزامن ( Synchronized ) في حال وجود أكثر من Thread شغال في البرنامج.


ملاحظة

الكلاس Vector و الكلاس HashTable لا حاجة إلى مزامنتهم لأنهم أصلاً متزامنين.


طريقة المزامنة

المزامنة أمر سهل جداً و هي مقسمة إلى خطوتين أساسياتين:

  1. جعل الكائن متزامن مباشرةً عند إنشاءه باستخدام دالة من دوال التزامن الموجودة في الكلاس Collections تكون ملائمة لنوعه.
  2. وضع الكود الذي يمكننا من المرور على عناصر هذا الكائن في بلوك متزامن باستخدام الكلمة المحجوزة synchronized.

مثال

في المثال التالي قمنا بإنشاء كائن متزامن نوعه ArrayList, إسمه al يحتوي على 5 عناصر.
بعدها قمنا بتخزين هذه العناصر في كائن نوعه Iterator, إسمه i, ثم قمنا بعرض عناصر الكائن i بشكل متزامن بواسطة الحلقة while.

Main.java
import java.util.ArrayList;          // ArrayList هنا قمنا باستدعاء الكلاس
import java.util.Collections;        // Collections هنا قمنا باستدعاء الكلاس
import java.util.Iterator;           // Iterator هنا قمنا باستدعاء الإنترفيس
import java.util.List;               // هنا قمنا باستدعاء الإنترفيس
 
public class Main {
 
    public static void main(String[] args) {
 
        // al إسمه ArrayList هنا قمنا بإنشاء كائن متزامن من الكلاس
        ArrayList al = Collections.synchronizedList( new ArrayList() );
 
        // al هنا قمنا بإضافة 5 عناصر في الكائن
        al.add("A");
        al.add("B");
        al.add("C");
        al.add("D");
        al.add("E");
 
        // متزامنة al هنا قمنا بإنشاء بلوك يجعل العمليات التي تجري على الكائن
        synchronized( al ) {
            // al وضعنا فيه جميع عناصر الكائن i إسمه Iterator هنا قمنا بإنشاء كائن نوعه
            Iterator i = al.iterator();
 
            // و تعرض كل عنصر تمر عليه i هنا أنشأنا حلقة تمر على جميع عناصر الكائن
            while(i.hasNext()) {
                System.out.println(i.next());
            }
        }
 
    }
 
}
		

سنحصل على النتيجة التالية عند التشغيل.

A
B
C
D
E
		

مثال شامل

في المثال التالي قمنا بإنشاء كائن من الكلاس ArrayList إسمه al، ثم أدخلنا فيه خمسة عناصر.
بعدها استخدمنا الدوال sort() و reverseOrder() و shuffle() لترتيب العناصر بشكل تصاعدي، بشكل مقلوب و بشكل عشوائي ثم عرضناهم.
ثم عرضنا أصغر و أكبر قيمة بواسطة الدوال min() و max().

Main.java
import java.util.ArrayList;   // ArrayList هنا قمنا باستدعاء الكلاس
import java.util.Collections;   // Collections هنا قمنا باستدعاء الكلاس
import java.util.Comparator;   // Comparator هنا قمنا باستدعاء الإنترفيس
import java.util.Random;   // Random هنا قمنا باستدعاء الكلاس
 
public class Main {
 
    public static void main(String[] args) {
 
        // al إسمه ArrayList هنا قمنا بإنشاء كائن من الكلاس
        ArrayList al = new ArrayList();
 
        // al هنا قمنا بإضافة 5 عناصر في الكائن
        al.add(4);
        al.add(9);
        al.add(-5);
        al.add(-2);
        al.add(7);
 
        // التي قمنا بإدخالها al هنا عرضنا عناصر الكائن
        System.out.println("values: " + al);
 
        // بشكل تصاعدي ثم عرضناهم al هنا قمنا بترتيب عناصر الكائن
        Collections.sort(al);
        System.out.println("sorted: " + al);
 
        // بالمقلوب, و بالتالي ظهر و كأننا عرضناهم بشكل تنازلي al هنا قمنا بترتيب عناصر الكائن
        Comparator r = Collections.reverseOrder();
        Collections.sort(al, r);
        System.out.println("sorted in reverse: " + al);
 
        // مرة واحدة بشكل عشوائي ثم عرضناهم al هنا قمنا بتبديل أماكن عناصر الكائن
        Collections.shuffle(al);
        System.out.println("shuffled once: " + al);
 
        // خمس مرات بشكل عشوائي ثم عرضناهم al هنا قمنا بتبديل أماكن عناصر الكائن
        Collections.shuffle(al, new Random(5));
        System.out.println("shuffled 5 times: " + al);
 
        // al هنا قمنا بعرض أصغر و أكبر قيمة في الكائن
        System.out.println("minimum value: " + Collections.min(al));
        System.out.println("maximum value: " + Collections.max(al));
 
    }
 
}
		

سنحصل على نتيجة تشبه النتيجة التالية عند التشغيل لأن الدالة shuffle() تبدل أماكن العناصر بشكل عشوائي.

values: [4, 9, -5, -2, 7]
sorted: [-5, -2, 4, 7, 9]
sorted in reverse: [9, 7, 4, -2, -5]
shuffled once: [7, -2, 9, 4, -5]
shuffled 5 times: [4, -2, -5, 7, 9]
minimum value: -5
maximum value: 9
		

الدورات

أدوات مساعدة

أقسام الموقع

دورات
مقالات كتب مشاريع أسئلة