القائمة المرتبطة بشكل مزدوج: C++، Python (مثال للتعليمات البرمجية)

ما هي القائمة المرتبطة بشكل مضاعف؟

في القائمة المرتبطة بشكل مزدوج، تحتوي كل عقدة على روابط لكل من العقدة السابقة والتالية. تتكون كل عقدة من ثلاثة عناصر: واحد يحمل البيانات، والآخران هما مؤشرات العقدة التالية والسابقة. يساعدنا هذان المؤشران على المضي قدمًا أو للخلف من عقدة معينة.

إليك البنية الأساسية للقائمة المرتبطة بشكل مزدوج.

هيكل القائمة المرتبطة بشكل مزدوج
هيكل القائمة المرتبطة بشكل مزدوج

تحتوي كل قائمة مرتبطة على عقدة رأس وذيل. لا تحتوي العقدة الرأسية على عقدة "سابقة" (المؤشر السابق)، ولا تحتوي العقدة الخلفية على عقدة "تالية".

فيما يلي بعض المصطلحات المهمة لقائمة مرتبطة بشكل مضاعف:

  • السابق: ترتبط كل عقدة بالعقدة السابقة لها. يتم استخدامه كمؤشر أو رابط.
  • التالى: ترتبط كل عقدة بالعقدة التالية لها. يتم استخدامه كمؤشر أو رابط.
  • تاريخ: يتم استخدامه لتخزين البيانات في العقدة. يمكن أن تحتوي "البيانات" على أشياء أخرى هياكل البيانات داخله. على سبيل المثال، يمكن تخزين السلسلة والقاموس والمجموعة والهاشماب وما إلى ذلك في "البيانات".

فيما يلي البنية الأساسية لعقدة واحدة في القائمة المرتبطة بشكل مزدوج:

هيكل العقدة في القائمة المرتبطة بشكل مزدوج

هيكل العقدة في القائمة المرتبطة بشكل مضاعف

Operaميزات القائمة المرتبطة بشكل مزدوج

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

وهنا لائحة operaالإجراءات التي يمكننا تنفيذها باستخدام القائمة المرتبطة بشكل مضاعف:

  • الإدراج في الجبهة
  • الإدراج في الذيل أو العقدة الأخيرة
  • الإدراج بعد العقدة
  • الإدراج قبل العقدة
  • الحذف من الأمام
  • الحذف من الذيل
  • بحث وحذف عقدة
  • اجتياز الرأس إلى الذيل
  • اجتياز الذيل إلى الرأس

سنرى التنفيذ والكود الكاذب لجميع operaالأمور أعلاه.

الإدراج أمام القائمة المرتبطة بشكل مزدوج

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

على سبيل المثال، هناك عقدة معينة "15". نحن بحاجة إلى إضافة هذا إلى العقدة الرئيسية.

إليك شرطين مهمين أثناء القيام بذلك operaنشوئها:

  1. ستكون العقدة الجديدة هي العقدة الرئيسية إذا لم تكن هناك عقدة في القائمة المرتبطة بشكل مزدوج.
  2. إذا كانت هناك عقدة رأس بالفعل، فسيتم استبدال الرأس السابق بالعقدة الجديدة.

وإليك الرمز الزائف لهذا operaنشوئها:

function insertAtFront (ListHead, value):
  newNode = Node()
  newNode.value = value
  ListHead.prev = NewNode
  NewNode.next = ListHead
  newNode.prev = NULL
  return ListHead
الإدراج في العقدة الأمامية
الإدراج في العقدة الأمامية

الإدراج في نهاية القائمة المرتبطة بشكل مزدوج

"الإدراج في النهاية" يعني أننا سنقوم بإنشاء عقدة في القائمة المرتبطة ووضعها في النهاية.

