Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

القائمة المترابطة المزدوجة

آخر تحديث

القائمة المترابطة المزدوجة هي قائمة مترابطة تحمل فيها كل عقدة مؤشرين: next (إلى العقدة التالية) وprev (إلى العقدة السابقة). يتيح هذا الرابط الخلفي الإضافي التنقل في الاتجاهين وحذف عقدة في O(1) عندما تكون لديك مرجع إليها بالفعل، لأنه يمكنك الوصول إلى سابقتها مباشرة بدلًا من السير من الرأس. اضغط على زر التشغيل أعلاه لمشاهدة العقد وهي تُربط وتُعاد ربطها في كلا الاتجاهين.

الثمن هو مؤشر إضافي لكل عقدة والمزيد من الإدارة: يجب أن يحدّث كل إدراج وحذف كلًا من next وprev لدى الجيران. إنها البنية الكامنة وراء العديد من قوائم الانتظار المزدوجة (deque) وذاكرات التخزين المؤقت LRU، حيث يهم الحذف السريع من الطرفين.

التعقيد الزمني

العمليةالتعقيدملاحظات
الإدراج في الرأس/الذيلO(1)مع مؤشري الرأس والذيل
حذف عقدة معروفةO(1)الوصول إلى prev مباشرة، بلا سير
البحثO(n)لا يزال مسحًا خطيًا
الوصول بالفهرسO(n)لا وصول عشوائي

القائمة المترابطة المفردة مقابل المزدوجة

الجانبمفردةمزدوجة
المؤشرات لكل عقدة1 (next)2 (next + prev)
التنقل للخلفلانعم
حذف عقدة معروفةO(n) (إيجاد prev)O(1)
العبء على الذاكرةأقلأعلى

مثال محلول

بناء [10, 20, 30] بالإلحاق ثم حذف العقدة 20:

الخطوةالبنيةالإجراء
البدايةnullقائمة فارغة: head وtail كلاهما null
إلحاق 1010العقدة الأولى؛ يشير إليها head وtail، وprev = next = null
إلحاق 2010 <-> 20ضبط 10.next = 20 و20.prev = 10؛ tail = 20
إلحاق 3010 <-> 20 <-> 30ضبط 20.next = 30 و30.prev = 20؛ tail = 30
حذف 2010 <-> 30باستخدام 20.prev و20.next: ضبط 10.next = 30 و30.prev = 10 في O(1)

متى تستخدم القائمة المترابطة المزدوجة

استخدمها عندماتجنبها عندما
تحتاج إلى التنقل أو الوصل في الاتجاهينتتحرك للأمام فقط: القائمة المفردة أخف
تحذف عقدًا اعتباطية تملك مرجعًا إليها بالفعل (O(1))تفهرس غالبًا حسب الموضع: استخدم مصفوفة للوصول في O(1)
تنفّذ deque أو ذاكرة تخزين مؤقت LRU أو سجل تراجعالذاكرة ضيقة: مؤشر prev الإضافي يضاعف عبء الروابط
يحدث الإدراج والإزالة كثيرًا عند الطرفينالبيانات صغيرة ونادرًا ما تتغير: نسخ المصفوفات أرخص

كود Doubly Linked List

تنفيذ نظيف وقابل للتشغيل لخوارزمية Doubly Linked List بلغات Python, JavaScript, Java, C++, C. اختر لغة، وانسخ الكود، أو افتحه محمّلًا مسبقًا في ساحة تجربة Coddy.

كود Doubly Linked List بلغة Python

