الأمراض المنقولة جنسيا::قائمة في C++ مع المثال

⚡ ملخص ذكي

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

  • 🔗 قائمة مرتبطة ثنائياً: يحتفظ كل عنصر بروابط إلى العقدة السابقة واللاحقة له، لذلك فإن بيانات std::list تعيش في ذاكرة غير متجاورة.
  • ⚡ إدراج وحذف سريع: إضافة أو إزالة عنصر في موضع معروف يستغرق وقتاً ثابتاً، على عكس المتجه الذي يقوم بتحريك العناصر.
  • 🚫 لا يوجد وصول عشوائي: يتم الوصول إلى العناصر عن طريق الاجتياز التسلسلي من كلا الطرفين، لذا فإن الفهرسة مثل list[3] غير متاحة.
  • 🧩 منشئو: تقوم الدوال الإنشائية الافتراضية، و fill، و range، و copy، و move، و initializer-list بإنشاء std::list بطرق مختلفة.
  • 🛠️ وظائف الأعضاء: تقوم الدوال push_front() و push_back() و insert() و erase() و size() و reverse() و merge() بإدارة محتويات القائمة.
  • 🤖 مساعدة الذكاء الاصطناعي: يقوم GitHub Copilot والمساعدون المماثلون بإنشاء هياكل لتصريحات std::list، والمكررات، ومنطق الإدراج أو الحذف من تعليق قصير.

الأمراض المنقولة جنسيا::قائمة في C++

ما هي الأمراض المنقولة جنسيا :: القائمة؟

In C++يشير std::list إلى حاوية تخزين. يتيح لك std::list إضافة العناصر وحذفها من أي مكان. يتم تنفيذ std::list كقائمة مرتبطة ثنائياً، مما يعني إمكانية الوصول إلى بيانات القائمة في كلا الاتجاهين وبشكل تسلسلي.

لا تدعم قائمة مكتبة القوالب القياسية الوصول العشوائي السريع، ولكنها تدعم الوصول التسلسلي من جميع الاتجاهات.

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

تثير هذه السمات سؤالاً عملياً: متى يجب عليك فعلاً اللجوء إلى قائمة؟

لماذا استخدام الأمراض المنقولة جنسيا :: القائمة؟

فيما يلي أسباب استخدام std::list:

  • تُعدّ std::list أفضل مقارنةً بحاويات التسلسل الأخرى مثل المصفوفة والمتجه.
  • تتميز بأداء أفضل في الإدخال والتحريك والإخراجtracعناصر الاختبار من أي موضع.
  • كما تعمل std::list بشكل أفضل مع الخوارزميات التي تقوم بتنفيذ مثل هذه العمليات بشكل مكثف.

بعد أن اتضحت الأسباب، فإن الخطوة التالية هي صياغة الصيغة التي تعلن عن ذلك.

بناء جملة القائمة

لتحديد std::list، علينا استيراد ملف الملف الاساسي. فيما يلي بناء جملة تعريف std::list:

template < class Type, class Alloc =allocator<T> > class list;

فيما يلي وصف للمعلمات المذكورة أعلاه:

  • T – يحدد نوع العنصر الموجود. يمكنك استبدال T بأي نوع بيانات، حتى الأنواع التي يحددها المستخدم.
  • Alloc – يحدد نوع كائن المُخصِّص. يستخدم هذا قالب فئة المُخصِّص افتراضيًا. وهو يعتمد على القيمة ويستخدم نموذجًا بسيطًا لتخصيص الذاكرة.

مثال 1

#include <algorithm>
#include <iostream>
#include <list>
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };

	for (int x : my_list) {
		std::cout << x << '\n';
	}
}

الإخراج:

مخرجات مثال إنشاء وتكرار قائمة std::list

فيما يلي لقطة شاشة للكود:

C++ كود يقوم بإنشاء قائمة std::list وطباعتها باستخدام حلقة for