ولتنفيذ ذلك يمكننا استخدام طريقتين:

  • طريقة 1: ابدأ في العبور من رأس القائمة المرتبطة بشكل مزدوج حتى تصبح "التالي" فارغة. ثم قم بربط العقدة الجديدة بالعقدة التالية.
  • طريقة 2: خذ العقدة الأخيرة من القائمة المرتبطة بشكل مزدوج. بعد ذلك، سيتم ربط العقدة "التالية" للعقدة الأخيرة بالعقدة الجديدة. الآن، ستكون العقدة الجديدة هي العقدة الخلفية.

إليك الرمز الزائف للإدراج في العقدة الخلفية:

function insertAtTail(ListHead, value):
  newNode = Node()
  newNode.value = value
  newNode.next = NULL
  while ListHead.next is not NULL:
	then ListHead = ListHead.next
  newNode.prev = ListHead
  ListHead.next = newNode
  return ListHead
الإدراج في نهاية القائمة المرتبطة

الإدراج في نهاية القائمة المرتبطة

الإدراج بعد العقدة

لنفترض أن لدينا قائمة مرتبطة بشكل مزدوج موجودة مثل القائمةwing:

الإدراج بعد العقدة

نريد إدراج عقدة معينة سيتم ربطها بعد العقدة، والتي لها القيمة "12".

وإليك الخطوات اللازمة لذلك:

الخطوة 1) اجتياز من الرأس إلى العقدة الأخيرة. تحقق من العقدة التي لها قيمة "12".

الخطوة 2) قم بإنشاء عقدة جديدة وقم بتعيينها كمؤشر التالي للعقدة "12". العقدة "التالية" للعقدة الجديدة ستكون 15.

إليك الرمز الزائف لإدراج عقدة بعد عقدة في القائمة المرتبطة بشكل مضاعف:

function insertAfter(ListHead, searchItem, value):
  List = ListHead
  NewNode = Node()
  NewNode.value = value
  while List.value is not equal searchItem
	then List = ListHead.next
  List = List.next
  NewNode.next = List.next
  NewNode.prev = List
  List.next = NewNode
الإدراج بعد العقدة

الإدراج بعد العقدة

الإدراج قبل العقدة

هذه operaيشبه الأمر إلى حد كبير "الإدراج بعد العقدة". نحتاج إلى البحث عن قيمة عقدة معينة للقيام بذلك. ثم سنقوم بإنشاء عقدة جديدة وإدراجها قبل العقدة التي تم البحث عنها.

لنفترض أننا نريد إدراج عقدة معينة "15" قبل العقدة "12". ثم إليك خطوات القيام بذلك:

الخطوة 1) اجتياز القائمة المرتبطة من العقدة الرئيسية إلى العقدة الخلفية.

الخطوة 2) تحقق مما إذا كان المؤشر التالي للعقدة الحالية يحمل القيمة "12" أم لا.

الخطوة 3) أدخل العقدة الجديدة باعتبارها العقدة "التالية" للعقدة الحالية.

إليك الرمز الزائف لإدراج عقدة قبل العقدة في القائمة المرتبطة بشكل مضاعف:

function insertBefore(ListHead, searchItem, value):
  List = ListHead
  NewNode = Node()
  NewNode.value = value
  while List.next.value is not equal searchItem
	then List = ListHead.next
  NewNode.next = List.next
  NewNode.prev = List
  List.next = NewNode
إدراج عقدة قبل العقدة

إدراج عقدة قبل العقدة

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

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

فيما يلي خطوات حذف العقدة الرئيسية:

الخطوة 1) قم بتعيين متغير لعقدة الرأس الحالية.

الخطوة 2) قم بزيارة العقدة "التالية" للعقدة الرئيسية الحالية واجعل العقدة "السابقة" (المؤشر السابق) على أنها "NULL". هذا يعني أننا نقوم بفصل العقدة الثانية عن العقدة الأولى.

الخطوة 3) قم بتحرير الذاكرة التي تشغلها العقدة الرئيسية السابقة.

إليك الكود الزائف لحذف الرأس من قائمة مرتبطة بشكل مضاعف:

