البنية الداخلية لـ LinkedList
استكشف بنية العقد مزدوجة الارتباط في LinkedList وخصائص تعقيدها الزمني
البنية الداخلية لـ LinkedList درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.
التركيب الداخلي لـ LinkedList
إن LinkedList في Java عبارة عن قائمة مترابطة مزدوجة: تحتوي كل عقدة على مرجع إلى العقدة السابقة والتالية، بالإضافة إلى قيمة العنصر. وعلى خلاف ArrayList، لا توجد مصفوفة داعمة؛ إذ تُخصَّص الذاكرة لكل عقدة.
class Node<T> {
T data;
Node<T> prev;
Node<T> next;
Node(T data) { this.data = data; }
}خصائص التعقيد الزمني
تختلف خصائص أداء LinkedList كثيرًا عن ArrayList:
- addFirst / addLast: O(1)
- get(index): O(n) — يجب اجتياز العناصر بدءًا من الرأس أو الذيل
- remove(index): O(n) للعثور على العنصر، ثم O(1) لفصله
- Iterator traversal: O(n)
استخدم LinkedList عندما تحتاج إلى عمليات إدراج متكررة في الرأس أو الذيل، وليس إلى الوصول العشوائي.
إنشاء LinkedList واجتيازها
يتبع إنشاء LinkedList والتكرار عليها واجهة List نفسها التي تعرفها بالفعل. ويكمن الاختلاف في البنية الداخلية.
import java.util.LinkedList;
LinkedList<String> list = new LinkedList<>();
list.add("Alice");
list.add("Bob");
list.add("Carol");
for (String name : list) {
System.out.println(name);
}
System.out.println("First: " + list.getFirst()); // Alice
System.out.println("Last: " + list.getLast()); // CaroladdFirst وaddLast وremoveFirst وremoveLast
توفّر LinkedList عمليات على الرأس والذيل لا يوفّرها ArrayList بكفاءة:
LinkedList<Integer> nums = new LinkedList<>();
nums.addLast(10); // [10]
nums.addLast(20); // [10, 20]
nums.addFirst(5); // [5, 10, 20]
System.out.println(nums.removeFirst()); // 5 → [10, 20]
System.out.println(nums.removeLast()); // 20 → [10]فصل العقدة: حذف O(1) بعد العثور عليها
بمجرد امتلاكك مرجعًا إلى عقدة (عبر iterator)، تصبح الإزالة بتعقيد O(1)، إذ لا يلزم سوى تحديث مؤشري next وprev، بخلاف ArrayList الذي يتطلب إزاحة العناصر.
import java.util.*;
LinkedList<String> tasks = new LinkedList<>(List.of("A","B","C","D"));
Iterator<String> it = tasks.iterator();
while (it.hasNext()) {
String t = it.next();
if (t.equals("B") || t.equals("D")) {
it.remove(); // O(1) unlink
}
}
System.out.println(tasks); // [A, C]استهلاك الذاكرة مقارنةً بـ ArrayList
تحمل كل عقدة في LinkedList مرجعين إضافيين (prev وnext) بالإضافة إلى مرجع العنصر، أي نحو 48 بايتًا لكل إدخال على JVM 64-bit. أما ArrayList فتخزن مرجع العنصر فقط (8 بايتات) في مصفوفة متجاورة.
بالنسبة إلى مجموعات البيانات الكبيرة التي تكثر فيها عمليات القراءة، تكون ArrayList عادةً أفضل من حيث الاستفادة من ذاكرة التخزين المؤقت وتستهلك ذاكرة أقل.
عمليات Deque: المكدس والطابور
تطبّق LinkedList الواجهة Deque، مما يتيح استخدامها كمكدس وكطابور.
import java.util.LinkedList;
import java.util.Deque;
// As a Queue (FIFO)
Deque<String> queue = new LinkedList<>();
queue.offer("first");
queue.offer("second");
System.out.println(queue.poll()); // first
// As a Stack (LIFO)
Deque<String> stack = new LinkedList<>();
stack.push("bottom");
stack.push("top");
System.out.println(stack.pop()); // topنظرة عامة على PriorityQueue
إن PriorityQueue طابور قائم على heap، حيث يُزال العنصر الأصغر دائمًا أولًا وفق الترتيب الطبيعي أو Comparator. وهي لا تعتمد على قائمة مترابطة، بل تستخدم مصفوفة تمثل heap ثنائيًا.
import java.util.PriorityQueue;
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(40);
pq.offer(10);
pq.offer(25);
System.out.println(pq.poll()); // 10 (smallest)
System.out.println(pq.poll()); // 25
System.out.println(pq.poll()); // 40PriorityQueue باستخدام Comparator مخصص
مرّر Comparator لعكس الترتيب أو للفرز حسب حقل مخصص:
import java.util.*;
record Task(String name, int priority) {}
PriorityQueue<Task> tasks = new PriorityQueue<>(
Comparator.comparingInt(Task::priority).reversed() // highest first
);
tasks.offer(new Task("Low", 1));
tasks.offer(new Task("High", 10));
tasks.offer(new Task("Med", 5));
while (!tasks.isEmpty()) {
System.out.println(tasks.poll().name());
}
// High, Med, Lowاختيار LinkedList أو ArrayList
قاعدة عامة:
- استخدم ArrayList للوصول العشوائي والتكرار ومعظم السيناريوهات.
- استخدم LinkedList عندما تحتاج إلى عمليات إدراج وإزالة متكررة بتعقيد O(1) عند الطرفين، ولا تحتاج إلى الوصول باستخدام الفهرس.
- استخدم PriorityQueue عندما تحتاج إلى معالجة مرتبة، مثل جدولة المهام أو خوارزمية Dijkstra.
الأخطاء الشائعة
تجنب استدعاء get(i) داخل حلقة على LinkedList، إذ يصبح التعقيد الإجمالي O(n²):
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 10000; i++) list.add(i);
// BAD: O(n^2) — each get(i) traverses from head
for (int i = 0; i < list.size(); i++) {
int val = list.get(i); // slow!
}
// GOOD: O(n) — use iterator
for (int val : list) {
// process val
}اختبار سريع
ما عملية LinkedList التي يكون تعقيدها O(1) بغض النظر عن حجم القائمة؟
خلاصة: LinkedList وDeque
أهم النقاط:
- LinkedList قائمة مترابطة مزدوجة، وتنفذ العمليات على الرأس والذيل بتعقيد O(1)
- الوصول العشوائي (get/set باستخدام الفهرس) تعقيده O(n)
- تطبّق Deque، ويمكن استخدامها كمكدس أو طابور
- توفّر PriorityQueue معالجة مرتبة حسب heap
- فضّل ArrayList في معظم حالات الاستخدام؛ إذ تتفوق LinkedList عند إجراء تغييرات متكررة على الرأس والذيل
الأسئلة الشائعة
هل درس «البنية الداخلية لـ LinkedList» مجاني؟
نعم — نص درس «البنية الداخلية لـ LinkedList» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «البنية الداخلية لـ LinkedList»؟
استكشف بنية العقد مزدوجة الارتباط في LinkedList وخصائص تعقيدها الزمني تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «البنية الداخلية لـ LinkedList»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- البنية الداخلية لـ LinkedList
- عمليات Deque: المكدس والطابور
- المفاضلة بين LinkedList وArrayList
- PriorityQueue للمعالجة المرتبة