Code التفسير:

  1. قم بتضمين ملف رأس الخوارزمية لاستخدام وظائفه.
  2. قم بتضمين ملف رأس iostream لاستخدام وظائفه.
  3. قم بتضمين ملف رأس القائمة لاستخدام وظائفه.
  4. استدعاء الدالة الرئيسية (). يجب إضافة منطق البرنامج داخل نص هذه الوظيفة.
  5. أنشئ قائمة باسم my_list تحتوي على مجموعة مكونة من 4 أعداد صحيحة.
  6. إستخدم لحلقة لإنشاء متغير حلقة x. سيتم استخدام هذا المتغير للتكرار على عناصر القائمة.
  7. اطبع قيم القائمة على وحدة التحكم.
  8. نهاية جسم الحلقة.
  9. نهاية نص الدالة main().

C++ وظائف القائمة

فيما يلي وظائف std::list الشائعة:

الوظيفة الوصف
إدراج() تقوم هذه الوظيفة بإدراج عنصر جديد قبل الموضع الذي يشير إليه المكرر.
إدفع إلى الخلف() تضيف هذه الوظائف عنصرًا جديدًا في نهاية القائمة.
Push_front() يضيف عنصرًا جديدًا في مقدمة القائمة.
pop_front() يقوم بحذف العنصر الأول في القائمة.
بحجم() تحدد هذه الوظيفة عدد عناصر القائمة.
أمام() لتحديد العناصر الأولى في القائمة.
خلف() لتحديد العنصر الأخير في القائمة.
عكس () إنه يعكس عناصر القائمة.
دمج() فهو يدمج قائمتين مرتبة.

البنائين

وهنا لائحة وظائف المقدمة من الملف الاساسي:

  • المُنشئ الافتراضي std::list::list()- يقوم بإنشاء قائمة فارغة تحتوي على صفر عناصر.
  • منشئ التعبئة std::list::list()- يقوم بإنشاء قائمة تحتوي على عناصر n ويعين قيمة صفر (0) لكل عنصر.
  • منشئ النطاق std::list::list()- ينشئ قائمة تحتوي على العديد من العناصر في النطاق من الأول إلى الأخير.
  • منشئ النسخ std::list::list()- يقوم بإنشاء قائمة تحتوي على نسخة من كل عنصر موجود في القائمة الموجودة.
  • منشئ النقل std::list::list()- ينشئ قائمة بعناصر قائمة أخرى باستخدام دلالات النقل.
  • منشئ قائمة التهيئة std::list::list() - يقوم بإنشاء قائمة بعناصر قائمة أخرى باستخدام دلالات النقل.

مثال 2

#include <iostream>
#include <list>
using namespace std;
int main(void) {
	list<int> l;
	list<int> l1 = { 10, 20, 30 };
	list<int> l2(l1.begin(), l1.end());
	list<int> l3(move(l1));  
	cout << "Size of list l: " << l.size() << endl;
	cout << "List l2 contents: " << endl;
	for (auto it = l2.begin(); it != l2.end(); ++it)
	      cout << *it << endl;
	cout << "List l3 contents: " << endl;
	for (auto it = l3.begin(); it != l3.end(); ++it)
		cout << *it << endl;
	return 0;
}

الإخراج:

مخرجات مثال مُنشئات std::list

فيما يلي لقطة شاشة للكود:

C++ كود يوضح كيفية إنشاء std::list باستخدام الدوال الافتراضية، وrange، وmove

Code التفسير:

  1. قم بتضمين ملف رأس iostream لاستخدام وظائفه.
  2. قم بتضمين ملف رأس القائمة لاستخدام وظائفه.
  3. قم بتضمين مساحة الاسم std في الكود لاستخدام فئاتها دون استدعائها.
  4. استدعاء الدالة الرئيسية (). يجب إضافة منطق البرنامج داخل نص هذه الوظيفة.
  5. أنشئ قائمة فارغة باسم l.
  6. أنشئ قائمة باسم l1 تحتوي على مجموعة مكونة من 3 أعداد صحيحة.
  7. أنشئ قائمة باسم l2 بجميع العناصر الموجودة في القائمة المسماة l1، من البداية إلى النهاية.
  8. أنشئ قائمة باسم l3 باستخدام دلالات النقل. ستحتوي القائمة l3 على نفس محتويات القائمة l2.
  9. اطبع حجم القائمة المسماة l على وحدة التحكم بجانب النص الآخر.
  10. طباعة بعض النص على وحدة التحكم.
  11. قم بإنشاء مكرر اسمه واستخدمه للتكرار على عناصر القائمة المسماة l2.
  12. اطبع عناصر القائمة المسماة l2 على وحدة التحكم.
  13. طباعة بعض النص على وحدة التحكم.
  14. قم بإنشاء مكرر اسمه واستخدمه للتكرار على عناصر القائمة المسماة l3.
  15. اطبع عناصر القائمة المسماة l3 على وحدة التحكم.
  16. يجب أن يقوم البرنامج بإرجاع القيمة عند اكتماله بنجاح.
  17. نهاية نص الدالة main().