function deleteHead(ListHead):
  PrevHead = ListHead
  ListHead = ListHead.next
  ListHead.prev = NULL
  PrevHead.next = NULL
  free memory(PrevHead)
  return ListHead
حذف العقدة الرئيسية

حذف عقدة الرأس

من الضروري حذف الذاكرة المخصصة بعد إجراء أي نوع من الحذف operaنشوئها. آخرwiseخلال فترة تشغيل البرنامج بأكملها، ستظل ذاكرة الكتلة المحذوفة مشغولة. لا يمكن لأي تطبيق آخر استخدام مقطع الذاكرة هذا.

احذف ذيل القائمة المرتبطة بشكل مزدوج.

هذه operaنشوئها هو نوع من نفس حذف الرأس. هنا، بدلا من الرأس، نحتاج إلى حذف الذيل. لتحديد العقدة كعقدة خلفية، يجب علينا التحقق مما إذا كان المؤشر التالي أو العقدة التالية فارغة أم لا. بعد حذف الذيل، نحن بحاجة إلى تحرير الذاكرة.

هذه operaيُعرف الحذف أيضًا باسم "الحذف من الخلف".

فيما يلي خطوات القيام بذلك:

الخطوة 1) اجتياز حتى العقدة الخلفية للقائمة المرتبطة بشكل مزدوج.

الخطوة 2) قم بتعيين متغير أو مؤشر إلى العقدة الخلفية.

الخطوة 3) اجعل العقدة "التالية" فارغة وحرر ذاكرة العقدة الخلفية.

إليك الرمز الزائف لحذف العقدة الخلفية:

function DeleteTail( ListHead ):
  head = ListHead
  while ListHead.next is not NULL:
	ListHead = ListHead.next
  Tail = ListHead.next
  ListHead.next = NULL
  free memory( Tail )
  return head

احذف ذيل الرابط المزدوج

بحث وحذف عقدة من القائمة المرتبطة بشكل مزدوج

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

وإليك الخطوات اللازمة لذلكarching وحذف عقدة في القائمة المرتبطة بشكل مزدوج:

الخطوة 1) قم باجتياز القائمة المرتبطة من الرأس حتى تساوي قيمة العقدة عنصر البحث.

الخطوة 2) قم بتعيين متغير "deleteNode" للعقدة المطابقة.

الخطوة 3) قم بتعيين العقدة السابقة من "deleteNode" إلى العقدة التالية.

الخطوة 4) تحرير ذاكرة "deleteNode"

إليك الرمز الزائف لـ searchiنانوغرام وحذف عقدة من القائمة المرتبطة:

function SearchAndDelete(ListHead, searchItem):
  head = ListHead
  while ListHead.next.value not equals searchItem:
	head = head.next
  deleteNode = head.next
  head.next = head.next.next
  head.next.prev = head
  deleteNode.next, deleteNode.next = NULL
  free memory(deleteNode)
  return ListHead
بحث وحذف Operaالإنتاج

بحث وحذف operaالإنتاج

اجتياز قائمة مرتبطة بشكل مضاعف من الأمام

للانتقال من العقدة الرئيسية والتكرار عبر العقدة التالية حتى نجد "NULL". أثناء اجتياز كل عقدة، يمكننا طباعة قيمة العقدة. فيما يلي خطوات العبور من الأمام (الاتجاه الأمامي):

الخطوة 1) قم بتعيين مؤشر أو متغير لعقدة الرأس الحالية.

الخطوة 2) قم بالتكرار إلى العقدة التالية من الرأس حتى تحصل على "NULL"

الخطوة 3) اطبع بيانات العقدة في كل تكرار.

الخطوة 4) إرجاع عقدة الرأس.

إليك الرمز الزائف لاجتياز القائمة المرتبطة بشكل مزدوج من الأمام:

function traverseFromFront(ListHead):
  head = ListHead
  while head not equals to NULL:
	print head.data
	head = head.next
  return ListHead