Python
1class Node:2    def __init__(self, value):3        self.value = value4        self.prev = None5        self.next = None6
7
8class DoublyLinkedList:9    def __init__(self):10        self.head = None11        self.tail = None12
13    def append(self, value):14        node = Node(value)15        if self.tail is None:16            self.head = self.tail = node17            return18        # Wire both directions: old tail <-> new node19        node.prev = self.tail20        self.tail.next = node21        self.tail = node22
23    def prepend(self, value):24        node = Node(value)25        if self.head is None:26            self.head = self.tail = node27            return28        node.next = self.head29        self.head.prev = node30        self.head = node31
32    def forward(self):33        values, current = [], self.head34        while current:35            values.append(current.value)36            current = current.next37        return values38
39    def backward(self):40        values, current = [], self.tail41        while current:42            values.append(current.value)43            current = current.prev44        return values45
46
47lst = DoublyLinkedList()48for value in [2, 3, 4]:49    lst.append(value)50lst.prepend(1)51
52print("Forward: ", lst.forward())53print("Backward:", lst.backward())
شغّل هذا الكود في ساحة تجربة Python

الأسئلة الشائعة حول القوائم المترابطة المزدوجة

ما الفرق بين القائمة المترابطة المفردة والمزدوجة؟
القائمة المترابطة المفردة لها مؤشر واحد لكل عقدة (next)، لذا يمكنك التحرك للأمام فقط. تضيف القائمة المترابطة المزدوجة مؤشر prev، مما يتيح التنقل للخلف وحذف عقدة تملك مرجعًا إليها في O(1) - مقابل مؤشر إضافي لكل عقدة وتحديث رابطين عند كل تغيير.
متى تستحق القائمة المترابطة المزدوجة الذاكرة الإضافية؟
عندما تحتاج إلى التنقل للخلف أو حذف عقد اعتباطية تشير إليها بالفعل في O(1) - الحالات الكلاسيكية هي قوائم الانتظار المزدوجة (deque) وذاكرات التخزين المؤقت LRU، حيث تُنقل المدخلات وتُطرد من الطرفين بكثرة.
لماذا تستطيع القائمة المترابطة المزدوجة حذف عقدة في O(1)؟
لإزالة عقدة يجب وصل سابقتها بلاحقتها. في القائمة المفردة عليك السير من الرأس لإيجاد السابقة (O(n))؛ أما في القائمة المزدوجة فيعطيك مؤشر prev للعقدة السابقة مباشرة، لذا تكون إعادة الربط في O(1).
القائمة المترابطة المزدوجة مقابل المصفوفة: أيهما أستخدم؟
استخدم المصفوفة عندما تحتاج إلى وصول في O(1) بالفهرس وتكرار ملائم للذاكرة المؤقتة، وعندما يحدث الإدراج غالبًا في النهاية. استخدم القائمة المترابطة المزدوجة عندما تدرج أو تحذف كثيرًا في المنتصف أو عند الطرفين مع وجود مرجع للعقدة، لأن ذلك O(1) مقابل إزاحة O(n) في المصفوفة. تتفوق المصفوفات في الذاكرة والمحلية؛ وتتفوق القائمة في التعديلات البنيوية.
ما هي العقدة الحارسة (sentinel) في القائمة المترابطة المزدوجة؟
العقدة الحارسة (أو الوهمية) هي عنصر نائب يوضع قبل الرأس و/أو بعد الذيل حتى لا تكون القائمة فارغة فعليًا أبدًا. تزيل فحوص null لـ head وtail وعمليات الإدراج/الحذف عند الحدود، مما يجعل كل عملية تتبع مسار إعادة الربط نفسه. تستخدم كثير من تطبيقات ذاكرة LRU في الإنتاج حارستين لتجنب معاملة الطرفين كحالات خاصة.
ما هو الخطأ الأكثر شيوعًا عند الحذف من قائمة مترابطة مزدوجة؟
نسيان تحديث head أو tail عند حذف العقدة الأولى أو الأخيرة، مما يترك مؤشرًا معلقًا إلى عقدة محررة. تحقق دائمًا مما إذا كان node.prev يساوي null (حدّث head) أو node.next يساوي null (حدّث tail) قبل إعادة ربط الجيران.
Coddy programming languages illustration

أتقن الخوارزميات مع Coddy

ابدأ الآن