خصائص حاوية

فيما يلي قائمة بخصائص الحاوية:

الممتلكات الوصف
تسلسل تقوم حاويات التسلسل بترتيب عناصرها بتسلسل خطي صارم. يتم الوصول إلى العناصر من خلال موقعها في التسلسل.
قائمة مرتبطة بشكل مزدوج يحتوي كل عنصر على معلومات حول كيفية تحديد العناصر السابقة والتالية. وهذا يسمح بوقت ثابت لعمليات الإدخال والحذف.
المُخصص - على علم يتم استخدام كائن المخصص لتعديل حجم التخزين ديناميكيًا.

الإدراج في القائمة

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

مثال 3

#include <algorithm>
#include <iostream>
#include <list>
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };
	my_list.push_front(11);
	my_list.push_back(18);
	auto it = std::find(my_list.begin(), my_list.end(), 10);
	if (it != my_list.end()) {
		my_list.insert(it, 21);
	}
	for (int x : my_list) {
		std::cout << x << '\n';
	}
}

الإخراج:

الناتج بعد إدراج العناصر في قائمة std::list

فيما يلي لقطة شاشة للكود:

C++ الكود الذي يستخدم push_front و push_back و insert على std::list

Code التفسير:

  1. قم بتضمين ملف رأس الخوارزمية لاستخدام وظائفه.
  2. قم بتضمين ملف رأس iostream لاستخدام وظائفه.
  3. قم بتضمين ملف رأس القائمة لاستخدام وظائفه.
  4. استدعاء الدالة الرئيسية (). يجب إضافة منطق البرنامج داخل نص هذه الوظيفة.
  5. أنشئ قائمة باسم my_list تحتوي على مجموعة مكونة من 4 أعداد صحيحة.
  6. أدخل العنصر 11 في مقدمة القائمة المسماة my_list.
  7. أدخل العنصر 18 في نهاية القائمة المسماة my_list.
  8. قم بإنشاء مكرر واستخدمه للعثور على العنصر 10 من القائمة my_list.
  9. استخدم عبارة if لتحديد ما إذا تم العثور على العنصر أعلاه أم لا.
  10. أدخل العنصر 21 قبل العنصر أعلاه إذا وجد.
  11. نهاية نص عبارة if.
  12. استخدم حلقة for لإنشاء متغير حلقة x. سيتم استخدام هذا المتغير للتكرار على عناصر القائمة.
  13. اطبع قيم القائمة على وحدة التحكم.
  14. نهاية جسم الحلقة.
  15. نهاية نص الدالة main().

يمكن إزالة العناصر التي تدخل في قائمة بسهولة تامة.

الحذف من القائمة

من الممكن حذف عناصر من قائمة. تتيح لك الدالة erase() حذف عنصر واحد أو نطاق من العناصر من القائمة.

  • لحذف عنصر واحد، ما عليك سوى تمرير موضع عدد صحيح واحد. سيتم حذف العنصر.
  • لحذف نطاق، عليك تمرير مُكرِّرات البداية والنهاية. دعونا نوضح ذلك.

مثال 4

#include <algorithm>
#include <iostream>
#include <list>
using namespace std;
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };
	cout << "List elements before deletion: ";
	for (int x : my_list) {
		std::cout << x << '\n';
	}
	list<int>::iterator i = my_list.begin();
	my_list.erase(i);
	cout << "\nList elements after deletion: ";
	for (int x : my_list) {
		std::cout << x << '\n';
	}
	return 0;
}

