LinkedList أو ArrayList: معركة عمالقة المجموعات في Java
\n\nإذا كنت قد كتبت كود Java يعمل مع قوائم البيانات من قبل، فبالتأكيد واجهت المعضلة: LinkedList أم ArrayList؟ هذا السؤال هو ضربة حقيقية على Stack Overflow، يناقشه آلاف المطورين. وليس من العبث. اختيار هيكل البيانات الخاطئ يمكن أن يحول كودك السريع إلى سلحفاة تزحف في المستنقع. بينما الاختيار الصحيح يمكن أن يجعل التطبيق سريع الاستجابة وفعالاً.
\n\nاليوم لن نعدد الحقائق الجافة فقط. سننظر تحت الغطاء في Java، ونفهم كيف تعمل هذه المجموعات على مستوى الذاكرة والمعالج، ونعطي إجابة واضحة: متى يجب استخدام LinkedList، ومتى يجب استخدام ArrayList؟ هيا بنا!
\n\nباختصار عن المهم: ماذا يقول السادة في التوثيق
\n\nلنبدأ بالأساسيات. كلا الفئتين تنفذان واجهة List، لكنهما تفعلان ذلك بطرق مختلفة.
- \n
- ArrayList هو مصفوفة ديناميكية. يخزن العناصر في كتلة ذاكرة متصلة. عندما تمتلئ المصفوفة، يقوم بإنشاء مصفوفة جديدة أكبر حجماً وينسخ إليها جميع العناصر. \n
- LinkedList هو قائمة مرتبطة مزدوجة. كل عنصر (عقدة) يخزن مراجع للعنصر السابق والتالي. يتم تخصيص الذاكرة لكل عقدة على حدة. \n
يبدو الأمر بسيطاً. لكن الشيطان، كما هو الحال دائماً، في التفاصيل. دعنا نلقي نظرة على الكود.
\n\nتحت الغطاء: كيف يعمل هذا عملياً
\n\nArrayList: سرعة الوصول، لكن إدخال بطيء في المنتصف
\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ArrayListDemo {\n public static void main(String[] args) {\n List<String> arrayList = new ArrayList<>();\n \n // الإضافة في النهاية — سريعة (O(1) معدلة)\n long start = System.nanoTime();\n for (int i = 0; i < 100000; i++) {\n arrayList.add("Element " + i);\n }\n long end = System.nanoTime();\n System.out.println("ArrayList add (في النهاية): " + (end - start) / 1e6 + " ms");\n \n // الوصول حسب الفهرس — فوري (O(1))\n start = System.nanoTime();\n String element = arrayList.get(50000);\n end = System.nanoTime();\n System.out.println("ArrayList get: " + (end - start) + " ns");\n \n // الإدخال في المنتصف — بطيء (O(n))\n start = System.nanoTime();\n arrayList.add(25000, "INSERTED");\n end = System.nanoTime();\n System.out.println("ArrayList insert (المنتصف): " + (end - start) / 1e6 + " ms");\n }\n}\n\nماذا يحدث هنا؟ عندما تقوم بإدخال عنصر في منتصف ArrayList، فإن جميع العناصر الموجودة على يمين نقطة الإدخال تنتقل موضعاً واحداً. هذه عملية O(n). إذا كان لديك مليون عنصر، فستكون مليون عملية نسخ. مؤلم.
\n\nLinkedList: الإدخال هو الملك، لكن الوصول هو المنبوذ
\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class LinkedListDemo {\n public static void main(String[] args) {\n List<String> linkedList = new LinkedList<>();\n \n // الإضافة في النهاية — سريعة (O(1))\n long start = System.nanoTime();\n for (int i = 0; i < 100000; i++) {\n linkedList.add("Element " + i);\n }\n long end = System.nanoTime();\n System.out.println("LinkedList add (في النهاية): " + (end - start) / 1e6 + " ms");\n \n // الوصول حسب الفهرس — بطيء (O(n))\n start = System.nanoTime();\n String element = linkedList.get(50000);\n end = System.nanoTime();\n System.out.println("LinkedList get: " + (end - start) / 1e6 + " ms");\n \n // الإدخال في المنتصف — سريع (O(1) بعد البحث عن الموضع)\n start = System.nanoTime();\n // ملاحظة: طريقة add(index, element) نفسها لا تزال تقوم بالبحث (O(n))\n linkedList