وهنا العودة ليست إلزامية. لكن من الممارسات الجيدة إرجاع عقدة الرأس بعد operaستعقد.

اجتياز قائمة مرتبطة بشكل مضاعف من الخلف

هذه operation هو عكس الاجتياز من الأمام. النهج هو نفسه مع اختلاف بسيط. يجب أن ننتقل إلى العقدة النهائية ثم ننتقل من العقدة النهائية إلى العقدة الأمامية.

فيما يلي خطوات اجتياز قائمة مرتبطة بشكل مزدوج من الخلف:

الخطوة 1) اجتياز حتى نصل إلى العقدة الذيل.

الخطوة 2) من العقدة الخلفية، سوف نجتاز حتى نحصل على العقدة السابقة كـ "NULL". سيكون "السابق" (المؤشر السابق) خاليًا بالنسبة للعقدة الرئيسية

الخطوة 3) في كل تكرار، سوف نقوم بطباعة بيانات العقدة.

إليك الرمز الزائف للعبور من الخلف:

function traverseFromBack(ListHead):
  head = ListHead
  while head not equals NULL:
	head = head.next
  tail = head
  while tail not equal to NULL:
	print tail.value
	tail = tail.prev
  return ListHead

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

يتمثل الاختلاف الرئيسي بين القائمة المنفردة والقائمة المرتبطة بشكل مزدوج في عدد الروابط.

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

إليك الفرق بين عقد القائمة المرتبطة بشكل فردي وبنية عقدة القائمة المرتبطة بشكل مزدوج:

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

القائمة المرتبطة بشكل مضاعف في C++

#include<iostream>
using namespace std;
  struct node{
  int data;
  struct node *next;
  struct node *prev;
  };
void insertFront(node* &listHead, int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  if(listHead!=NULL)
  {
	listHead->prev = newNode;
  	newNode->next = listHead;
  }
  
  listHead = newNode;
  cout<<"Added "<<value<<" at the front"<<endl;
  }
void insertEnd(node * &listHead, int value){
  if(listHead==NULL)
  {
  	insertFront(listHead,value);
  }
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  node *head = listHead;
  while(head->next!=NULL){
  head = head->next;
  }
  head->next = newNode;
  newNode->prev = head;
  cout<<"Added "<<value<<" at the end"<<endl;
  }
void insertAfter(node * &listHead, int searchValue,int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;	
  newNode->next = NULL;
  node *head = listHead;	
  while(head->next!=NULL &&  head->data!=searchValue){	
  head = head->next;	
  }	
  newNode->next = head->next;	
  head->next = newNode;	
  newNode->prev = head;	
  if(newNode->next !=NULL){	
  newNode->next->prev = newNode;	
  }	
  cout<<"Inserted "<<value<<" after node "<<searchValue<<endl;
  }
void insertBefore(node * &listHead, int searchValue,int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;	
  newNode->next = NULL;	
  node *head = listHead;	
  while(head->next!=NULL &&  head->next->data!=searchValue){	
  head = head->next;	
  }	
  newNode->next = head->next;	
  head->next = newNode;	
  newNode->prev = head;	
  if(newNode->next !=NULL){	
  newNode->next->prev = newNode;	
  }	
  cout<<"Inserted "<<value<<" before node "<<searchValue<<endl;	
  }
void traverseFromFront(node *listHead){
  node* head = new node();
  head = listHead;
  cout<<"Traversal from head:\t";	
  while(head!=NULL){	
  cout<<head->data<<"\t ";	
  head = head->next;	
  }	
  cout<<endl;
  }	
void traverseFromEnd(node *listHead){
  node* head = new node();
  head = listHead;	
  cout<<"Traversal from head:\t";	
  while(head->next!=NULL){	
  head = head->next;	
  }	
  node *tail = head;	
  while(tail!=NULL){	
  cout<<tail->data<<"\t";	
  tail = tail->prev;	
  }	
  cout<<endl;	
  }
void searchAndDelete(node **listHead, int searchItem){
  node* head = new node();
  head = (*listHead);
  while(head->next!=NULL &&  head->data!=searchItem){
  head = head->next;
  }
  if(*listHead == NULL || head == NULL) return;
  if((*listHead)->data == head->data){
  	*listHead = head->next;
  }
  if(head->next != NULL){
  	head->next->prev = head->prev;
  }
  
  if(head->prev != NULL){
  	head->prev->next = head->next;
  }
  free(head);
  cout<<"Deleted Node\t"<<searchItem<<endl;
  return;
  }
int main(){
  node *head = NULL;
  insertFront(head,5);
  insertFront(head,6);
  insertFront(head,7);
  insertEnd(head,9);
  insertEnd(head,10);
  insertAfter(head,5,11);
  insertBefore(head,5,20);
  traverseFromFront(head);
  traverseFromEnd(head);
  searchAndDelete(&head,7);
  traverseFromFront(head);
  traverseFromEnd(head);
}

الناتج

Added 5 at the front
Added 6 at the front
Added 7 at the front
Aded 9 at the end
Added 10 at the end
Inserted 11 after node 5
Inserted 20 before node 5
Traversal from head:    7        6       20      5       11      9       10
Traversal from head:    10      9       11      5       20      6       7
Deleted Node    7
Traversal from head:    6        20      5       11      9       10
Traversal from head:    10      9       11      5       20      6

قائمة مرتبطة مضاعفة في بايثون

class node:
  def __init__(self,data = None, prev=None, next = None):
    self.data = data
    self.next = next
    self.prev = prev
class DoublyLinkedList:
  def __init__(self):
    self.head = None

  def insertFront(self, val):
    newNode = node(data=val)
    newNode.next = self.head
    if self.head is not None:
      self.head.prev = newNode
    self.head = newNode
    print("Added {} at the front".format(val))

  def insertEnd(self,val):
    newNode = node(data=val)
    if self.head is None:
      self.insertFront(val)
    
    temp = self.head
    while temp.next is not None:
      temp = temp.next
    temp.next = newNode
    newNode.prev = temp
    print("Added {} at the end".format(val))

  def traverseFromFront(self):
    temp = self.head
    print("Traversing from head:\t",end="")
    while temp:
      print("{}\t".format(temp.data),end="")
      temp = temp.next
    print()

  def traverseFromEnd(self):
    temp = self.head
    print("Traversing from Tail:\t",end="")
    while temp.next is not None:
      temp = temp.next
    tail = temp
    while tail is not None:
      print("{}\t".format(tail.data),end="")
      tail = tail.prev
    print()
  
  def insertAfter(self,searchItem, value):
    newNode = node(data=value)

    temp = self.head
    while temp.next is not None and temp.data is not searchItem:
      temp = temp.next
    
    newNode.next = temp.next
    temp.next = newNode
    newNode.prev = temp

    if newNode.next is not None:
      newNode.next.prev = newNode
    print("Inserted {} after node {}".format(value,searchItem))

  def insertBefore(self,searchItem, value):
    newNode = node(data=value)

    temp = self.head
    while temp.next is not None and temp.next.data is not searchItem:
      temp = temp.next
    
    newNode.next = temp.next
    temp.next = newNode
    newNode.prev = temp

    if newNode.next is not None:
      newNode.next.prev = newNode
    print("Inserted {} before node {}".format(value,searchItem))

  def searchAndDelete(self,searchItem):
    temp = self.head

    while temp.next is not None and temp.data is not searchItem:
      temp = temp.next
    
    if self.head is None or temp is None:
      return

    if self.head.data is temp.data:
      self.head = temp.next

    if temp.next is not None:
      temp.next.prev = temp.prev
    
    if temp.prev is not None:
      temp.prev.next = temp.next
    
    print("Deleted Node\t{}".format(searchItem))
    return

doublyLinkedList = DoublyLinkedList()
doublyLinkedList.insertFront(5)
doublyLinkedList.insertFront(6)
doublyLinkedList.insertFront(7)
doublyLinkedList.insertEnd(9)
doublyLinkedList.insertEnd(10)
doublyLinkedList.insertAfter(5, 11)
doublyLinkedList.insertBefore(5, 20)
doublyLinkedList.traverseFromFront()
doublyLinkedList.traverseFromEnd()
doublyLinkedList.searchAndDelete(7)
doublyLinkedList.traverseFromFront()
doublyLinkedList.traverseFromEnd()

الناتج

Added 5 at the front
Added 6 at the front
Added 7 at the front
Added 9 at the end
Added 10 at the end
Inserted 11 after node 5
Inserted 20 before node 5
Traversing from head:   7       6       20      5       11      9       10
Traversing from Tail:   10      9       11      5       20      6       7
Deleted Node    7
Traversing from head:   6       20      5       11      9       10
Traversing from Tail:   10      9       11      5       20      6

معplexأهمية القائمة المرتبطة بشكل مزدوج

بشكل عام، الوقت كومplexوتنقسم ity إلى ثلاثة أنواع.

وهي:

  1. أفضل حالة
  2. متوسط ​​الحالة
  3. الحالة الأسوأ

فريق معplexity في أفضل حالة للقائمة المرتبطة بشكل مضاعف:

  1. الإدراج في الرأس أو الذيل سيكلف O(1). لأننا لا نحتاج إلى التنقل داخل القائمة المرتبطة. يمكن أن يتيح لنا مؤشر الرأس والذيل الوصول إلى عقدة الرأس والذيل باستخدام O(1) time complexإيتي.
  2. سيكلف الحذف في الرأس أو الذيل O(1).
  3. Searchiسيكون للعقدة الوقت complexأهمية O(1). لأن العقدة المستهدفة يمكن أن تكون العقدة الرئيسية.

فريق معplexity في الحالة المتوسطة للقائمة المرتبطة بشكل مزدوج:

  1. الإدراج في الرأس أو الذيل سيكون له وقت complexتكلفة التكلفة O(1).
  2. سيكون للحذف في الرأس أو الذيل وقت complexتكلفة التكلفة O(1).
  3. Searchiسيكون للعقدة الوقت complexوحدة O(n). لأن عنصر البحث يمكن أن يتواجد في أي مكان بين القائمة المرتبطة. هنا، "n" هو إجمالي العقدة الموجودة في القائمة المرتبطة.

أسوأ الأوقات كومplexستكون جودة القائمة المرتبطة بشكل مزدوج هي نفس الحالة المتوسطة.

الذاكرة كومplexأهمية القائمة المرتبطة بشكل مزدوج

الذاكرة كومplexity هي O(n)، حيث "n" هو العدد الإجمالي للعقد. أثناء تنفيذ القائمة المرتبطة يجب علينا تحرير الذاكرة التي استخدمناها. آخرwise، للحصول على قائمة مرتبطة أكبر، سيؤدي ذلك إلى تسرب الذاكرة.

نبذة عامة

  • القائمة المرتبطة هي نوع من بنية البيانات الخطية، وهي عبارة عن مجموعة من البيانات ممثلة بطريقة خطية.
  • القائمة المرتبطة بشكل مزدوج هي نوع من القائمة المرتبطة حيث تحتوي العقدة على روابط مع العقدة السابقة والتالية.
  • تحتوي القائمة المرتبطة بشكل مضاعف على كافة operaإجراءات مثل إضافة عقدة، وحذف عقدة، وإدراج عقدة بعد أو قبل عقدة أخرى، واجتياز القائمة المرتبطة من الرأس إلى الذيل.
  • تحتوي القائمة المرتبطة بشكل مزدوج على حقل بيانات واحد ورابطين. واحد للعقدة السابقة والآخر للعقدة التالية.
  • معplexأهمية القائمة المرتبطة بشكل مضاعف، أفضل حالة، حالة متوسطة
  • وأسوأ حالة.