الإخراج:

الناتج بعد حذف عنصر من قائمة std::list

فيما يلي لقطة شاشة للكود:

C++ الكود الذي يستخدم دالة المسح على قائمة std::list

Code التفسير:

  1. قم بتضمين ملف رأس الخوارزمية لاستخدام وظائفه.
  2. قم بتضمين ملف رأس iostream لاستخدام وظائفه.
  3. قم بتضمين ملف رأس القائمة لاستخدام وظائفه.
  4. قم بتضمين مساحة الاسم std في برنامجنا لاستخدام فئاتها دون استدعائها.
  5. استدعاء الدالة الرئيسية (). يجب إضافة منطق البرنامج داخل نص هذه الوظيفة.
  6. أنشئ قائمة باسم my_list تحتوي على مجموعة مكونة من 4 أعداد صحيحة.
  7. طباعة بعض النص على وحدة التحكم.
  8. استخدم حلقة for لإنشاء متغير حلقة x. سيتم استخدام هذا المتغير للتكرار على عناصر القائمة.
  9. اطبع قيم القائمة على وحدة التحكم.
  10. نهاية جسم الحلقة.
  11. قم بإنشاء مكرر i يشير إلى العنصر الأول في القائمة.
  12. استخدم وظيفة المسح () التي يشير إليها المكرر i.
  13. طباعة بعض النص على وحدة التحكم.
  14. استخدم حلقة for لإنشاء متغير حلقة x. سيتم استخدام هذا المتغير للتكرار على عناصر القائمة.
  15. اطبع قيم القائمة على وحدة التحكم. وهذا يأتي بعد الحذف
  16. نهاية جسم الحلقة.
  17. يجب أن يقوم البرنامج بإرجاع قيمة عند اكتماله بنجاح.
  18. نهاية نص الدالة main().

الأسئلة الشائعة

يخزن std::vector العناصر في ذاكرة متجاورة مع وصول عشوائي O(1)، بينما std::list عبارة عن قائمة مرتبطة ثنائياً تتيح إضافة أو حذف العناصر في أي مكان O(1). اختر vector للفهرسة، وlist لإضافة العناصر بشكل متكرر في المنتصف.

لا، لا يحتوي std::list على مُعامل وصول عشوائي، لذا فإن list[2] لا يُترجم. يمكنك الوصول إلى عنصر ما عن طريق التكرار من begin() أو end() عقدة واحدة في كل مرة، وهو ما يستغرق وقتًا خطيًا O(n) للوصول إلى موقع عميق.

std::list هي قائمة مرتبطة ثنائياً تجتاز كلا الاتجاهين وتدعم خاصية الإضافة للخلف (push_back). أما std::forward_list فهي قائمة مرتبطة أحادياً تتحرك للأمام فقط، وتستخدم ذاكرة أقل لكل عقدة، ولا توفر دالة size() أو مُكرِّرات عكسية.

استدعِ الدالة العضوية my_list.sort()، التي تعمل في زمن يقارب N log N وتحافظ على ثبات العناصر المتساوية. لن تعمل خوارزمية std::sort لأنها تتطلب مُكرِّرات وصول عشوائي. مرِّر std::greater إلى sort() لترتيب العناصر تنازليًا.

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

نعم. القائمة std::list ليست مجموعة، لذا فهي تخزن القيم المتكررة بحرية. كل عملية دفع (push_back) أو دفع (push_front) أو إدراج (insert) تضيف عقدة جديدة بغض النظر عن المحتويات الموجودة. استخدم std::set عندما تحتاج إلى رفض العناصر المكررة.

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

تُكمل مساعدات البرمجة المدعومة بالذكاء الاصطناعي تلقائيًا شيفرة حاويات مكتبة STL، وتُشير إلى استخدامات المُكرِّرات الخاطئة، وتُحوِّل std::list إلى std::vector، وتُوضِّح المفاضلات بين التعقيد والنتائج. تُسرِّع هذه المساعدات عملية تعلُّم مكتبة STL، مع العلم أن كل اقتراح لا يزال بحاجة إلى مراجعة.

تلخيص هذه التدوينة بـ: