You are on page 1of 60

‫الفصــــــــــل ‪ .

10‬الخــــــــــوارزميــــــــــات الـشــــــــــاملــــــة‬
‫‪Chapter 10. Generic Algorithms‬‬

‫الـمحتويات‬
‫‪Contents‬‬

‫‪10.1 Overview‬‬ ‫‪ 10٫1‬مراجــعــة عــــــامــــــة‬

‫‪10.2 A First Look at the Algorithms‬‬ ‫‪ 10٫2‬نظرة أولى على الخوارزميات‬

‫‪10.3 Customizing Operations‬‬ ‫‪ 10٫3‬تخصيــــص العملــــيات‬

‫‪10.4 Revisiting Iterators‬‬ ‫‪ 10٫4‬مراجعــــة املــــكــــررات‬

‫‪10.5 Structure of Generic Algorithms‬‬ ‫‪ 10٫5‬هيكلــة الخوارزميات الشاملة‬

‫‪10.6 Container-Specific Algorithms‬‬ ‫‪ 10٫6‬خوارزميات الحاوية الخاصة‬

‫‪Chapter Summary‬‬ ‫ملخــــــص الفصــــــل‬

‫‪Defined Terms‬‬ ‫مصطلحــــــات معرفــــــة‬

‫تعرف حاويات املكتبة مجموعة صغرية من العمليات بشكل مدهش‪ .‬فبدال ً من إضافة عدة دوال لكل حاوية ‪،‬‬
‫ّ‬
‫توفر املكتبة مجموعة خوارزميات ‪ ،‬معظمها مستقلة عن أي نوع حاوية معني‪.‬‬ ‫•‬
‫هذه خوارزميات تعترب شاملة ‪ :‬حيث تعمل على أنواع مختلفة من الحاويات وعنارص من أنواع مختلفة‪.‬‬ ‫•‬

‫يتكون موضوع هذا الفصل من الخوارزميات الشاملة ومراجعة بتفصيل أكرث على املكررات‪.‬‬

‫تعرف الحاويات املتسلسلة عمليات قليلة ‪:‬‬


‫ّ‬
‫قسمها األكرب يتمحور حول إضافة أو إزالة عنارص ‪ ،‬الوصول إلى أول أو آخر عنرص ‪،‬‬ ‫•‬
‫تحديد ما إذا كانت الحاوية فارغة ‪ ،‬واكتساب مكرر ألول أو ما بعد آخر عنرص‪.‬‬ ‫•‬

‫يمكننا تخيل عدة عمليات مفيدة أخرى قد يرغب املرء في القيام بها ‪:‬‬
‫قد نرغب في إيجاد عنرص معني ‪ ،‬أو استبدال أو إزالة قيمة معينة ‪،‬‬ ‫•‬
‫أو إعادة ترتيب عنارص حاوية ‪ ،‬وما إلى ذلك‪.‬‬ ‫•‬

‫وبدال ً من تعريف كل تلك العمليات كأعضاء في كل نوع حاوية ‪،‬‬


‫تعرف املكتبة القياسية مجموعة خوارزميات شاملة ‪:‬‬
‫ّ‬ ‫•‬
‫تُعترب "خوارزميات" ألنها تنفذ خوارزميات كالسيكية شائعة كالفرز والبحث ‪،‬‬ ‫•‬
‫وتُعترب "شاملة" ألنها تعمل على عنارص أنواع مختلفة وعرب أنواع حاويات متعددة ؛‬ ‫•‬
‫أيضا نوع املصفوفة املدمجة ‪،‬‬
‫ليس فقط أنواع مكتبة كاملتجه أو القائمة ‪ ،‬لكن تتضمن ً‬ ‫•‬
‫أيضا‪.‬‬
‫وكما سرنى ‪ ،‬تعمل كذلك على أنواع تسلسالت أخرى ً‬ ‫•‬
‫‪ . 10٫1‬مراجــــــــــعة عــــــــامة‬
‫‪10.1 Overview‬‬

‫يتم تعريف معظم الخوارزميات في عنوان الخوارزمية ‪.algorithm‬‬


‫املعرفة في العنوان العددي ‪.numeric‬‬
‫ّ‬ ‫أيضا مجموعة من الخوارزميات العددية الشاملة‬
‫تعرف املكتبة ً‬‫كذلك ّ‬ ‫•‬
‫بشكل عام ‪ ،‬ال تعمل الخوارزميات مبارشة على حاوية‪.‬‬ ‫•‬
‫بل تعمل بدال ً من ذلك من خالل اجتياز مجموعة عنارص يحددها مكرران‪.‬‬ ‫•‬
‫عاد ًة ‪ ،‬عندما تعرب الخوارزمية النطاق ‪ ،‬فإنها تفعل شيًئ ا مع كل عنرص‪.‬‬ ‫•‬
‫متجها من أرقام صحيحة ‪vector of ints‬‬
‫ً‬ ‫على سبيل املثال ‪ ،‬افرتض أن لدينا‬ ‫•‬
‫ونريد معرفة ما إذا كان هذا املتجه يحمل قيمة معينة‪.‬‬ ‫•‬
‫فالطريقة األسهل لإلجابة على هذا السؤال هي استدعاء خوارزمية البحث ‪ find‬في املكتبة ‪:‬‬ ‫•‬

‫‪int val = 42; // value we'll look for‬‬


‫‪// result denote element we want if it's in vec, or vec.cend if not‬‬
‫;)‪auto result = find(vec.cbegin(), vec.cend(), val‬‬
‫‪// report the result‬‬
‫? )(‪cout << "The value " << val << (result == vec.cend‬‬
‫;‪" is not present" : " is present") << endl‬‬

‫أول وثاني وسيطات ‪ find‬هما مكرران يدالن على نطاق عنارص ‪ ،‬الثالثة عبارة قيمة‪.‬‬ ‫•‬
‫يقارن ‪ find‬كل عنرص في النطاق املحدد بالقيمة املحددة‪.‬‬ ‫•‬
‫يقوم بإعادة مكرر ألول عنرص يساوي تلك القيمة‪.‬‬ ‫•‬
‫إذا لم يكن هناك تطابق ‪ ،‬فسيعيد ‪ find‬مكرره الثاني ليشري إلى الفشل‪.‬‬ ‫•‬
‫وبالتالي ‪ ،‬يمكننا تحديد ما إذا كان قد تم اإليجاد العنرص من خالل مقارنة القيمة املعادة باملكرر الثاني‪.‬‬ ‫•‬
‫نقوم بإجراء هذا االختبار في جملة املخرجات ‪،‬‬ ‫•‬
‫واليت تستخدم العامل الرشطي إلظهار ما إذا تم إيجاد القيمة‪.‬‬ ‫•‬
‫ونظرًا ألن ‪ find‬تعمل بمنهجية املكررات ‪ ،‬فيمكننا استخدام نفس الدالة ‪ find‬للبحث عن قيم أي نوع حاوية‪.‬‬
‫• فعلى سبيل املثال ‪ ،‬يمكننا استخدام ‪ find‬للبحث عن قيمة في قائمة سالسل ‪: list of strings‬‬

‫;"‪string val = "a value‬‬ ‫‪// value we'll look for‬‬


‫‪// this call to find looks through string elements in a list‬‬
‫;)‪auto result = find(1st.cbegin(), 1st.cend(), val‬‬

‫بنفس الكيفية ‪ ،‬وألن املؤرشات تعمل كاملكررات في املصفوفات املدمجة ‪ ،‬يمكننا استخدام ‪ find‬للبحث في مصفوفة‪:‬‬

‫;}‪int ia[] = {27, 210, 12, 47, 109, 83‬‬


‫;‪int val = 83‬‬
‫;)‪int* result = find(begin(ia), end(ia), val‬‬
‫هنا نستخدم دوال مكتبة بداية_ ونهاية_ لتمرير مؤرش ألول عنرص وما‪-‬بعد اﻷخري في ‪.ia‬‬ ‫•‬
‫أيضا البحث في نطاق فرعي من تسلسل بتمرير مكررات (أو مؤرشات) ﻷول وما بعد آخر عنرص من‬
‫يمكننا ً‬ ‫•‬
‫ذلك النطاق الفرعي‪.‬‬
‫فعلى سبيل املثال ‪ ،‬يبحث هذا االستدعاء عن تطابق في العنارص ]‪ ia[1‬و ]‪ ia[2‬و ]‪:ia[3‬‬ ‫•‬

‫]‪// search elements begining from ia[1] up to but not including ia[4‬‬
‫;)‪auto result = find(ia + 1, ia + 4, val‬‬

‫‪How the Algorithms Work‬‬ ‫كيف تعمل الخوارزميات‬

‫ملعرفة كيف يمكن استخدام الخوارزميات في أنواع حاويات مختلفة ‪ ،‬دعنا نلقي نظرة عن كثب على ‪.find‬‬
‫تتمثل مهمة ‪ find‬في إيجاد عنرص معني في تسلسل عنارص غري مفرزة‪.‬‬ ‫•‬
‫من الناحية املفاهيمية ‪ ،‬يمكننا رسد خطوات ‪ find‬اليت يجب أن يتخذها ‪:‬‬ ‫•‬
‫‪ .1‬ينفذ إلى أول عنرص في التسلسل‪.‬‬
‫‪ .2‬فيقارن ذلك العنرص بالقيمة اليت نريدها‪.‬‬
‫تعرف ذلك العنرص‪.‬‬
‫‪ .3‬إذا تطابق العنرص مع ما نريده ‪ ،‬يعيد ‪ find‬قيمة ّ‬
‫‪ .4‬وإال ‪ ،‬فيتقدم ‪ find‬نحو العنرص التالي ويكرر الخطوتني الثانية والثالثة‪.‬‬
‫‪ .5‬يجب أن يتوقف ‪ find‬عند وصوله إلى نهاية التسلسل‪.‬‬
‫‪ .6‬إذا صادف ‪ find‬نهاية التسلسل ‪ ،‬فسيحتاج إلعادة قيمة تشري إلى أن العنرص لم يتم العثور عليه‪.‬‬
‫‪ -‬يجب أن يكون لهذه القيمة والقيمة املعادة من الخطوة الثالثة أنواع متوافقة‪.‬‬

‫ال تعتمد أي من هذه العمليات على نوع الحاوية اليت تحمل العنارص‪.‬‬
‫فطاملا أنه يوجد مكرر يمكن استخدامه للوصول إلى العنارص ‪،‬‬ ‫•‬
‫فال يعتمد ‪ find‬بأي شكل على نوع الحاوية (أو حىت ما إذا كانت العنارص مخزنة في حاوية)‪.‬‬ ‫•‬

‫املكررات تجعل حاوية الخوارزميات مستقلة ‪... ،‬‬


‫‪Iterators Make the Algorithms Container Independent, ...‬‬

‫يمكن معالجة كل الخطوات باستثناء الخطوة الثانية في دالة ‪ find‬عن طريق عمليات املكرر ‪:‬‬
‫حيث يتيح عامل إلغاء مرجع املكرر الوصول إلى قيمة العنرص ؛‬ ‫•‬
‫إذا تم إيجاد عنرص مطابق ‪ ،‬فيمكن لـ ‪ find‬أن يعيد مكرراً لهذا العنرص ؛‬ ‫•‬
‫ويتحرك عامل تزايد املكرر نحو العنرص التالي ؛‬ ‫•‬
‫سيشري مكرر "ما‪-‬بعد‪-‬النهاية" مىت صادف ‪ find‬نهاية تسلسله املحدد ؛‬ ‫•‬
‫ويتمكن ‪ find‬من إعادة مكرر ما‪-‬بعد النهاية ليشري إلى أنه لم يتم إيجاد القيمة املحددة‪.‬‬ ‫•‬

‫‪ ...‬لكن الخوارزميات تعتمد فعالً على عمليات نوع العنرص‬


‫‪...But Algorithms Do Depend on Element-Type Operations‬‬
‫فعلى الرغم من أن املكررات تجعل حاوية الخوارزميات مستقلة ‪،‬‬
‫إال أن معظم الخوارزميات تستخدم عملية واحدة (أو أكرث) على نوع العنرص‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬تستخدم الخطوة ‪ 2‬عامل نوع العنرص التساوي (==) ملقارنة كل عنرص بالقيمة املحددة‪.‬‬ ‫•‬
‫تتطلب خوارزميات أخرى أن يكون لنوع العنرص العامل > ‪ .‬مع ذلك ‪ ،‬كما سرنى ‪،‬‬
‫توفر لنا معظم الخوارزميات طريقة لزتويدنا بعملياتنا الخاصة الستخدامها بدال ً من العامل االفرتايض‪.‬‬ ‫•‬

‫تمارين القسم ‪10.1‬‬

‫التمرين ‪:10.1‬‬
‫زوجا من املكررات وقيمة مثل ‪.find‬‬
‫ً‬ ‫عد_ ‪ count‬تأخذ‬
‫يعرف عنوان الخوارزمية دالة تسمى ّ‬
‫‪ّ -‬‬
‫‪ -‬يقوم ‪ count‬بإعادة عدد مرات ظهور هذه القيمة‪.‬‬
‫‪ -‬قم بقراءة تسلسل أرقام صحيحة في متجه‬
‫‪ -‬واطبع عدد العنارص اليت لها قيمة محددة‪.‬‬

‫التمرين ‪:10.2‬‬
‫كرر الربنامج السابق ‪ ،‬لكن اقرأ القيم في قائمة سالسل ‪.list of strings‬‬

‫أبدا‬
‫الخوارزميات ال تنفذ عمليات حاوية ً‬ ‫مفهوم أسايس‪:‬‬

‫‪Key Concept:‬‬ ‫‪Algorithms Never Execute Container Operations‬‬

‫ال تنفذ الخوارزميات الشاملة عمليات حاوية بنفسها‪ .‬ﻻ تحدث العمليات إﻻ بمنهجية املكرر وعملياته‪.‬‬ ‫•‬
‫تعمل الخوارزميات بمنهجية املكررات وليس بعمليات الحاوية ؛‬ ‫•‬
‫حقيقة ذلك قد يكون له تأثري مدهش لكنه أسايس ومفصلي ‪:‬‬ ‫•‬
‫ﻻ تغري الخوارزميات أب ًدا حجم الحاوية األساسية‪.‬‬ ‫•‬
‫قد تغري الخوارزميات قيم العنارص املخزنة في الحاوية ‪ ،‬وقد تنقل عنارص داخل الحاوية‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فلن تضيف أو تزيل عنارص مبارشة‪.‬‬ ‫•‬

‫كما سرنى في الفقرة ‪ ، 10.4.1‬هناك فئة مكرر خاصة ‪ ،‬وهي امل ُ ِ‬


‫دخالت ‪،‬‬ ‫•‬
‫تقوم بأكرث من اجتياز التسلسل الذي ترتبط به‪.‬‬ ‫•‬
‫عندما نقوم بتعيني على تلك املكررات ‪ ،‬فإنها تنفذ عمليات إدراج في الحاوية األساسية‪.‬‬ ‫•‬
‫وعندما تعمل الخوارزمية على إحدى تلك املكررات ‪ ،‬قد يكون للمكرر تأثري إضافة عنارص إلى الحاوية‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فإن الخوارزمية نفسها لن تقوم بذلك أب ًدا‪.‬‬ ‫•‬
‫‪ . 10٫2‬نظــــــــــرة أولــــــى عــــــــلى الخــــــــــوارزميــــــــــات‬
‫‪10.2 A First Look at the Algorithms‬‬

‫توفر املكتبة أكرث من ‪ 100‬خوارزمية‪ .‬لحسن الحظ ‪ ،‬هي مشابهة للحاويات ‪ ،‬حيث تتمتع بنية متسقة‪.‬‬
‫ففهم هذه البنية يجعل تعلم واستخدام الخوارزميات أسهل من حفظ ما يزيد على ‪ 100‬منها‪.‬‬ ‫•‬
‫في هذا الفصل ‪ ،‬سوف نوضح كيفية استخدام الخوارزميات ‪ ،‬وسنوصف املبادئ املوحدة اليت تمزيها‪.‬‬ ‫•‬
‫يرسد امللحق أ جميع الخوارزميات املصنفة حسب كيفية عملها‪.‬‬ ‫•‬

‫مع استثناءات قليلة فقط ‪ ،‬تعمل الخوارزميات عرب نطاق عنارص‪.‬‬


‫سنشري إلى هذا النطاق باسم "نطاق املدخالت ‪."input range‬‬ ‫•‬
‫دائما أول معلمتني ليشريا إلى ذلك النطاق‪.‬‬
‫ً‬ ‫تستخدم الخوارزميات اليت تأخذ نطاق مدخالت‬ ‫•‬
‫تلك املعلمتان عبارة عن مكرران يدالن على أول عنرص وما بعد العنرص األخري الذي تعالجه الخوارزمية‪.‬‬ ‫•‬

‫وعلى الرغم من أن معظم الخوارزميات متشابهة كونها تعمل عرب نطاق مدخالت ‪،‬‬
‫إال أنها تختلف في كيفية استخدام العنارص في ذلك النطاق‪.‬‬ ‫•‬
‫الطريقة األساسية لفهم الخوارزميات هي معرفة ما إذا كانت تقرأ عنارص أو تكتبها أو تُعيد ترتيبها‪.‬‬ ‫•‬

‫‪10.2.1. Read-Only Algorithms‬‬ ‫‪ .10.2.1‬خوارزميات قراءة‪-‬فقط‬

‫تقوم عدة خوارزميات بقراءة العنارص في نطاق مدخالتها ‪ ،‬لكنها ال تكتب عليها مطل ًقا‪.‬‬
‫عد_ ‪ count‬املستخدمة في التمرين السابق‪.‬‬
‫الدالة إيجاد_ ‪ find‬إحدى تلك الخوارزميات ‪ ،‬ومثلها دالة ّ‬ ‫•‬
‫املعرفة في العنوان العددي ‪.numeric‬‬
‫ّ‬ ‫خوارزمية أخرى للقراءة فقط هي تجميع_ ‪، accumulate‬‬ ‫•‬
‫تأخذ تجميع_ ثالث وسيطات‪.‬‬ ‫•‬
‫تحدد األوليان نطاق العنارص املراد جمعها‪ .‬والثالثة عبارة عن قيمة ابتدائية للمجموع‪.‬‬ ‫•‬
‫فبافرتاض أن ‪ vec‬عبارة عن سلسلة من األعداد الصحيحة ‪ ،‬فإن التالي ‪:‬‬ ‫•‬

‫‪// sum elements in vec begining summation with value 0‬‬


‫;)‪int sum = accumulate(vec.cbegin(), vec.cend(), 0‬‬

‫يضبط ‪ sum‬على مجموع العنارص في ‪ ، vec‬باستخدام صفر كقيمة ابتدائية للمجموع‪.‬‬

‫ملحوظة‬

‫نوع وسيطة تجميع_ الثالثة يحدد أي عامل جمع يستخدم ؛ وهو النوع الذي يقوم تجميع_ بإعادته‪.‬‬

‫‪Algorithms and Element Types‬‬ ‫الخوارزميات وأنواع العنارص‬

‫حقيقة أن تجميع_ يستخدم وسيطته الثالثة كقيمة ابتدائية للمجموع لها تأثري مهم ‪:‬‬
‫يجب أن يكون من املمكن جمع نوع العنرص مع نوع املجموع‪.‬‬ ‫•‬
‫بمعىن أن العنارص في التسلسل يجب أن تتطابق أو تكون قابلة للتحويل إلى نوع الوسيطة الثالثة‪.‬‬ ‫•‬
‫في هذا املثال ‪ ،‬قد تكون العنارص في ‪ vec‬عدداً صحيحاً ‪ ،‬أو مزدوجاً أو طويالً_أطول ‪، long long‬‬ ‫•‬
‫أو أي نوع آخر يمكن جمعه مع عدد صحيح‪.‬‬ ‫•‬
‫مثال آخر ‪ ،‬ألن السلسلة تملك العامل ‪، +‬‬ ‫•‬
‫فيمكننا ربط عنارص متجه من سالسل عن طريق استدعاء تجميع_ ‪:‬‬ ‫•‬

‫;))""(‪string sum = accumulate(v.cbegin(), v.cend(), string‬‬

‫يربط هذا االستدعاء كل عنرص في ‪ v‬بسلسلة تهئي على سلسلة فارغة‪.‬‬ ‫•‬
‫الحظ أننا ننئش سلسلة رصاحة كمعامل ثالث‪.‬‬ ‫•‬
‫ذلك ألن تمرير السلسلة الفارغة كحرفية سلسلة خطأ في وقت الرتجمة ‪:‬‬ ‫•‬

‫*‪// error: no + on const char‬‬


‫;)"" ‪string sum = accumulate(v.cbegin(), v.cend(),‬‬

‫فإذا مررنا حرفية سلسلة ‪ ،‬سيكون نوع الكائن املستخدم لحفظ املجموع هو مؤرش لحرف ثابت*‪.‬‬ ‫•‬
‫وبما أن هذا النوع يحدد أي عامل جمع سنستخدمه‪.‬‬ ‫•‬
‫ونظر ًا لعدم وجود عامل ‪ +‬لنوع مؤرش الحرف الثابت ‪ ،‬فلن يتم ترجمة هذا االستدعاء‪.‬‬ ‫•‬

‫أفضل املمارسات‬

‫من األفضل عاد ًة استخدام ‪ cbegin‬و ‪ cend‬مع خوارزميات تقرأ عنارص وال تكتبها‪.‬‬ ‫•‬
‫لكن ‪ ،‬إن خططت الستخدام مكرر معاد بخوارزمية تغرّي قيمة عنرص ‪ ،‬ستحتاج لتمرير ‪ begin‬و ‪. end‬‬ ‫•‬

‫‪Algorithms That Operate on Two Sequences‬‬ ‫خوارزميات تعمل على تسلسلني‬

‫خوارزمية أخرى للقراءة فقط هي تساوي_ ‪ ، equal‬واليت تتيح لنا تحديد ما إذا تسلسالن يحمالن نفس القيم‪.‬‬
‫تقارن تساوي_ كل عنرص من أول تسلسل بعنرصه املقابل في الثاني‪.‬‬ ‫•‬
‫وتُعيد قيمة صحيحة ‪ true‬إن كانت العنارص املتقابلة متساوية ‪ ،‬وإال تعيد قيمة خطأ ‪.false‬‬ ‫•‬
‫تأخذ الخوارزمية تساوي_ ثالثة مكررات‪ :‬أولهما (كالعادة) يشريان لنطاق العنارص في أول تسلسل ؛‬ ‫•‬
‫بينما يشري الثالث إلى أول عنرص في التسلسل الثاني ‪:‬‬ ‫•‬

‫‪// roster2 should have at least as many elements as roster1‬‬


‫;))(‪equal(roster1.cbegin(), roster1.cend(), roster2.cbegin‬‬

‫وألن تساوي_ تعمل بنهج املكررات ‪ ،‬فيمكننا استدعاءها ملقارنة عنارص في حاويات مختلفة األنواع ‪.‬‬ ‫•‬
‫أيضا أن تكون أنواع العنارص واحدة طاملا نستخدم == ملقارنة تلك األنواع‪.‬‬
‫عالوة على ذلك ‪ ،‬ال حاجة ً‬ ‫•‬
‫متجها من سلسلة وتكون ‪ roster2‬قائمة من مؤرش لحرف ثابت ‪.‬‬
‫ً‬ ‫• فمثالً ‪ ،‬يمكن أن تكون ‪roster1‬‬
‫مهما للغاية‪:‬‬
‫افرتاضا ً‬
‫ً‬ ‫مع ذلك ‪ ،‬تضع تساوي_ تضع‬
‫فهي تفرتض أن حجم التسلسل الثاني على األقل بمقدار حجم أول تسلسل‪.‬‬ ‫•‬
‫فمن املحتمل أن تبحث هذه الخوارزمية في كامل عنارص أول تسلسل‪.‬‬ ‫•‬
‫حيث تفرتض أن هناك عنرصًا مطاب ًقا لكل عنرص منها في التسلسل الثاني املقابل‪.‬‬ ‫•‬

‫تحذير‬

‫مكررا وحي ًدا تدل على تسلسل ثانٍ أن حجم الثاني على األقل سيكون بحجم األول‪.‬‬
‫ً‬ ‫تفرتض خوارزميات تأخذ‬

‫تمارين القسم ‪10.2.1‬‬

‫التمرين ‪:10.3‬‬
‫استخدم "تجميع_ ‪ "accumulate‬لجمع العنارص في متجه عدد صحيح <‪.vector<int‬‬

‫التمرين ‪:10.4‬‬
‫بافرتاض أن ‪ v‬متجه <‪ ، >double‬فما الخطأ ‪ ،‬إن ُوجد ‪ ،‬في استدعاء تجميع_ كالتالي ‪:‬‬
‫?)‪accumulate(v.cbegin(), v.cend(), 0‬‬

‫التمرين ‪:10.5‬‬
‫‪ -‬في استدعاء تساوي_ على قوائم ‪، rosters‬‬
‫‪ -‬ماذا سيحدث إذا حملت كلتا القائمتني سالسل من النمط ‪ ، C‬بدال ً من سالسل املكتبة؟‬

‫‪ .10.2.2‬خوارزميات تكتب على عنارص حاوية‬


‫‪10.2.2. Algorithms That Write Container Elements‬‬

‫تقوم بعض الخوارزميات بتعيني قيم جديدة على عنارص في تسلسل‪.‬‬


‫وعندما نستخدم خوارزمية تعني على عنارص ‪ ،‬يجب أن نتأكد ‪،‬‬ ‫•‬
‫أن حجم التسلسل الذي تكتب عليه الخوارزمية على األقل بحجم عدد العنارص املطلوب كتابتها‪.‬‬ ‫•‬
‫تذكر‪ :‬ال تؤدي الخوارزميات عمليات حاوية ‪ ،‬لذلك ليس لديها طريقة ذاتية لتغيري حجم حاوية‪.‬‬ ‫•‬
‫تكتب بعض الخوارزميات على عنارص في نطاق املدخالت نفسه‪.‬‬ ‫•‬
‫هذه الخوارزميات ليست خطرية بطبيعتها ألنها تكتب فقط على نفس عدد العنارص في النطاق املحدد‪.‬‬ ‫•‬
‫كمثال ‪ ،‬تأخذ الخوارزمية تعبئة_ ‪ fill‬زوج مكررات تشري إلى نطاق ووسيطة ثالثة تمثل قيمة‪.‬‬ ‫•‬
‫تعني تعبئة_ القيمة املعطاة على كل عنرص في نطاق تسلسل املدخالت ‪:‬‬ ‫•‬

‫;)‪fill(vec.begin(), vec.end(), 0‬‬ ‫‪// reset each element to 0‬‬


‫‪// set a subsequence of the container to 10‬‬
‫;)‪fill(vec.begin(), vec.begin() + vec.size()/2, 10‬‬

‫وألن تعبئة_ تكتب على نطاق مدخالت محدد ‪،‬‬ ‫•‬


‫فطاملا مررنا نطاق مدخالت صالح ‪ ،‬ستكون عمليات الكتابة آمنة‪.‬‬ ‫•‬

‫‪Key Concept:‬‬ ‫‪Iterator Arguments‬‬ ‫مفهوم رئييس‪ :‬وسيطات املكرر‬

‫هناك خوارزميات تقرأ عنارص من تسلسلني‪.‬‬ ‫•‬


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

‫عالوة على ذلك ‪ ،‬لن يتطلب التطابق التام في أنواع العنارص في تسلسلني‪.‬‬ ‫•‬
‫إنما املطلوب هو أن نكون قادرين على مقارنة عنارص من كال التسلسلني‪.‬‬ ‫•‬
‫فمثالً ‪ ،‬في خوارزمية تساوي_ ‪ ،‬ال حاجة لتماثل أنواع العنارص ‪،‬‬ ‫•‬
‫لكن يجب أن نكون قادرين فعالً على استخدام == ملقارنة عنارص من كال التسلسلني‪.‬‬ ‫•‬

‫تختلف الخوارزميات اليت تعمل على تسلسلني حول كيفية تمرير التسلسل الثاني‪.‬‬ ‫•‬
‫تأخذ بعضها ‪ -‬مثل تساوي_ ‪ -‬ثالثة مكررات ‪:‬‬ ‫•‬
‫تشري األوليان إلى نطاق عنارص أول تسلسل ‪ ،‬ويشري الثالث إلى أول عنرص في التسلسل الثاني‪.‬‬ ‫•‬
‫تأخذ خوارزميات أخرى أربعة مكررات‪:‬‬ ‫•‬
‫تشري األوليان إلى نطاق عنارص أول تسلسل ‪ ،‬وتشري األخريان إلى نطاق عنارص التسلسل الثاني‪.‬‬ ‫•‬

‫تفرتض خوارزميات تشري بمكرر واحد إلى التسلسل الثاني أن يكون حجمه على األقل بحجم األول‪.‬‬ ‫•‬
‫األمر مرتوك لنا لنتأكد أن الخوارزمية لن تحاول الوصول إلى عنرص غري موجود في التسلسل الثاني‪.‬‬ ‫•‬
‫مثالً ‪ ،‬يحتمل أن تقارن خوارزمية تساوي_ كل عنرص من تسلسله األول مع عنرص في الثاني‪.‬‬ ‫•‬
‫فإذا كان التسلسل الثاني مجموعة فرعية من األول ‪ ،‬فهذا يعين أن لدى برنامجنا خطأ فادحاً ‪-‬‬ ‫•‬
‫حيث سيحاول تساوي_ الوصول إلى عنارص تتجاوز نهاية التسلسل الثاني‪.‬‬ ‫•‬

‫‪Algorithms Do Not Check Write Operations‬‬ ‫ال تفحص الخوارزميات عمليات الكتابة‬

‫مكررا يشري إلى وجهة منفصلة‪.‬‬


‫ً‬ ‫تأخذ بعض الخوارزميات‬
‫بدءا من العنرص املشار إليه بمكرر الوجهة‪.‬‬
‫تقوم تلك الخوارزميات بتعيني قيم جديدة على عنارص التسلسل ً‬ ‫•‬
‫مكررا واح ًدا وعدداً وقيمة‪.‬‬
‫ً‬ ‫فمثالً ‪ ،‬تأخذ الدالة تعبئة_ع ‪fill_n‬‬ ‫•‬
‫بدءا من العنرص املشار إليه باملكرر‪.‬‬
‫حيث تقوم بتعيني القيمة املحددة على عدد محدد من العنارص ً‬ ‫•‬
‫قد نستخدم ‪ fill_n‬لتعيني قيمة جديدة على عنارص في متجه ‪:‬‬ ‫•‬

‫;‪vector<int> vec‬‬ ‫‪// empty vector‬‬


‫‪// use vec giving it various values‬‬
‫‪fill_n(vec.begin(), vec.size(), 0); // reset all elements of vec to 0‬‬

‫تفرتض الدالة ‪ fill_n‬أنه من اآلمن كتابة العدد املحدد من العنارص‪.‬‬ ‫•‬


‫بمعىن أنه ‪ ،‬من أجل استدعاء النموذج ‪:‬‬ ‫•‬
‫)‪fill_n(dest, n, val‬‬

‫ستفرتض ‪ fill_n‬أن ‪ dest‬تشري إلى عنرص ‪،‬‬ ‫•‬


‫بدءا من ‪. dest‬‬
‫وأن هناك عدد ‪ n‬من العنارص على األقل في التسلسل ً‬ ‫•‬
‫من الخطأ الشائع بكرثة عند املبتدئني استدعاء ‪( fill_n‬أو خوارزميات مشابهة تكتب على عنارص) على‬ ‫•‬
‫حاوية ال تحتوي على عنارص ‪:‬‬

‫;‪vector<int> vec‬‬ ‫‪// empty vector‬‬


‫‪// disaster: attempts to write to ten (nonexistent) elements in vec‬‬
‫;)‪fill_n(vec.begin(), 10, 0‬‬

‫استدعاء ‪ fill_n‬هذا سيكون كارثة‪.‬‬ ‫•‬


‫لقد حددنا بأنه يجب الكتابة على عرشة عنارص ‪ ،‬لكن ال وجود لها ‪ -‬حيث أن ‪ vec‬فارغة‪.‬‬ ‫•‬
‫معرف‪.‬‬
‫ستكون النتيجة سلوكاً غري ّ‬ ‫•‬

‫تحذير‬

‫تفرتض خوارزميات تكتب على مكرر وجهة أن حجم الوجهة كبري بما يكفي الحتواء عدد العنارص اليت ستكتب‪.‬‬

‫‪Introducing back_inserter‬‬ ‫تقديم ُمدرج_خلف‬

‫هناك طريقة واحدة للتأكد من أن خوارزمية ما لديها عنارص كافية لتحمل املخرجات ‪:‬‬
‫استخدام مكرر إدراج ‪.insert iterator‬‬ ‫•‬
‫مكرر اإلدراج عبارة عن مكرر يضيف عنارص إلى حاوية‪.‬‬ ‫•‬
‫وعادة ‪ ،‬عندما نقوم بتعيني على عنرص حاوية من خالل مكرر ‪ ،‬فإننا نعني على عنرص يشري إليه املكرر‪.‬‬ ‫•‬
‫لكن عندما نقوم بتعيني من خالل مكرر إدراج ‪،‬‬ ‫•‬
‫فإنه يتم إضافة عنرص جديد إلى الحاوية مساوي لقيمة الجهة اليمىن‪.‬‬ ‫•‬
‫سيكون لدينا املزيد عن مكررات اإلدراج في فقرة ‪. 10.4.1‬‬
‫بكل حال ‪ ،‬من أجل توضيح كيفية استخدام خوارزميات تكتب على حاوية ‪،‬‬ ‫•‬
‫معرفة في عنوان املكرر ‪. iterator‬‬
‫الـمد ِرج_الخلفي ‪ ، back_inserter‬وهي دالة ّ‬
‫سنستخدم ُ‬ ‫•‬
‫مرتبطا بتلك الحاوية‪.‬‬
‫ً‬ ‫مرجعا لحاوية ويعيد مكرر إدراج‬
‫ً‬ ‫تأخذ دالة ُمدرج_خلف‬ ‫•‬
‫وعندما نقوم بتعيني من خالل هذا املكرر ‪،‬‬ ‫•‬
‫فإن التعيني سيستدعي دفع_للخلف ليضيف عنرصاً بالقيمة املحددة إلى الحاوية ‪:‬‬ ‫•‬

‫‪vector<int> vec; // empty vector‬‬


‫‪auto it = back_inserter(vec); // assign through it adds elements to vec‬‬
‫;‪*it = 42‬‬ ‫‪// vec now has one element with value 42‬‬

‫وكثريًا ما نستخدم ُمدرج_خلف إلنشاء مكرر الستخدامه كوجهة للخوارزمية‪ .‬فمثال ‪:‬‬ ‫•‬

‫‪vector<int> vec; // empty vector‬‬


‫‪// ok: back_inserter creates insert iterator that adds elements to vec‬‬
‫;)‪fill_n(back_inserter(vec), 10, 0‬‬ ‫‪// appends ten elements to vec‬‬

‫على كل تكرار ‪ ،‬تعني ‪ fill_n‬على عنرص في التسلسل املحدد‪.‬‬ ‫•‬


‫بمدرج_خلف ‪، back_inserter‬‬
‫مكررا معاداً ُ‬
‫ً‬ ‫ونظرًا ألننا مررنا‬ ‫•‬
‫فإن كل تعيني سيستدعي دفع_للخلف على ‪.vec‬‬ ‫•‬
‫نتيجة لذلك ‪ ،‬يضيف استدعاء ‪ fill_n‬عرشة عنارص في نهاية ‪ ، vec‬لكل منها القيمة ‪. 0‬‬ ‫•‬

‫‪Copy Algorithms‬‬ ‫الخوارزمية نسخ‬

‫تعد الخوارزمية نسخ مثااًل آخر على خوارزمية تكتب على عنارص تسلسل مخرجات يشار إليه بواسطة مكرر وجهة‪.‬‬
‫• تأخذ هذه الخوارزمية ثالثة مكررات‪ .‬يشري األوليان لنطاق املدخالت ؛ والثالث إلى بداية تسلسل الوجهة‪.‬‬
‫تنسخ هذه الخوارزمية عنارص من نطاق مدخالتها إلى عنارص في الوجهة‪.‬‬ ‫•‬
‫من األسايس أن يكون حجم الوجهة اليت يتم تمريرها للخوارزمية كبرياً على األقل بحجم نطاق املدخالت‪.‬‬ ‫•‬
‫كمثال ‪ ،‬يمكننا استخدام ‪ copy‬لنسخ مصفوفة مدمجة إلى أخرى‪:‬‬

‫;}‪int a1[] = {0,1,2,3,4,5,6,7,8,9‬‬


‫;])‪int a2[sizeof(a1)/sizeof(*a1‬‬ ‫‪// a2 has the same size as a1‬‬
‫‪// ret points just past last element copied into a2‬‬
‫;)‪auto ret = copy(begin(a1), end(a1), a2‬‬ ‫‪// copy a1 into a2‬‬

‫هنا نعرف مصفوفة باسم ‪ a2‬ونستخدم ‪ sizeof‬لضمان أن تملك ‪ a2‬عنارص بعدد عنارص ‪. a1‬‬ ‫•‬
‫ثم نستدعي ‪ copy‬لنسخ ‪ a1‬إلى ‪.a2‬‬ ‫•‬
‫بعد استدعاء ‪ ، copy‬سيكون للعنارص في كال املصفوفتني القيم نفسها‪.‬‬ ‫•‬
‫القيمة املعادة من ‪ copy‬هي القيمة (املزتايدة) عن مكرر الوجهة‪.‬‬ ‫•‬
‫بمعىن أن ‪ ، ret‬سيشري ملا بعد آخر عنرص تم نسخه إلى ‪.a2‬‬ ‫•‬

‫توفر عدة خوارزميات ما يسمى بإصدارات "‪."copying‬‬


‫تحوسب هذه الخوارزميات قيم عنارص جديدة ‪،‬‬ ‫•‬
‫لكن بدال ً من إعادتها إلى تسلسل مدخالتها ‪ ،‬تنئش الخوارزميات تسلساًل جدي ًدا الحتواء النتائج‪.‬‬ ‫•‬
‫فمثالً ‪ ،‬تقوم خوارزمية استبدال_ ‪ replace‬بقراءة تسلسل وتستبدل كل مثيل لقيمة معينة بقيمة أخرى‪.‬‬ ‫•‬
‫تأخذ هذه الخوارزمية أربعة معلمات‪ :‬مكرران يشريان لنطاق املدخالت ‪ ،‬وقيمتان‪.‬‬ ‫•‬
‫يستبدل كل عنرص يساوي أول قيمة بالقيمة الثانية ‪:‬‬ ‫•‬

‫‪// replace any element with value 0 with 42‬‬


‫;)‪replace(ilst.begin(), ilst.end(), 0, 42‬‬

‫يستبدل هذا االستدعاء كل مثيالت القيمة ‪ 0‬بالقيمة ‪.42‬‬ ‫•‬


‫أما إذا أردنا ترك التسلسل األصلي دون تغيري ‪ ،‬فيمكننا استدعاء نسخ_استبدال_ ‪.replace_copy‬‬ ‫•‬
‫تأخذ هذه الخوارزمية وسيطة عبارة عن مكرر ثالث يشري إلى وجهة يتم فيها كتابة التسلسل املعدل ‪:‬‬ ‫•‬
‫‪// use back_inserter to grow destination as needed‬‬
‫;)‪replace_copy(ilst.cbegin(), ilst.cend(),back_inserter(ivec), 0, 42‬‬

‫بعد هذا االستدعاء ‪ ،‬لم تتغري ‪ ، ilst‬وامتلكت ‪ ivec‬نسخة من ‪ ilst‬؛‬ ‫•‬


‫باستثناء أن كل عنرص في ‪ ilst‬بالقيمة ‪ 0‬يملك القيمة ‪ 42‬في ‪.ivec‬‬ ‫•‬

‫تمارين القسم ‪10.2.2‬‬

‫التمرين ‪:10.6‬‬
‫برنامجا لتعيني تسلسل قيم رقم صحيح على ‪.0‬‬
‫ً‬ ‫باستخدام ‪ ، fill_n‬اكتب‬

‫التمرين ‪:10.7‬‬
‫حدد ما إذا كانت هناك أية أخطاء في الربامج التالية ‪ ،‬وإذا كان األمر كذلك ‪ ،‬فقم بتصحيح الخطأ (األخطاء)‪:‬‬
‫)‪(a‬‬
‫;‪vector<int> vec; list<int> lst; int i‬‬
‫)‪while (cin >> i‬‬
‫;)‪     lst.push_back(i‬‬
‫;))(‪copy(lst.cbegin(), lst.cend(), vec.begin‬‬
‫)‪(b‬‬
‫;‪vector<int> vec‬‬
‫)‪vec.reserve(10); // reserve is covered in § 9.4 (p. 356‬‬
‫;)‪fill_n(vec.begin(), 10, 0‬‬

‫التمرين ‪:10.8‬‬
‫قلنا أن الخوارزميات ال تغري حجم الحاويات اليت تعمل عليها‪ .‬ملاذا ال يؤدي استخدام ُمدرج_خلف إلى إبطال هذا‬
‫اﻻدعاء ؟‬

‫‪ .10.2.3‬خوارزميات تُعيد ترتيب عنارص حاوية‬


‫‪10.2.3. Algorithms That Reorder Container Elements‬‬

‫تُعيد بعض الخوارزميات ترتيب العنارص داخل الحاوية‪.‬‬


‫من األمثلة الواضحة على مثل هذه الخوارزميات فرز_ ‪.sort‬‬ ‫•‬
‫يرتب استدعاء فرز_ عنارص في نطاق املدخالت في ترتيب مصنف باستخدام عامل نوع العنرص >‪.‬‬ ‫•‬
‫كمثال ‪ ،‬افرتض أننا نريد تحليل الكلمات املستخدمة في مجموعة قصص أطفال‪.‬‬ ‫•‬
‫نصا من عدة قصص‪.‬‬ ‫متجها يحمل ً‬
‫ً‬ ‫سنفرتض أن لدينا‬ ‫•‬
‫نود تقليص هذا املتجه بحيث تظهر كل كلمة مرة واحدة فقط ‪،‬‬ ‫•‬
‫بغض النظر عن عدد املرات اليت تظهر فيها هذه الكلمة في أي من القصص املحددة‪.‬‬ ‫•‬
‫ألغراض التوضيح ‪ ،‬سنستخدم القصة البسيطة التالية كمدخالتنا ‪:‬‬

‫‪the quick red fox jumps over the slow red turtle‬‬

‫بالنظر إلى هذه املدخالت ‪ ،‬يجب أن ينتج برنامجنا املتجه التالي‪:‬‬

‫‪fox‬‬ ‫‪jumps‬‬ ‫‪over‬‬ ‫‪quick‬‬ ‫‪red‬‬ ‫‪slow‬‬ ‫‪the‬‬ ‫‪turtle‬‬

‫‪Eliminating Duplicates‬‬ ‫استبعاد التكرارات‬

‫الستبعاد الكلمات املتكررة ‪ ،‬سنقوم أوال ً بفرز املتجه بحيث تظهر الكلمات املتكررة بجوار بعضها‪.‬‬
‫بمجرد فرز املتجه ‪ ،‬يمكننا استخدام خوارزمية مكتبة أخرى ‪ ،‬تسمى فريد_ ‪،unique‬‬ ‫•‬
‫وذلك إلعادة ترتيب املتجه بحيث تظهر العنارص الفريدة منه في الجزء األول من املتجه‪.‬‬ ‫•‬
‫وألن الخوارزميات ال يمكنها إجراء عمليات حاوية ‪،‬‬ ‫•‬
‫فعليا ‪:‬‬
‫ً‬ ‫سنستخدم العضو مسح_ ‪ erase‬في املتجه إلزالة العنارص‬ ‫•‬

‫)‪void elimDups(vector<string> &words‬‬


‫‪{ // sort words alphabetically so we can find duplicates‬‬
‫;))(‪    sort(words.begin(), words.end‬‬
‫‪    // unique reorders input range so that each word appears once in‬‬
‫‪    // front portion of range and returns iterator one past unique range‬‬
‫;))(‪    auto end_unique = unique(words.begin(), words.end‬‬
‫‪    // erase uses a vector operation to remove non-unique elements‬‬
‫;))(‪    words.erase(end_unique, words.end‬‬
‫}‬

‫تأخذ الخوارزمية فرز_ مكررين للداللة على نطاق عنارص الفرز‪.‬‬ ‫•‬
‫في هذا االستدعاء ‪ ،‬نقوم بفرز املتجه بأكمله‪.‬‬ ‫•‬
‫بعد استدعاء فرز_ ‪ ،‬يتم ترتيب الكلمات بتنسيق‬ ‫•‬

‫‪fox‬‬ ‫‪jumps‬‬ ‫‪over‬‬ ‫‪quick‬‬ ‫‪red‬‬ ‫‪red‬‬ ‫‪slow‬‬ ‫‪the‬‬ ‫‪the‬‬ ‫‪turtle‬‬

‫الحظ ظهور الكلمتني ‪ red‬و ‪ the‬مرتني‪.‬‬ ‫•‬

‫‪Using unique‬‬ ‫استخدام فريد_‬

‫بمجرد فرز كلمات ‪ ، words‬سنود أن نحتفظ بنسخة واحدة فقط من كل كلمة‪.‬‬


‫تُعيد الخوارزمية فريد_ ‪ unique‬ترتيب نطاق املدخالت "لتستبعد" املدخالت املتكررة املتجاورة ‪،‬‬ ‫•‬
‫مكررا يشري إلى نهاية نطاق القيم الفريدة‪.‬‬
‫ً‬ ‫وتُعيد‬ ‫•‬
‫فبعد أن نستدعي فريد_ ‪ ،‬سيحمل املتجه‬ ‫•‬
‫‪fox‬‬ ‫‪jumps‬‬ ‫‪over‬‬ ‫‪quick‬‬ ‫‪red‬‬ ‫‪slow‬‬ ‫‪the‬‬ ‫‪turtle‬‬ ‫???‬ ‫???‬
‫|‬
‫‪end_unique‬‬
‫)‪(one past last unique element‬‬

‫حجم كلمات كما هو ؛ فال يزال يحمل عرشة عنارص‪ .‬لكن تم تغيري ترتيب هذه العنارص ‪-‬‬ ‫•‬
‫حيث تمت "إزالة" العنارص املتكررة املتجاورة‪.‬‬ ‫•‬
‫لقد وضعنا إزالة بني عالميت اقتباس ألن الخوارزمية فريد_ لن تزيل أية عنارص‪.‬‬ ‫•‬
‫بل ‪ ،‬تقوم بالكتابة فوق املتكررات املتجاورة بحيث تظهر العنارص الفريدة في مقدمة التسلسل‪.‬‬ ‫•‬
‫املكرر املعاد بواسطة فريد_ يشري إلى ما بعد آخر عنرص فريد‪.‬‬ ‫•‬
‫ستظل عنارص ما بعد تلك النقطة موجودة ‪ ،‬لكننا لن نعرف ما القيم اليت تملكها‪.‬‬ ‫•‬

‫ملحوظة‬

‫تعمل خوارزميات املكتبة على مكررات ‪ ،‬ﻻ على حاويات‪ .‬لذا ‪ ،‬لن يمكنها (مبارشة) أن تضيف أو تزيل عنارص‪.‬‬

‫استخدام عمليات حاوية إلزالة عنارص‬


‫‪Using Container Operations to Remove Elements‬‬

‫فعليا ‪ ،‬يجب أن نستخدم عملية حاوية ‪ ،‬وذلك باستدعاء مسح_ ‪.erase‬‬


‫ً‬ ‫إلزالة عنارص غري مستخدمة‬
‫تقوم مسح_ بإزالة نطاق العنارص من العنرص الذي يشري إليه ‪ end_unique‬عرب نهاية كلمات‪.‬‬ ‫•‬
‫بعد هذا االستدعاء ‪ ،‬ستحتوي كلمات على ثماني كلمات فريدة من املدخالت‪.‬‬ ‫•‬
‫جدير بالذكر أن هذا االستدعاء ملسح_ سيكون آمناً حىت لو لم تحتوي كلمات على كلمات متكررة‪.‬‬
‫في تلك الحالة ‪ ،‬يعيد فريد_ نهاية كلمات ‪. words.end‬‬ ‫•‬
‫ِ‬
‫وكال وسيطتا مسح_ سيكون لهما نفس القيمة وهو ‪ :‬نهاية_ كلمات ‪. Words.end‬‬ ‫•‬
‫فارغا‪.‬‬
‫ً‬ ‫وحقيقة أن املكررات متساوية تعين أن النطاق الذي تم تمريره ملسح_ سيكون‬ ‫•‬
‫عملية مسح لنطاق فارغ لن يكون له أي تأثري يذكر ‪،‬‬ ‫•‬
‫لذا فإن برنامجنا صحيح حىت لو لم يكن للمدخالت أي عنارص متكررة‪.‬‬ ‫•‬

‫تمارين القسم ‪10.2.3‬‬

‫التمرين ‪:10.9‬‬
‫‪ -‬نفذ إصدارك من دالة ‪.elimDups‬‬
‫‪ -‬اخترب برنامجك بطباعة املتجه بعد قراءة املدخالت ‪،‬‬
‫‪ -‬وبعد استدعاء فريد_ ‪،‬‬
‫‪ -‬وبعد استدعاء مسح_‪.‬‬
‫التمرين ‪:10.10‬‬
‫ملاذا تعتقد أن الخوارزميات ال تغري حجم الحاويات؟‬
‫‪ 10٫3‬تخصــــــــــيص العمـــــــــليــــــــــات‬
‫‪10.3 Customizing Operations‬‬

‫العديد من الخوارزميات تقارن العنارص في تسلسل املدخالت‪.‬‬


‫تستخدم هذه الخوارزميات افرتاضياً إما عامل نوع العنرص أقل من > أو التساوي ==‪.‬‬ ‫•‬
‫أيضا إصدارات تتيح لنا توفري عملياتنا الخاصة الستخدامها بدال ً من العامل االفرتايض‪.‬‬
‫تعرف املكتبة ً‬
‫ّ‬ ‫•‬

‫فعلى سبيل املثال ‪ ،‬تستخدم الخوارزمية فرز_ ‪ sort‬عامل نوع العنرص > أقل من‪.‬‬
‫مع ذلك ‪ ،‬قد نرغب في فرز تسلسل إلى ترتيب مختلف عن ذلك املحدد بواسطة > ‪،‬‬ ‫•‬
‫أو قد يحتوي تسلسلنا على عنارص من نوع فئة (كبيانات_املبيعات) ال تملك العامل >‪.‬‬ ‫•‬
‫في كلتا الحالتني ‪ ،‬نحتاج إلى تجاوز السلوك االفرتايض لـفرز_‪.‬‬ ‫•‬

‫‪10.3.1. Passing a Function to an Algorithm‬‬ ‫‪ .10.3.1‬تمرير دالة لخوارزمية‬

‫مثال ‪ ،‬افرتض أننا نريد طباعة متجه بعد أن استدعينا ‪. elimDups‬‬


‫أبجديا داخل كل حجم‪.‬‬
‫ً‬ ‫أيضا أننا نريد أن نرى الكلمات مرتبة حسب حجمها ‪ ،‬ثم‬
‫مع ذلك ‪ ،‬سنفرتض ً‬ ‫•‬
‫فإلعادة ترتيب املتجه حسب الطول ‪ ،‬سنستخدم نسخة فرز_ أخرى زائدة‪-‬التعبئة‪.‬‬ ‫•‬
‫ستأخذ نسخة فرز_ هذه وسيطة ثالثة يطلق عليها ‪ :‬املحمولة ‪. Predicate‬‬ ‫•‬

‫‪Predicates‬‬ ‫املحموالت‬

‫املحمولة تعبري يمكن استدعاؤه ويعيد قيمة يمكن استخدامها كرشط (تعطي نتيجة منطقية)‪.‬‬
‫املحموالت اليت تستخدمها خوارزميات املكتبة هي‬ ‫•‬
‫إما محموالت أحادية ‪ ( unary predicates‬بمعىن أن لديها معلمة واحدة ) ‪،‬‬ ‫•‬
‫وإما محموالت ثنائية ‪ ( binary predicates‬بمعىن أن لديها معلمتان )‪.‬‬ ‫•‬

‫الخوارزميات اليت تأخذ محموالت تستدعي املحمولة املحدد على عنارص في نطاق املدخالت‪.‬‬
‫نتيجة لذلك ‪ ،‬يجب أن يكون من املمكن تحويل نوع العنرص إلى نوع معلمة املحمولة‪.‬‬ ‫•‬
‫يستخدم إصدار فرز_ الذي يأخذ محمولة ثنائية املحمولة املحددة بدال ً من العامل > ملقارنة عنارص‪.‬‬ ‫•‬
‫يجب أن تفي املحموالت اليت نوفرها لفرز_ باملتطلبات اليت سنصفها في الفقرة ‪.11.2.2‬‬ ‫•‬
‫تعرف ترتيبًا ثاب ًتا لجميع العنارص املمكنة في تسلسل املدخالت‪.‬‬
‫حالياً ‪ ،‬نحتاج معرفة أن العملية يجب أن ّ‬ ‫•‬
‫تعد الدالة هل_أقرص ‪ isShorter‬من الفصل ‪ 6‬مثاال ً على دالة تليب هذه املتطلبات ‪،‬‬ ‫•‬
‫لذا يمكننا تمريرها لفرز_‪ .‬وسيؤدي القيام بذلك إلى إعادة ترتيب العنارص حسب الحجم ‪:‬‬ ‫•‬

‫‪// comparison function to be used to sort by word length‬‬


‫{ )‪bool isShorter(const string &s1, const string &s2‬‬
‫;)(‪return s1.size() < s2.size‬‬ ‫}‬
‫‪// sort on word length, shortest to longest‬‬
‫;)‪sort(words.begin(), words.end(), isShorter‬‬

‫إذا احتوت الكلمات على نفس البيانات الواردة في الفقرة ‪، 10٫2٫3‬‬ ‫•‬
‫فإن هذا االستدعاء سيعيد ترتيب الكلمات ‪،‬‬ ‫•‬
‫بحيث تظهر جميع الكلمات ذات الطول ‪ 3‬قبل ذات الطول ‪ ، 4‬واليت بدورها تتبعها كلمات بطول ‪ ، 5‬و هكذا‪.‬‬ ‫•‬

‫‪Sorting Algorithms‬‬ ‫خوارزميات الفرز‬

‫أيضا الحفاظ على الرتتيب األبجدي بني العنارص اليت لها نفس الطول‪.‬‬
‫عندما نفرز كلمات حسب الحجم ‪ ،‬نريد ً‬
‫وللحفاظ على الكلمات متساوية الطول برتتيبها األبجدي ‪ ،‬نستخدم خوارزمية فرز_صلب ‪.stable_sort‬‬ ‫•‬
‫يحافظ فرز_صلب على الرتتيب األصلي بني العنارص املتساوية‪.‬‬ ‫•‬

‫في العادة ‪ ،‬ال نهتم بالرتتيب النسيب للعنارص املتساوية في تسلسل مفرز‪ .‬فبعد كل يشء ‪ ،‬إنها متساوية‪.‬‬
‫مع ذلك ‪ ،‬في هذه الحالة ‪ ،‬قمنا بتعريف كلمة "متساوي" لتعين "تملك نفس الطول"‪.‬‬ ‫•‬
‫ال تزال العنارص متساوية الطول تختلف عن بعضها عند عرض محتوياتها‪.‬‬ ‫•‬
‫من خالل استدعاء فرز_صلب ‪ ،‬يمكننا الحفاظ على الرتتيب األبجدي بني العنارص متساوية الطول‪:‬‬ ‫•‬

‫‪// put words in alphabetical order and remove duplicates‬‬


‫;)‪elimDups(words‬‬
‫‪// resort by length,‬‬
‫‪// maintaining alphabetical order among words of the same length‬‬
‫;)‪stable_sort(words.begin(), words.end(), isShorter‬‬
‫)‪for (const auto &s : words‬‬ ‫‪// no need to copy the strings‬‬
‫;" " << ‪cout << s‬‬ ‫‪// print each element separated by a space‬‬
‫;‪cout << endl‬‬

‫بافرتاض أن الكلمات كانت بالرتتيب األبجدي قبل هذا االستدعاء ‪،‬‬ ‫•‬
‫بعد االستدعاء ‪ ،‬سيتم فرز الكلمات حسب حجم العنرص ‪ ،‬وستبقى كلمات كل طول بالرتتيب األبجدي‪.‬‬ ‫•‬
‫إذا قمنا بتشغيل هذا الكود على املتجه األصلي الخاص بنا ‪ ،‬فستكون املخرجات‬

‫‪fox‬‬ ‫‪red‬‬ ‫‪the‬‬ ‫‪over‬‬ ‫‪slow‬‬ ‫‪jumps‬‬ ‫‪quick‬‬ ‫‪turtle‬‬

‫تمارين القسم ‪10.3.1‬‬

‫التمرين ‪:10.11‬‬
‫برنامجا يستخدم "فرز_صلب ‪" stable_sort‬و هل_أقرص ‪ isShorter‬لفرز متجه تم تمريره إلى‬
‫ً‬ ‫‪ -‬اكتب‬
‫إصدارك من ‪.elimDups‬‬
‫‪ -‬اطبع املتجه للتحقق من صحة برنامجك‪.‬‬
‫التمرين ‪:10.12‬‬
‫‪ -‬اكتب دالة باسم ‪ CompareIsbn‬تقارن بني أعضاء ‪ isbn‬لكائنني من كائنات ‪.Sales_data‬‬
‫‪ -‬استخدم هذه الدالة لفرز متجه يحتوي على كائنات ‪.Sales_data‬‬

‫التمرين ‪:10.13‬‬
‫ُعرف املكتبة خوارزمية تسمى " ِق ْسم ‪ " partition‬تأخذ محمولة وتقسم الحاوية بحيث تظهر القيم اليت يكون‬
‫‪-‬ت ّ‬
‫صحيحا ‪ true‬في القسم األول وتلك اليت يكون تعبري محمولها خاطًئ ا ‪ false‬لتظهر في القسم‬
‫ً‬ ‫تعبري محمولها‬
‫الثاني‪.‬‬
‫صحيحا‪.‬‬
‫ً‬ ‫مكررا بعد آخر عنرص أعاد محموله‬
‫ً‬ ‫‪ -‬تُعيد الخوارزمية‬
‫منطقيا يشري إلى ما إذا كانت السلسلة تتكون من خمسة أحرف أو أكرث‪.‬‬
‫ً‬ ‫‪ -‬اكتب دالة تأخذ سلسلة وتُعيد‬
‫‪ -‬استخدم هذه الدالة لتقسيم كلمات‪.‬‬
‫‪ -‬اطبع العنارص اليت تحتوي على خمسة أحرف أو أكرث‪.‬‬

‫‪10.3.2. Lambda Expressions‬‬ ‫‪ .10.3.2‬تعابري المدا‬

‫يجب أن تحتوي املحموالت اليت نمررها إلى خوارزمية ما على معلمة واحدة أو اثنتني ‪،‬‬
‫اعتما ًد ا على ما إذا كانت الخوارزمية تأخذ محمولة أحادية أو ثنائية ‪ ،‬على التوالي‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فإننا نود أحياناً إجراء معالجة تتطلب وسيطات أكرث مما تسمح به محمولة الخوارزمية‪.‬‬ ‫•‬
‫فعلى سبيل املثال ‪ ،‬في الحل الذي كتبته للتمرين األخري في القسم السابق ‪،‬‬ ‫•‬
‫كان يجب أن يربط الحجم ‪ 5‬إلى املحمولة املستخدمة لتقسيم التسلسل‪.‬‬ ‫•‬
‫سيكون من املفيد القدرة على تقسيم تسلسل دون الحاجة إلى كتابة محمولة منفصلة لكل حجم ممكن‪.‬‬ ‫•‬
‫كمثال ذي صلة ‪ ،‬سرناجع برنامجنا من الفقرة ‪ 10٫3٫1‬إلظهار عدد الكلمات ذات الحجم املحدد أو أكرب‪.‬‬ ‫•‬
‫أيضا بتغيري املخرجات بحيث ﻻ يطبع إﻻ الكلمات ذات الطول املحدد أو أكرب‪.‬‬
‫سنقوم ً‬ ‫•‬
‫الرسم التخطيطي لهذه الدالة ‪ ،‬اليت سنسميها ‪ ، biggies‬سيكون على النحو التالي ‪:‬‬

‫)‪void biggies(vector<string> &words, vector<string>::size_type sz‬‬


‫‪{ // put words in alphabetical order and remove duplicates‬‬
‫;)‪elimDups(words‬‬
‫‪// resort by length,‬‬
‫‪//maintaining alphabetical order among words of the same length‬‬
‫;)‪stable_sort(words.begin(), words.end(), isShorter‬‬
‫‪// get an iterator to first element whose size() is >= sz‬‬
‫‪// compute number of elements with size >= sz‬‬
‫‪// print words of given size or longer, each one followed by space‬‬
‫}‬

‫تتمثل مشكلتنا الجديدة في إيجاد أول عنرص في املتجه يملك الحجم املحدد‪.‬‬ ‫•‬
‫بمجرد أن نعرف ذلك العنرص ‪ ،‬سنستخدم موضعه لحوسبة عدد العنارص اليت تملك ذلك الحجم أو أكرب‪.‬‬ ‫•‬
‫يمكننا استخدام خوارزمية املكتبة أوجد_إذا ‪ find_if‬إليجاد عنرص بحجم معني‪.‬‬
‫زوجا من املكررات تدل على نطاق‪.‬‬
‫ً‬ ‫ومثل الخوارزمية إيجاد_ ‪ ، find‬تأخذ الخوارزمية ‪find_if‬‬ ‫•‬
‫لكنها على عكس ‪ ، find‬ستكون وسيطتها الثالثة عبارة عن محمولة‪.‬‬ ‫•‬
‫تستدعي الخوارزمية ‪ find_if‬املحمولة املحددة على كل عنرص في نطاق املدخالت‪.‬‬ ‫•‬
‫فتقوم بإعادة أول عنرص تقوم املحمولة بإعادة قيمة غري صفرية له ‪،‬‬ ‫•‬
‫أو تقوم بإعادة مكرر نهاية_ إذا لم يتم إيجاد مثل ذلك العنرص‪.‬‬ ‫•‬

‫وحجما‬
‫ً‬ ‫سيكون من السهل كتابة دالة تأخذ سلسلة‬
‫منطقيا يشري إلى ما إذا كان حجم سلسلة معينة أكرب من الحجم املحدد‪.‬‬
‫ً‬ ‫وتُعيد‬ ‫•‬
‫مع ذلك ‪ ،‬فإن ‪ find_if‬تأخذ محمولة أحادية ؛ فأي دالة نمررها إلى ‪، find_if‬‬ ‫•‬
‫يجب أن تملك معامالً واحداً بالضبط يمكن استدعاؤه باستخدام عنرص من تسلسل املدخالت‪.‬‬ ‫•‬
‫إذن‪ ،‬فال توجد طريقة لتمرير وسيطة ثانية تمثل الحجم‪.‬‬ ‫•‬
‫لحل هذا الجزء من مشكلتنا ‪ ،‬سنحتاج إلى استخدام بعض أقسام اللغة اإلضافية‪.‬‬ ‫•‬

‫‪Introducing Lambdas‬‬ ‫تقديم المدا_‬

‫يمكننا تمرير أي نوع من الكائنات القابلة لالستدعاء إلى خوارزمية‪.‬‬


‫فيمكن استدعاء كائن أو تعبري ما دام بإمكاننا تطبيق عامل االستدعاء عليه‪ .‬بمعىن ‪:‬‬ ‫•‬
‫إذا كان ‪ e‬تعبريًا قابالً لالستدعاء ‪ ،‬فيمكننا كتابة )‪ e(args‬حيث تكون ‪ args‬قائمة من صفر وسيطات أو‬ ‫•‬
‫أكرث مفصولة بفواصل‪.‬‬

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

‫>‪[capture list] (parameter list) -‬‬ ‫} ‪return type { function body‬‬

‫حيث ‪:‬‬
‫معرفة في الدالة املتضمنة‬
‫غالبا) ّ‬
‫ً‬ ‫قائمة_التقاط ‪ capture list‬هي قائمة متغريات محلية (فارغة‬ ‫•‬
‫نوع_اإلعادة ‪ return type‬وقائمة املعلمات ‪ parameter list‬وبنية الدالة ‪function body‬‬ ‫•‬
‫هي نفسها كما في أي دالة عادية‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فعلى عكس الدوال العادية ‪ ،‬يجب أن تستخدم المدا العائد الالحق لتعريف نوع اإلعادة‪.‬‬ ‫•‬
‫دائما تضمني قائمة_التقاط وبنية الدالة ‪:‬‬
‫ً‬ ‫يمكننا حذف قائمة املعلمات أو نوع اإلعادة أو كالهما لكن يجب‬ ‫•‬
‫;} ;‪auto f = [] { return 42‬‬

‫هنا ‪ ،‬عرفنا ‪ f‬ككائن قابل لالستدعاء ال يأخذ أية وسيطات ويعيد ‪. 42‬‬ ‫•‬
‫نستدعي الالمدا_ بنفس الطريقة اليت نستدعي بها أية دالة وذلك باستخدام عامل االستدعاء ‪:‬‬

‫;‪cout << f() << endl‬‬ ‫‪// prints 42‬‬

‫إن حذف األقواس وقائمة املعلمات في المدا_ يعادل تعريف قائمة معلمات فارغة‪.‬‬ ‫•‬
‫ومن ثم ‪ ،‬فعندما نستدعي ‪ ، f‬ستكون قائمة وسيطاتها فارغة‪.‬‬ ‫•‬
‫فإذا حذفنا نوع اإلعادة ‪ ،‬فإن الالمدا_ تملك نوع إعادة مستنتج يعتمد على الكود في بنية الدالة‪.‬‬ ‫•‬
‫أما إذا كانت بنية الدالة تملك فقط جملة ِ‬
‫أعد ‪ ،‬فسيتم استنتاج نوع اإلعادة من نوع التعبري املعاد‪.‬‬ ‫•‬
‫خالف ذلك ‪ ،‬يكون نوع اإلعادة فراغـاً ‪.void‬‬

‫ملحوظة‬

‫الالمدا_ ذات بنية دالة ال تحوي أي يشء إﻻ جملة ِ‬


‫أعد وحيدة وال تحدد نوع إعادتها ستُعيد فراغـاً‪.‬‬

‫‪Passing Arguments to a Lambda‬‬ ‫تمرير وسيطات إلى المدا_‬

‫كما هو حال استدعاء أي دالة عادية ‪ ،‬تُستخدم وسيطات استدعاء المدا لتهيئة معامالتها‪.‬‬
‫فكالعادة ‪ ،‬يجب أن تتطابق الوسيطات مع أنواع املعلمات‪.‬‬ ‫•‬
‫لكن على عكس الدوال العادية ‪ ،‬ﻻ يسمح أن تحتوي الالمدا على وسيطات افرتاضية‪.‬‬ ‫•‬
‫دائم ا ما يكون عدد وسيطات استدعاء الالمدا مطابقاً لعدد معلماتها‪.‬‬
‫ً‬ ‫لذا ‪،‬‬ ‫•‬
‫وبمجرد تهيئة معلماتها ‪ ،‬يتم تنفيذ بنية الدالة‪.‬‬ ‫•‬
‫كمثال على المدا تأخذ وسيطات ‪ ،‬يمكننا كتابة المدا تترصف مثل دالتنا ‪: isShorter‬‬

‫};)(‪[](const string &a, const string &b){ return a.size() < b.size‬‬

‫تشري قائمة االلتقاط الفارغة هذه إلى أن هذه الالمدا لن تستخدم أي متغريات محلية من الدالة املتضمنة‪.‬‬ ‫•‬
‫معلمات الالمدا ‪ ،‬مثل معلمات ‪ ، isShorter‬عبارة عن مراجع لسلسلة ثابتة‪.‬‬ ‫•‬
‫وتقارن بنيتها حجم معلماته وتعيد قيمة منطقية تعتمد على األحجام النسبية للوسيطات املعطاة‪.‬‬ ‫•‬
‫يمكننا إعادة كتابة استدعائنا لفرز_صلب ‪ stable_sort‬لتستخدم هذه الالمدا على النحو التالي ‪:‬‬

‫‪// sort words by size,‬‬


‫‪// but maintain alphabetical order for words of the same size‬‬
‫‪stable_sort(words.begin(), words.end(),‬‬
‫)‪[](const string &a, const string &b‬‬
‫;)};)(‪{ return a.size() < b.size‬‬

‫عندما تحتاج "‪ "stable_sort‬إلى مقارنة عنرصين ‪ ،‬فسوف يستدعي تعبري الالمدا املعطى‪.‬‬ ‫•‬
‫‪Using the Capture List‬‬ ‫استخدام قائمة االلتقاط‬

‫نحن اآلن جاهزون لحل مشكلتنا األصلية ‪،‬‬


‫وهو كتابة تعبري قابل لالستدعاء يمكننا تمريره لإليجاد املرشوط ‪. find_if‬‬ ‫•‬
‫نريد تعبريًا يقارن طول كل سلسلة في تسلسل املدخالت بقيمة املعلمة ‪ sz‬في دالة ‪.biggies‬‬ ‫•‬

‫وبالرغم من أن الالمدا قد تظهر داخل دالة ‪،‬‬


‫إال أنه لن يمكنها استخدام متغريات محلية لتلك الدالة إال إن كانت تحدد متغريات تنوي استخدامها‪.‬‬ ‫•‬
‫تعر ف الالمدا متغريات ستستخدمها من خالل تضمني تلك املتغريات املحلية في قائمة التقاطها‪.‬‬
‫ّ‬ ‫•‬
‫تقوم قائمة االلتقاط بتوجيه الالمدا لتضمني املعلومات الالزمة للوصول إلى تلك املتغريات داخلها‪.‬‬ ‫•‬
‫في هذه الحالة ‪ ،‬ستلتقط الالمدا ‪ sz‬وستكون لديها معلمة سلسلة وحيدة‪.‬‬ ‫•‬
‫ستقارن بنية الالمدا حجم السلسلة املحدد بقيمة ‪ sz‬امللتقطة ‪:‬‬ ‫•‬

‫;} ;‪[sz](const string &a) { return a.size() >= sz‬‬

‫معرفة في الدالة املتضمنة مفصولة بفواصل‪.‬‬


‫داخل القوس [ ] في بداية الالمدا يمكننا تقديم قائمة بأسماء ّ‬ ‫•‬
‫وألن هذه الالمدا_ تلتقط ‪ ، sz‬فقد تستخدم بنيتها ‪.sz‬‬ ‫•‬
‫لم تلتقط الالمدا ‪ ، words‬وبالتالي لن يمكنها الوصول إلى ذلك املتغري‪.‬‬ ‫•‬
‫لو أعطينا الالمدا_ قائمة التقاط فارغة ‪ ،‬فلن يتم تجميع الكود الخاص بنا ‪:‬‬ ‫•‬

‫‪// error: sz not captured‬‬


‫;} ;‪[](const string &a){ return a.size() >= sz‬‬

‫ملحوظة‬

‫محليا لدالتها املتضمنة إﻻ إذا التقطت ذلك املتغري ضمن قائمة التقاطها‪.‬‬
‫ً‬ ‫لن تستخدم المدا متغريًا‬

‫‪Calling find_if‬‬ ‫استدعاء ‪find_if‬‬

‫باستخدام هذه الالمدا ‪ ،‬يمكننا إيجاد أول عنرص يكون حجمه على األقل بحجم ‪: sz‬‬

‫‪// get an iterator to first element whose size() is >= sz‬‬


‫)‪auto wc = find_if(words.begin(), words.end(), [sz](const string &a‬‬
‫;)} ;‪{ return a.size() >= sz‬‬

‫يقوم استدعاء ‪ find_if‬بإعادة مكرر إلى أول عنرص يكون على األقل بطول ‪ sz‬املعطى ‪،‬‬ ‫•‬
‫أو بإعادة نسخة من نهاية_ كلمات ‪ Words.end‬إذا لم يكن ذلك العنرص موجو ًدا‪.‬‬ ‫•‬
‫يمكننا استخدام املكرر العائد من ‪ find_if‬لحوسبة عدد العنارص اليت ظهرت بني ذلك املكرر ونهاية_ كلمات‪:‬‬

‫‪// compute number of elements with size >= sz‬‬


‫;‪auto count = words.end() - wc‬‬
‫)"‪cout << count << " " << make_plural(count, "word", "s‬‬
‫;‪<< " of length " << sz << " or longer" << endl‬‬

‫تستدعي جملة مخرجاتنا ‪ make_plural‬لتطبع كلمة أو كلمات ‪ ،‬اعتما ًدا على ما إذا كان هذا الحجم يساوي ‪.1‬‬

‫‪The for_each Algorithm‬‬ ‫الخوارزمية ‪for_each‬‬

‫الجزء األخري من مشكلتنا هو طباعة العنارص في كلمات واليت طولها مساو لـ‪ sz‬أو أكرب‪.‬‬
‫للقيام بذلك ‪ ،‬سنستخدم الخوارزمية ‪.for_each‬‬ ‫•‬
‫تأخذ هذه الخوارزمية كائنًا قابالً لالستدعاء وتستدعي ذلك الكائن على كل عنرص في نطاق املدخالت ‪:‬‬ ‫•‬

‫‪// print words of given size or longer, each one followed by space‬‬
‫;)};" " << ‪for_each(wc, words.end(),[](const string &s){cout << s‬‬
‫;‪cout << endl‬‬

‫قائمة االلتقاط في هذه الالمدا فارغة ‪ ،‬مع ذلك تستخدم البنية اسمني ‪:‬‬
‫معلمتها الخاصة اليت تسمى ‪ ، s‬و ‪.cout‬‬ ‫•‬
‫معرفة ضمن الدالة املتضمنة فقط‪.‬‬
‫إن قائمة االلتقاط فارغة ألننا نستخدمها ملتغريات ( ‪ّ ) non-static‬‬ ‫•‬
‫معرفة خارج الدالة اليت تتضمنها المدا_‪.‬‬
‫لكن يمكن أن تستخدم المدا أسماء ّ‬ ‫•‬
‫محليا في الدالة املتضمنة ‪ biggies‬؛‬
‫ً‬ ‫اسما معرفاً‬
‫ً‬ ‫في هذه الحالة ‪ cout ،‬ليس‬ ‫•‬
‫حيث يتم تعريف هذا االسم في العنوان ‪.iostream‬‬ ‫•‬
‫وطاملا تم تضمني العنوان ‪ iostream‬في نطاق يظهر فيه ‪ ، biggies‬يمكن أن تستخدمه الالمدا_‪.‬‬ ‫•‬

‫ملحوظة‬

‫تُستخدم قائمة االلتقاط ملتغريات محلية غري‪-‬ساكنة فقط ؛‬ ‫•‬


‫حيث يمكن أن تستخدم الالمدا متغريات ساكنة محلية ومتغريات معلنة مبارشة خارج الدالة‪.‬‬ ‫•‬

‫‪Putting It All Together‬‬ ‫لنضع كل يشء معا‬

‫اآلن بعد أن نظرنا إلى الربنامج بالتفصيل ‪ ،‬إليك الربنامج ككل‪:‬‬

‫)‪void biggies(vector<string> &words, vector<string>::size_type sz‬‬


‫‪{ // put words in alphabetical order and remove duplicates‬‬
‫;)‪    elimDups(words‬‬
‫‪    // sort words by size,‬‬
‫‪    // but maintain alphabetical order for words of the same size‬‬
‫‪    stable_sort(words.begin(), words.end(),‬‬
‫)‪[](const string &a, const string &b‬‬
‫;)};)(‪{ return a.size() < b.size‬‬
‫‪    // get an iterator to first element whose size() is >= sz‬‬
‫)‪    auto wc = find_if(words.begin(), words.end(),[sz](const string &a‬‬
‫;)} ;‪{ return a.size() >= sz‬‬
‫‪    // compute number of elements with size >= sz‬‬
‫;‪    auto count = words.end() - wc‬‬
‫)"‪    cout << count << " " << make_plural(count, "word", "s‬‬
‫;‪<< " of length " << sz << " or longer" << endl‬‬
‫‪    // print words of given size or longer, each one followed by space‬‬
‫;)};" " << ‪    for_each(wc, words.end(), [](const string &s){cout << s‬‬
‫;‪    cout << endl‬‬
‫}‬

‫تمارين القسم ‪10.3.2‬‬

‫تمرين ‪:10.14‬‬
‫اكتب المدا تأخذ رقمني صحيحني وتُعيد مجموعهما‪.‬‬

‫التمرين ‪:10.15‬‬
‫‪ -‬اكتب المدا تلتقط رقم صحيح من دالة تضمينها وتأخذ معامل رقم صحيح‪.‬‬
‫‪ -‬ينبغي أن تُعيد الالمدا مجموع الرقم الصحيح امللتقط مع معلمة الرقم الصحيح‪.‬‬

‫التمرين ‪:10.16‬‬
‫اكتب نسختك من دالة ‪ biggies‬باستخدام الالمدا‪.‬‬

‫التمرين ‪:10.17‬‬
‫أعد كتابة التمرين ‪ 10٫12‬من الفقرة ‪ 10٫3٫1‬باستخدام الالمدا في استدعاء فرز بدال ً من دالة ‪.CompareIsbn‬‬

‫التمرين ‪:10.18‬‬
‫‪ -‬أعد كتابة ‪ biggies‬باستخدام القسم ‪ partition‬بدال ً من ‪ .find_if‬لقد‬
‫‪ -‬وصفنا خوارزمية التقسيم في التمرين ‪ 10٫13‬في الفقرة ‪.3.1.10‬‬

‫التمرين ‪:10.19‬‬
‫‪ -‬أعد كتابة التمرين السابق باستخدام "القسم الصلب ‪، "stable_partition‬‬
‫‪ -‬والذي مثل "الفرز الصلب ‪ "stable_sort‬يحافظ على ترتيب العنارص األصلي في التسلسل املقسم‪.‬‬

‫‪10.3.3. Lambda Captures and Returns‬‬ ‫‪ .10.3.3‬التقاط وإعادة المدا‬

‫نعرف المدا ‪ ،‬يقوم املرتجم بتوليد نوع فئة جديد (غري مسمى) يتوافق مع تلك الالمدا‪.‬‬
‫عندما ّ‬
‫سرنى كيف يتم توليد تلك الفئات في فقرة ‪ .14٫8٫1‬أما في الوقت الحالي ‪ ،‬فما يفيدنا فهمه هو ‪:‬‬ ‫•‬
‫نعرف نوعاً جديداً وكائناً من ذلك النوع ‪:‬‬
‫أنه عندما نقوم بتمرير المدا إلى دالة ‪ ،‬فإننا ّ‬ ‫•‬
‫فالوسيطة هي كائن غري مسمى من نوع الفئة املولّ د بواسطة املرتجم هذا‪.‬‬ ‫•‬
‫وباملثل ‪ ،‬عندما نستخدم ‪ auto‬لتعريف متغري تمت تهيئته بواسطة المدا ‪،‬‬ ‫•‬
‫نعرف كائنًا من النوع املولّ د من تلك الالمدا‪.‬‬
‫فإننا ّ‬ ‫•‬

‫افرتاضياً ‪ ،‬تحتوي الفئة املولّ دة من المدا على عضو بيانات يتوافق مع املتغريات امللتقطة بواسطة الالمدا‪.‬‬
‫فمثل أعضاء بيانات أي فئة ‪ ،‬تتم تهيئة أعضاء بيانات المدا عند إنشاء كائن المدا‪.‬‬ ‫•‬

‫‪Capture by Value‬‬ ‫التقاط بواسطة قيمة‬

‫على غرار تمرير املعلمات ‪ ،‬يمكننا التقاط متغريات بواسطة قيمة أو بواسطة مرجع‪.‬‬
‫يغطي الجدول ‪ 10٫1‬الطرق املختلفة اليت يمكننا من خاللها تكوين قائمة التقاط‪.‬‬ ‫•‬
‫حىت اآلن ‪ ،‬التقطت الالمدا متغريات بواسطة قيمة‪.‬‬ ‫•‬
‫وكما هو حال معلمة تم تمريرها بواسطة قيمة ‪ ،‬يجب أن يكون من املمكن نسخ تلك املتغريات‪.‬‬ ‫•‬
‫لكن على عكس املعلمات ‪ ،‬يتم نسخ قيمة متغري ملتقط عند إنشاء الالمدا ‪ ،‬وليس عند استدعائها ‪:‬‬ ‫•‬

‫{ )(‪void fcn1‬‬
‫;‪    size_t v1 = 42‬‬ ‫‪// local variable‬‬
‫‪    // copies v1 into the callable object named f‬‬
‫;} ;‪    auto f = [v1] { return v1‬‬
‫;‪    v1 = 0‬‬
‫‪    auto j = f(); } // j is 42; f stored a copy of v1 when we created it‬‬

‫ونظرًا ألن القيمة نُسخت عند إنشاء الالمدا ‪،‬‬ ‫•‬


‫فلن يكون للتغيريات الالحقة على متغري ملتقط أي تأثري على القيمة املقابلة داخل الالمدا‪.‬‬ ‫•‬

‫الجدول ‪ .10.1‬قائمة التقاط المدا‬

‫‪Empty capture list. The lambda may not use variables‬‬


‫‪from the enclosing function.‬‬
‫][‬
‫‪A lambda may use local variables only if it captures‬‬
‫‪them.‬‬

‫‪Names is a comma-separated list of names local to the‬‬


‫‪enclosing function.‬‬
‫]‪[names‬‬
‫‪By default, variables in the capture list are copied.‬‬
‫‪A name preceded by & is captured by reference.‬‬

‫‪Implicit by reference capture list.‬‬


‫]&[‬ ‫‪Entities from the enclosing function used in the‬‬
‫‪lambda body are used by reference.‬‬
Implicit by value capture list.
[=] Entities from the enclosing function used in the
lambda body are copied into the lambda body.

identifier_list is comma-separated list of zero or


more variables from the enclosing function.
These variables are captured by value; any implicitly
[&, identifier_list]
captured variables are captured by reference.
The names in identifier_list must not be preceded by
an &.

Variables included in the reference_list are captured


by reference; any implicitly captured variables are
[=, reference_list] captured by value.
The names in reference_list may not include this and
must be preceded by an &.

Capture by Reference ‫التقاط حسب املرجع‬

: ‫ فمثال‬. ‫أيضا تعريف المدا تلتقط متغريات بواسطة مرجع‬


ً ‫يمكننا‬

void fcn2() {
    size_t v1 = 42; // local variable
    // the object f2 contains a reference to v1
    auto f2 = [&v1] { return v1; };
    v1 = 0;
    auto j = f2(); } // j is 0; f2 refers to v1; it doesn't store it

.‫ كمرجع‬v1 ‫ إلى أنه يجب التقاط‬v1 ‫يشري & قبل‬ •


.‫فمتغري ملتقط بواسطة مرجع يترصف كأي مرجع آخر‬ •
.‫ فإننا نستخدم كائناً يرتبط به ذلك املرجع‬، ‫عندما نستخدم املتغري داخل بنية الالمدا‬ •
.v1 ‫ فإنها تُعيد قيمة كائن يشري إليه‬، v1 ‫ عندما تُعيد الالمدا‬، ‫في هذه الحالة‬ •

.‫تواجه امللتقطات املرجعية نفس املشاكل والقيود اليت تواجهها املراجع املعادة‬
.‫ فيجب أن نتأكد من وجود الكائن املشار إليه في وقت تنفيذ الالمدا‬، ‫فإذا التقطنا متغريًا بواسطة مرجع‬ •
.‫ وتنتهي من الوجود بمجرد اكتمال الدالة‬.‫املتغريات امللتقطة بواسطة المدا عبارة عن متغريات محلية‬ •
، ‫فإذا كان من املمكن تنفيذ المدا بعد انتهاء الدالة‬ •
.‫فاملتغريات املحلية اليت يشري إليها االلتقاط لن تظل موجودة‬ •

.‫التقاطات املراجع رضورية في بعض األحيان‬


: ‫ نكتب عليها وحر ًفا الستخدامه كفاصل‬ostream ‫ مرجعاً على‬biggies ‫ قد نرغب أن تأخذ دالتنا‬، ً‫فمثال‬ •

void biggies(vector<string> &words, vector<string>::size_type sz,


‫{ )' ' = ‪ostream &os = cout, char c‬‬
‫‪    // code to reorder words as before‬‬
‫‪    // statement to print count revised to print to os‬‬
‫‪    for_each(words.begin(), words.end(),‬‬
‫} ;)} ;‪[&os, c](const string &s) { os << s << c‬‬

‫وبما أنه لن نتمكن من نسخ كائنات قنوات املخرجات ‪ ostream‬؛‬ ‫•‬


‫فالطريقة الوحيدة اللتقاط ‪ os‬هي بواسطة املرجع (أو من خالل مؤرش لـ ‪.)os‬‬ ‫•‬

‫عندما نقوم بتمرير المدا إلى دالة ‪ ،‬كما هو حال استدعاء ‪ ، for_each‬سيتم تنفيذ الالمدا على الفور‪.‬‬ ‫•‬
‫يعد التقاط ‪ os‬باملرجع أمرًا جي ًدا ‪ ،‬ألن املتغريات في ‪ biggies‬موجودة أثناء تشغيل ‪.for_each‬‬ ‫•‬

‫أيض ا إعادة المدا من دالة‪ .‬فقد تقوم الدالة بإعادة كائن قابل لالستدعاء مبارشة ‪،‬‬
‫ويمكننا ً‬
‫أو قد تُعيد كائنًا من فئة تحتوي على كائن قابل لالستدعاء كعضو بيانات‪.‬‬ ‫•‬
‫مرجعا ملتغري محلي ‪-‬‬
‫ً‬ ‫فإن كانت الدالة تُعيد المدا ‪ ،‬فإذن ‪ -‬ولنفس األسباب اليت تجعل دالة ال يجب أن تُعيد‬ ‫•‬
‫يجب أال تحتوي تلك الالمدا على التقاطات مرجعية‪.‬‬ ‫•‬

‫تحذير‬

‫عندما نلتقط متغريًا باملرجع ‪ ،‬يجب أن نتأكد من وجود املتغري في الوقت الذي يتم فيه تنفيذ الالمدا‪.‬‬

‫نصيحة‪ :‬حافظ على التقاطات الالمدا بسيطة‬

‫‪Advice: Keep Your Lambda Captures Simple‬‬

‫يقوم التقاط المدا بتخزين معلومات بني وقت إنشاء الالمدا ووقت تنفيذها ؛‬ ‫•‬
‫(أي عند تنفيذ الكود الذي يعرف الالمدا) والوقت (أو األوقات) اليت يتم فيها تنفيذ الالمدا نفسها‪.‬‬ ‫•‬
‫حيث يقع على عاتق املربمج مسؤولية التأكد من أن ‪:‬‬ ‫•‬
‫أي معلومات يتم التقاطها تحمل املعىن املقصود في كل مرة يتم فيها تنفيذ الالمدا‪.‬‬ ‫•‬

‫عاد ًة ما يكون التقاط متغري عادي ‪ -‬عدد صحيح أو سلسلة أو أي نوع آخر غري مؤرش ‪ -‬بواسطة قيمة‬ ‫•‬
‫أمرًا مبارشًا‪.‬‬
‫في هذه الحالة ‪ ،‬نحتاج فقط أن نهتم بما إذا كان املتغري يملك القيمة اليت نحتاجها عند التقاطه‪.‬‬ ‫•‬

‫مكررا ‪ ،‬أو التقطنا متغريًا بواسطة مرجع ‪،‬‬


‫ً‬ ‫إذا التقطنا مؤرشًا أو‬ ‫•‬
‫فيجب علينا أن نتأكد أن الكائن املرتبط بذلك املكرر أو املؤرش أو املرجع سيظل موجو ًدا ‪ ،‬كلما تم تنفيذ‬ ‫•‬
‫الالمدا‪.‬‬
‫عالوة على ذلك ‪ ،‬نحتاج أن نتأكد أن الكائن يملك القيمة املقصودة‪.‬‬ ‫•‬

‫قد يؤدي الكود الذي ينفذ بني وقت إنشاء الالمدا ووقت تنفيذه إلى تغيري قيمة الكائن الذي يؤرش عليه (أو‬ ‫•‬
‫يشري إليه ) التقاط الالمدا‪.‬‬
‫قد تكون قيمة الكائن في وقت التقاط املؤرش (أو املرجع) فيه هي ما أردناه‪.‬‬ ‫•‬
‫تماما‪.‬‬
‫ً‬ ‫لكن قد تكون قيمة هذا الكائن عند تنفيذ الالمدا مختلفة‬ ‫•‬

‫كقاعدة عامة ‪ ،‬يمكننا تجنب مشاكل االلتقاطات املحتملة عن طريق تقليل البيانات اليت نلتقطها‪.‬‬ ‫•‬
‫عالوة على ذلك ‪ ،‬إذا أمكن ‪ ،‬تجنب التقاط مؤرشات أو مراجع‪.‬‬ ‫•‬

‫‪Implicit Captures‬‬ ‫التقاطات ضمنية‬

‫بدال ً من رسد املتغريات اليت نريد استخدامها رصاحة من الدالة املتضمنة ‪،‬‬
‫يمكننا السماح للمرتجم باستنتاج أي متغريات سنستخدمها من الكود في بنية الالمدا‪.‬‬ ‫•‬
‫لتوجيه املرتجم الستنتاج قائمة االلتقاط ‪ ،‬نستخدم & أو = في قائمة االلتقاط‪.‬‬ ‫•‬
‫يخرب الـ & املرتجم أن يلتقط باملرجع ‪ ،‬و يقول الـ = أن القيم تلتقط بالقيمة‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬يمكننا إعادة كتابة الالمدا اليت مررناها لـ ‪: find_if‬‬ ‫•‬

‫‪// sz implicitly captured by value‬‬


‫)‪wc = find_if(words.begin(), words.end(), [=](const string &s‬‬
‫;)} ;‪                { return s.size() >= sz‬‬

‫لو أردنا التقاط بعض املتغريات بالقيمة وأخرى باملرجع ‪ ،‬فيمكننا مزج االلتقاط الضمين والرصيح‪:‬‬

‫‪void biggies(vector<string> &words, vector<string>::size_type sz,‬‬


‫{ )' ' = ‪             ostream &os = cout, char c‬‬
‫‪    // other processing as before‬‬
‫‪    // os implicitly captured by reference; c explicitly by value‬‬
‫)‪    for_each(words.begin(), words.end(), [&, c](const string &s‬‬
‫;)} ;‪{ os << s << c‬‬
‫‪    // os explicitly captured by reference; c implicitly by value‬‬
‫)‪    for_each(words.begin(), words.end(), [=, &os](const string &s‬‬
‫;)} ;‪{ os << s << c‬‬
‫}‬

‫عندما نمزج االلتقاطات الضمنية مع الرصيحة ‪ ،‬يجب أن يكون أول عنرص في قائمة االلتقاط إما & وإما = ‪.‬‬ ‫•‬
‫سيضبط هذا الرمز وضع االلتقاط االفرتايض على أنه بمرجع أو بقيمة ‪ ،‬على التوالي‪.‬‬ ‫•‬
‫وكذلك يجب أن تستخدم املتغريات امللتقطة رصاحة الشكل البديل‪ .‬بمعىن أنه ‪:‬‬ ‫•‬
‫إذا كان االلتقاط الضمين باملرجع (استخدام &) ‪ ،‬فيجب أن يتم التقاط املتغريات املسماة رصاحة بالقيمة ؛‬ ‫•‬
‫ومن ثم ال يجوز أن تسبق أسمائها عالمة &‪ .‬والعكس بالعكس ‪،‬‬ ‫•‬
‫فإذا كان االلتقاط الضمين بالقيمة (استخدام =) ‪ ،‬فيجب أن تكون املتغريات املسماة رصاحة مسبوقة بـ &؛‬ ‫•‬
‫لتشري إلى أنه سيتم التقاطها عن طريق املرجع‪.‬‬ ‫•‬

‫‪Mutable Lambdas‬‬ ‫المدا_ قابلة للتغيري‬

‫افرتاضيا ‪ ،‬قد ال تغري المدا_ قيمة متغري تنسخه بواسطة قيمة‪.‬‬


‫ً‬
‫فإذا رغبنا في تغيري قيمة متغري ملتقط ‪ ،‬فيجب أن نُتبِع قائمة املعلمات بكلمة ‪ :‬قابلة للتغيري ‪. mutable‬‬ ‫•‬
‫وﻻ يسمح أن تحذف الالمدا القابلة للتغيري قائمة املعلمات ‪:‬‬ ‫•‬

‫{ )(‪void fcn3‬‬
‫‪    size_t v1 = 42; // local variable‬‬
‫‪    // f can change value of variables it captures‬‬
‫;} ;‪    auto f = [v1] () mutable { return ++v1‬‬
‫;‪    v1 = 0‬‬
‫;)(‪    auto j = f‬‬ ‫‪} // j is 43‬‬

‫ﻻ تعتمد إمكانية تغيري متغري تم التقاطه باملرجع (كاملعتاد) ‪،‬‬ ‫•‬


‫إﻻ على ما إذا كان ذلك املرجع يشري لنوع ثابت أو غري ثابت ‪: const or non-const‬‬ ‫•‬

‫{ )(‪void fcn4‬‬
‫;‪    size_t v1 = 42‬‬ ‫‪// local variable‬‬
‫‪    // v1 is a reference to a non const variable‬‬
‫‪    // we can change that variable through reference inside f2‬‬
‫;} ;‪    auto f2 = [&v1] { return ++v1‬‬
‫;‪    v1 = 0‬‬
‫‪    auto j = f2(); } // j is 1‬‬

‫‪Specifying the Lambda Return Type‬‬ ‫تحديد نوع إعادة الالمدا‬

‫تحتوي الالمدا اليت كتبناها حىت اآلن على جملة ِ‬


‫أعد واحدة فقط‪ .‬نتيجة لذلك ‪ ،‬لم نضطر إلى تحديد نوع اإلعادة‪.‬‬
‫• افرتاضياً ‪ ،‬إذا احتوت بنية المدا_ على أي جمل بخالف ِ‬
‫أعد ‪،‬‬
‫فمن املفرتض أن تقوم الالمدا بإعادة الفراغ ‪.void‬‬ ‫•‬
‫ومثل الدوال األخرى اليت تُعيد فراغاً ‪ ،‬فإن الالمدا اليت تم استنتاجها لتعيد فراغاً قد ال تُعيد قيمة‪.‬‬ ‫•‬
‫كمثال بسيط ‪ ،‬قد نستخدم خوارزمية املكتبة تحويل_ ‪ transform‬و المدا ‪،‬‬ ‫•‬
‫الستبدال كل قيمة سالبة في تسلسل بقيمتها املطلقة ‪:‬‬ ‫•‬

‫‪transform(vi.begin(), vi.end(), vi.begin(),‬‬


‫;)} ;‪[](int i) { return i < 0 ? -i : i‬‬

‫تأخذ الدالة تحويل_ ثالثة مكررات وقابالً لالستدعاء‪.‬‬ ‫•‬


‫يشري أول مكررين إلى تسلسل مدخالت والثالث عبارة عن وجهة‪.‬‬ ‫•‬
‫ستستدعي الخوارزمية االستدعاء املحدد على كل عنرص في تسلسل املدخالت وتكتب النتيجة على الوجهة‪.‬‬ ‫•‬
‫كما هو الحال في هذا االستدعاء ‪ ،‬يمكن أن يكون مكرر الوجهة هو نفسه مكرر يشري إلى بداية املدخالت‪.‬‬ ‫•‬
‫وعندما يكون مكرر املدخالت ومكرر الوجهة متماثلني ‪،‬‬ ‫•‬
‫سيستبدل التحويل كل عنرص في نطاق املدخالت بنتيجة استدعاء القابل لالستدعاء على ذلك العنرص‪.‬‬ ‫•‬
‫في هذا االستدعاء ‪ ،‬مررنا المدا تعيد القيمة املطلقة ملعلمته‪.‬‬ ‫•‬
‫أعد وحيدة تُعيد النتيجة لتعبري رشطي‪.‬‬ ‫بنية الالمدا عبارة عن جملة ِ‬ ‫•‬
‫ال نحتاج لتحديد نوع اإلعادة ‪ ،‬ألن ذلك النوع يمكن استنتاجه من نوع العامل الرشطي‪.‬‬ ‫•‬
‫ظاهريا باستخدام جملة ‪ ، if‬فلن يتم تجميع كودنا ‪:‬‬
‫ً‬ ‫مع ذلك ‪ ،‬إذا كتبنا الربنامج املكافئ‬

‫‪// error: cannot deduce return type for lambda‬‬


‫‪transform(vi.begin(), vi.end(), vi.begin(),‬‬
‫;)} ;‪          [](int i) { if (i < 0) return -i; else return i‬‬

‫يستنتج إصدار الالمدا هذا نوع اإلعادة على أنه فراغ لكننا قمنا بإعادة قيمة‪.‬‬ ‫•‬
‫عندما نحتاج إلى تعريف نوع إعادة المدا ‪ ،‬يجب أن نستخدم نوع إعادة الحق ‪:‬‬ ‫•‬

‫‪transform(vi.begin(), vi.end(), vi.begin(),‬‬


‫;)} ;‪          [](int i) -> int { if (i < 0) return -i; else return i‬‬

‫في هذه الحالة ‪ ،‬وسيطة تحويل_ الرابعة عبارة عن المدا بقائمة التقاط فارغة ‪،‬‬ ‫•‬
‫وتأخذ معلمة وحيدة من نوع عدد صحيح وتُعيد قيمة من نوع عدد صحيح‪.‬‬ ‫•‬
‫بنية دالتها عبارة عن جملة ‪ if‬تُعيد القيمة املطلقة ملعلمتها‪.‬‬ ‫•‬

‫تمارين القسم ‪10.3.3‬‬

‫التمرين ‪:10.20‬‬
‫عد_إذا تسمى ‪.count_if‬‬
‫تعرف املكتبة خوارزمية ّ‬
‫‪ّ -‬‬
‫‪ -‬مثل أوجد_إذا ‪ ، find_if‬تأخذ هذه الدالة زوج مكررات لنطاق مدخالت ومحمولة تنطبق على كل عنرص في‬
‫النطاق املحدد‪.‬‬
‫‪ -‬يعرض ‪ count_if‬عدد مرات صحة املحمولة‪.‬‬
‫‪ -‬استخدم ‪ count_if‬إلعادة كتابة جزء برنامجنا الذي يحسب عدد الكلمات األكرب من الطول ‪.6‬‬

‫التمرين ‪:10.21‬‬
‫محليا ويتناقص ذلك املتغري حىت يصل إلى ‪.0‬‬
‫ً‬ ‫‪ -‬اكتب المدا تلتقط متغرياً عدداً صحيحاً‬
‫‪ -‬بمجرد أن يصبح املتغري صفرًا ‪ ،‬يجب أال تنقص املتغري استدعاءات إضافية‪.‬‬
‫منطقيا يشري إلى ما إذا كان املتغري امللتقط هو ‪.0‬‬
‫ً‬ ‫‪ -‬ينبغي أن تُعيد الالمدا‬

‫‪Binding Arguments‬‬ ‫‪ .10.3.4‬الوسيطات امللزمة‬

‫تعد تعبريات المدا أكرث فائدة لعمليات بسيطة ال نحتاج إلى استخدامها في أكرث من مكان أو مكانني‪.‬‬
‫أما إذا احتجنا إلى إجراء نفس العملية في عدة أماكن ‪،‬‬ ‫•‬
‫فينبغي عاد ًة تعريف دالة بدال ً من كتابة نفس تعبري الالمدا عدة مرات‪.‬‬ ‫•‬
‫وباملثل ‪ ،‬إذا كانت عملية ما تتطلب عدة جمل ‪ ،‬فمن األفضل عاد ًة استخدام دالة‪.‬‬ ‫•‬

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

‫مع ذلك ‪ ،‬فليس من السهل كتابة دالة تستبدل المدا تلتقط متغريات محلية‪.‬‬
‫فمثالً ‪ ،‬قارنت الالمدا اليت استخدمناها في استدعاء ‪( find_if‬قارنت) سلسلة بحجم معني‪.‬‬ ‫•‬
‫يمكننا بسهولة كتابة دالة للقيام بنفس العمل ‪:‬‬ ‫•‬

‫)‪bool check_size(const string &s, string::size_type sz‬‬


‫} ;‪{ return s.size() >= sz‬‬

‫مع ذلك ‪ ،‬لن يمكننا استخدام هذه الدالة كوسيطة لـ ‪.find_if‬‬ ‫•‬
‫فكما رأينا ‪ ،‬فإن ‪ find_if‬تأخذ محمولة أحادية ‪ ،‬لذلك يجب أن يأخذ قابل االستدعاء الذي تم تمريره إلى‬ ‫•‬
‫‪ find_if‬وسيطة وحيدة‪.‬‬
‫تستخدم الالمدا الذي مررته ‪ biggies‬إلــى ‪ find_if‬قائمة التقاطها لتخزين ‪.sz‬‬ ‫•‬
‫من أجل استخدام ‪ check_size‬في مكان تلك الالمدا ‪ ،‬علينا إيجاد طريقة لتمرير وسيط إلى املعلمة ‪.sz‬‬ ‫•‬

‫‪The Library bind Function‬‬ ‫دالة املكتبة ربط_‬

‫يمكننا حل مشكلة تمرير وسيطة حجم إلى ‪، check_size‬‬


‫وذلك باستخدام دالة مكتبة جديدة تسمى ربط_ ‪ ، bind‬واليت يتم تعريفها في العنوان ‪.functional‬‬ ‫•‬
‫يمكن اعتبار الدالة ربط_ بمثابة مكيف دالة ألغراض عامة‪.‬‬ ‫•‬
‫استدعاءا جدي ًدا "يتكيف" مع قائمة معلمات الكائن األصلي‪.‬‬
‫ً‬ ‫حيث تأخذ كائنًا قابالً لالستدعاء وتولد‬ ‫•‬
‫النموذج العام الستدعاء ربط_ هو ‪:‬‬

‫;)‪auto newCallable = bind(callable, arg_list‬‬

‫حيث ‪:‬‬
‫يعترب ‪ newCallable‬نفسه كائن قابل لالستدعاء‬ ‫•‬
‫و ‪ arg_list‬قائمة وسيطات مفصولة بفاصلة تتوافق مع معلمات قابل االستدعاء املحدد‪.‬‬ ‫•‬
‫بمعىن أنه عند استدعاء ‪، newCallable‬‬ ‫•‬
‫فستقوم ‪ newCallable‬باستدعاء ‪ ، callable‬ممررة الوسيطات في ‪. arg_list‬‬ ‫•‬

‫صحيحا‪.‬‬
‫ً‬ ‫قد تتضمن الوسيطات في ‪ arg_list‬أسماء من النموذج _‪ ، n‬حيث تمثل ‪ n‬عد ًدا‬
‫هذه الوسيطات هي " عنارص نائبة ‪ " placeholders‬تمثل معلمات ‪. newCallable‬‬ ‫•‬
‫إنها تقف "في مكان" الوسيطات اليت سيتم تمريرها إلى ‪. newCallable‬‬ ‫•‬
‫الرقم ‪ n‬يمثل موضع املعلمة في االستدعاء املولّ د ‪:‬‬ ‫•‬
‫فـ _‪ 1‬هو أول معلمة في ‪ ، newCallable‬و _‪ 2‬هي املعلمة الثانية ‪ ،‬وهكذا دواليك‪.‬‬ ‫•‬

‫‪Binding the sz Parameter of check_size‬‬ ‫ربط املعلمة ‪ sz‬مع ‪check_size‬‬


‫كمثال بسيط ‪ ،‬سنستخدم الربط ‪ bind‬لتوليد كائن يستدعي ‪ check_size‬بقيمة ثابتة ملعلمة ‪ sz‬كالتالي ‪:‬‬

‫‪// check6 is a callable object that takes one argument of type string‬‬
‫‪// and calls check_size on its given string and value 6‬‬
‫;)‪auto check6 = bind(check_size, _1, 6‬‬

‫استدعاء الربط هذا لديه عنرص نائب واحد فقط ‪ ،‬ما يعين أن ‪ check6‬تأخذ وسيطة وحيدة‪.‬‬ ‫•‬
‫يظهر العنرص النائب أوال ً في ‪، arg_list‬‬ ‫•‬
‫ما يعين أن املعلمة في ‪ check6‬تتوافق مع املعلمة األولى لـ ‪.check_size‬‬ ‫•‬
‫تلك املعلمة عبارة عن سلسلة ثابتة مرجعية ‪،‬‬ ‫•‬
‫أيضا سلسلة ثابتة مرجعية‪.‬‬
‫ما يعين أن املعلمة في ‪ check6‬هي ً‬ ‫•‬
‫وبالتالي ‪ ،‬يجب أن يمرر استدعاء ‪ check6‬وسيطة من نوع ‪، string‬‬ ‫•‬
‫واليت ستمرر ‪ check6‬كأول وسيط لـ ‪.check_size‬‬ ‫•‬

‫الوسيطة الثانية في ‪( arg_list‬أي الثالثة لربط_) هي القيمة ‪.6‬‬


‫هذه القيمة مربوطة باملعلمة الثانية ‪.check_size‬‬ ‫•‬
‫فعندما نسمي ‪ ، check6‬سوف نمرر ‪ 6‬كمتغري ثانٍ لـ ‪: check_size‬‬ ‫•‬

‫;"‪string s = "hello‬‬
‫;)‪bool b1 = check6(s‬‬ ‫)‪// check6(s) calls check_size(s, 6‬‬

‫باستخدام ربط ‪ ،‬يمكننا استبدال استدعاءنا األصلية مبين‪-‬على‪-‬المدا لـ ‪find_if‬‬

‫)‪auto wc = find_if(words.begin(), words.end(), [sz](const string &a‬‬

‫بإصدار يستخدم ‪: check_size‬‬

‫;))‪auto wc = find_if(words.begin(), words.end(), bind(check_size, _1, sz‬‬

‫سيولد هذا االستدعاء لربط_ كائنًا قابالً لالستدعاء يربط الوسيطة الثانية من ‪ check_size‬بقيمة ‪.sz‬‬ ‫•‬
‫عندما تستدعي ‪ find_if‬هذا الكائن على سالسل في كلمات ‪،‬‬ ‫•‬
‫فإن هذه االستدعاءات بدورها ستستدعي ‪ check_size‬ممررة السلسلة املعطاة و ‪.sz‬‬ ‫•‬
‫لذلك ‪ ،‬سوف تستدعي ‪( find_if‬بشكل فعال) ‪ check_size‬على كل سلسلة في نطاق املدخالت‬ ‫•‬
‫ويقارن حجم هذه السلسلة بـ ‪.sz‬‬

‫‪Using placeholders Names‬‬ ‫استخدام أسماء العنارص النائبة‬

‫يتم تعريف األسماء _‪ n‬في مساحة اسم تسمى العنارص النائبة ‪. placeholders‬‬
‫يتم تعريف مساحة االسم نفسها داخل مساحة االسم ‪. std‬‬ ‫•‬
‫والستخدام هذه األسماء ‪ ،‬يجب علينا توفري األسماء ملساحيت اﻻسم‪.‬‬ ‫•‬
‫كما هو الحال مع األمثلة األخرى ‪ ،‬تفرتض استدعاءاتنا لربط_ وجود إعالنات ‪ using‬مناسبة‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬إعالن ‪ using‬لـ _‪ 1‬هو ‪:‬‬ ‫•‬

‫;‪using std::placeholders::_1‬‬

‫يوضح هذا اإلعالن أننا نستخدم االسم _‪ ، 1‬الذي تم تعريفه في مساحة االسم ‪،placeholders‬‬ ‫•‬
‫والذي تم تعريفه بنفسه في مساحة االسم ‪. std‬‬ ‫•‬

‫يجب أن نقدم إعالن ‪ using‬منفصل لكل اسم عنرص نائب نستخدمه‪.‬‬


‫كتابة مثل هذه اإلعالنات يمكن أن تكون مملة وعرضة للخطأ‪.‬‬ ‫•‬
‫فبدال ً من اإلعالن عن كل عنرص نائب بشكل منفصل ‪،‬‬ ‫•‬
‫يمكننا استخدام نموذج مختلف من ‪ using‬سنغطيه بمزيد من التفصيل في الفقرة ‪ . 18٫2٫2‬هذا النموذج ‪:‬‬ ‫•‬

‫;‪using namespace namespace_name‬‬

‫يقول أننا نريد أن نجعل جميع األسماء من ‪ namespace_name‬متاحة لربنامجنا‪ .‬فمثال ‪:‬‬

‫;‪using namespace std::placeholders‬‬

‫يجعل جميع األسماء املعرفة بواسطة ‪ placeholders‬قابلة لالستخدام‪.‬‬ ‫•‬


‫مثل دالة الربط ‪ ،‬يتم تعريف مساحة اسم ‪ placeholders‬في العنوان ‪.functional‬‬ ‫•‬

‫‪Arguments to bind‬‬ ‫وسيطات ربط‬

‫كما رأينا ‪ ،‬يمكننا استخدام ربط إلصالح القيمة ملعلمة‪.‬‬


‫بشكل أكرث عمومية ‪ ،‬يمكننا استخدام ربط لربط أو إعادة ترتيب املعلمات في القابل لالستدعاء املحدد‪.‬‬ ‫•‬
‫فمثالً ‪ ،‬بافرتاض أن ‪ f‬كائن قابل لالستدعاء لديه خمس معلمات ‪ ،‬فإن االستدعاء التالي لربط_ ‪:‬‬ ‫•‬

‫‪// g is a callable object that takes two arguments‬‬


‫;)‪auto g = bind(f, a, b, _2, c, _1‬‬

‫يولد قابل استدعاء جدي ًدا يأخذ وسيطتني ‪ ،‬يمثلهما العنرصان النائبان _‪ 2‬و _‪.1‬‬ ‫•‬
‫سوف يمرر القابل لالستدعاء الجديد وسيطاته الخاصة باعتباره الوسيط الثالث والخامس لـ ‪.f‬‬ ‫•‬
‫تُربط الوسيطات األولى والثانية والرابعة لـ ‪ f‬بالقيم املحددة ‪ a ،‬و ‪ b‬و ‪ c‬على التوالي‪.‬‬ ‫•‬

‫تُربط وسيطات ‪ g‬بشكل موضعي بالعنارص النائبة‪.‬‬ ‫•‬


‫أي أن وسيطة ‪ g‬األولى مربوطة بـ _‪ ، 1‬والوسيطة الثانية مربوطة بـ _‪.2‬‬ ‫•‬
‫وهكذا ‪ ،‬عندما نستدعي ‪ ، g‬سيتم تمرير وسيطة ‪ g‬األولى باعتبارها وسيطة ‪ f‬األخرية ؛‬ ‫•‬
‫بينما سيتم تمرير وسيطة ‪ g‬الثانية كوسيطة ‪ f‬الثالثة‪ .‬في الواقع ‪ ،‬هذا االستدعاء لربط يرسم خريطة‬ ‫•‬
‫)‪g(_1, _2‬‬

‫إلى‬
‫)‪f(a, b, _2, c, _1‬‬

‫جنبا إلى جنب مع‬


‫ً‬ ‫وهذا يعين أن ‪ ،‬استدعاء ‪ g‬سيستدعي ‪ f‬باستخدام وسيطات ‪ g‬للعنارص النائبة‬ ‫•‬
‫الوسيطات املربوطة ‪ a ،‬و ‪ b‬و ‪.c‬‬
‫فعلى سبيل املثال ‪ ،‬استدعاء )‪ g(X ، Y‬سيستدعي‬ ‫•‬
‫)‪f(a, b, Y, c, X‬‬

‫‪Using to bind to Reorder Parameters‬‬ ‫استخدام ربط إلعادة ترتيب املعلمات‬

‫كمثال أكرث واقعية الستخدام ربط إلعادة ترتيب الوسيطات ‪ ،‬يمكننا استخدام ربط لعكس معىن ‪isShorter‬‬
‫بكتابة‬

‫‪// sort on word length, shortest to longest‬‬


‫;)‪sort(words.begin(), words.end(), isShorter‬‬
‫‪// sort on word length, longest to shortest‬‬
‫;))‪sort(words.begin(), words.end(), bind(isShorter, _2, _1‬‬

‫في أول استدعاء ‪ ،‬عندما احتاجت فرز ملقارنة العنرصين ‪ A‬و ‪ ، B‬فإنها استدعت )‪.isShorter(A ، B‬‬ ‫•‬
‫أما في االستدعاء الثاني لفرز ‪ ،‬تم مبادلة وسيطات ‪.isShorter‬‬ ‫•‬
‫وفي تلك الحالة ‪ ،‬عندما تقارن فرز بني العنارص ‪،‬‬ ‫•‬
‫فسيكون األمر كما لو أن فرز استدعت )‪.isShorter(B ، A‬‬ ‫•‬

‫‪Binding Reference Parameters‬‬ ‫معلمات مرجعية مربوطة‬

‫افرتاضياً ‪ ،‬يتم نسخ وسيطات ربط اليت ليست عنارص نائبة إلى الكائن القابل لالستدعاء الذي تعيده ربط_‪.‬‬
‫• مع ذلك ‪ ،‬وكما هو الحال مع الالمدا ‪ ،‬فأحيانا يكون لدينا وسيطات نريد ربطها ‪،‬‬
‫لكننا نريد تمريرها بواسطة مرجع أو قد نرغب في ربط وسيطة لديها نوع ال يمكننا نسخه‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬الستبدال الالمدا اليت التقطت ‪ ostream‬باملرجع ‪:‬‬

‫‪// os is a local variable referring to an output stream‬‬


‫‪// c is a local variable of type char‬‬
‫‪for_each(words.begin(), words.end(),‬‬
‫;)} ;‪[&os, c](const string &s) { os << s << c‬‬

‫يمكننا بسهولة كتابة دالة للقيام بنفس العمل ‪:‬‬

‫)‪ostream &print(ostream &os, const string &s, char c‬‬


‫{‬ ‫;‪return os << s << c‬‬ ‫}‬

‫ومع ذلك ‪ ،‬ال يمكننا استخدام ربط مبارشة الستبدال التقاط ‪: os‬‬

‫‪// error: cannot copy os‬‬


‫;))' '‪for_each(words.begin(), words.end(), bind(print, os, _1,‬‬
‫ألن ‪ bind‬ينسخ وسيطاته وال يمكن نسخ ‪.ostream‬‬ ‫•‬
‫فإذا أردنا تمرير كائن لربطه دون نسخه ‪ ،‬فيتوجب علينا استخدام دالة املكتبة ‪: ref‬‬ ‫•‬

‫;))' ' ‪for_each(words.begin(), words.end(), bind(print, ref(os), _1,‬‬

‫تُعيد الدالة ‪ ref‬كائنًا يحتوي على املرجع املحدد ويكون هو نفسه قاباًل للنسخ‪.‬‬ ‫•‬
‫مرجعا لـثابت‪.‬‬
‫ً‬ ‫أيضا الدالة ‪ cref‬اليت تولد فئة تحمل‬
‫هناك ً‬ ‫•‬
‫ومثل ربط_ ‪ ،‬يتم تعريف داليت ‪ ref‬و ‪ cref‬في عنوان الدوال ‪.functional‬‬ ‫•‬

‫التوافق مع اإلصدارات السابقة‪ :‬وسيطات الربط‬

‫‪Backward Compatibility: Binding Arguments‬‬

‫قدمت إصدارات يس‪ ++‬اﻷقدم مجموعة أقسام محدودة أكرث ‪ -‬لكن أكرث تعقي ًدا ‪ -‬لربط الوسيطات بالدوال‪.‬‬ ‫•‬
‫فعرفت املكتبة دالتني باسم ‪ bind1st‬و ‪.bind2nd‬‬
‫ّ‬ ‫•‬

‫ومثل ربط_ ‪ ،‬تأخذ هاتني الدالتني دالة وتولدان كائنًا جدي ًدا قابالً لالستدعاء ‪،‬‬ ‫•‬
‫يستدعي الدالة املحددة بإحدى معلماتها املربوطة بقيمة معينة‪.‬‬ ‫•‬

‫مع ذلك ‪ ،‬يمكن لهاتني الدالتني ربط املعلمة األولى أو الثانية فقط ‪ ،‬على التوالي‪.‬‬ ‫•‬
‫ونظرًا ألن فائدتها محدودة للغاية ‪ ،‬فقد تم إهمالها في املعيار الجديد‪.‬‬ ‫•‬
‫املزية املهملة هي املزية اليت قد ال يتم دعمها في إصدارات مستقبلية‪.‬‬ ‫•‬

‫ينبغي أن تستخدم برامج يس‪ ++‬الحديثة ربط ‪.bind‬‬

‫تمارين القسم ‪10.3.4‬‬

‫التمرين ‪:10.22‬‬
‫أعد كتابة الربنامج لحساب الكلمات ذات الحجم ‪ 6‬أو أقل باستخدام الدوال بدال ً من المدا‪.‬‬

‫التمرين ‪:10.23‬‬
‫كم عدد الوسيطات اليت تأخذها ربط؟‬

‫التمرين ‪:10.24‬‬
‫استخدم ‪ bind and check_size‬إليجاد العنرص األول في متجه أرقام صحيحة الذي له قيمة أكرب من طول‬
‫قيمة سلسلة محددة‪.‬‬

‫التمرين ‪ :10.25‬في تدريبات الفقرة ‪ 10.3.2‬كتبت نسخة من ‪ biggies‬تستخدم التقسيم‪ .‬أعد كتابة هذه الدالة‬
‫باستخدام ‪ check_size‬والربط‪.‬‬
‫‪ 10٫4‬مراجــــــــــعة املـــــــــكــــــــــررات‬
‫‪10.4 Revisiting Iterators‬‬

‫إضافة إلى املكررات اليت تم تعريفها لكل من الحاويات ‪،‬‬


‫تعرف املكتبة عدة أنواع مكررات إضافية في عنوان املكرر ‪ . iterator‬وتتضمن هذه املكررات‬
‫ّ‬ ‫•‬
‫مكررات اﻹدراج ‪: Insert iterators‬‬
‫هذه املكررات مرتبطة بحاوية ويمكن استخدامها إلدراج عنارص إلى الحاوية‪.‬‬ ‫•‬
‫مكررات القناة ‪: Stream iterators‬‬
‫هذه املكررات مرتبطة بقنوات املدخالت أو املخرجات ويمكن استخدامها لتتكرر عرب قنواتها املرتبطة‪.‬‬ ‫•‬
‫املكررات العكسية ‪: Reverse iterators‬‬
‫تتحرك للخلف بدال ً من األمام‪ .‬تحتوي حاويات املكتبة ‪ ،‬عدا القائمة_اﻷمامية على مكررات عكسية‪.‬‬ ‫•‬
‫مكررات الحركة ‪: Move iterators‬‬
‫هذه مكررات ذات أغراض خاصة تحرك عنارصها بدال ً من نسخها‪.‬‬ ‫•‬
‫سنقوم بتغطية مكررات الحركة في الفصل الثالث عرش فقرة ‪.6.2‬‬ ‫•‬

‫‪10.4.1 Insert Iterators‬‬ ‫‪ .10.4.1‬مكررات اﻹدراج‬

‫مكررا يضيف عنارص إلى الحاوية املحددة‪.‬‬


‫ً‬ ‫اإلدراج عبارة عن مكيف مكرر يأخذ حاوية وينتج‬
‫فعندما نقوم بتعيني قيمة من خالل مكرر إدراج ‪،‬‬ ‫•‬
‫يقوم املكرر باستدعاء عملية حاوية لتضيف عنرصاً في موضع محدد في الحاوية املحددة‪.‬‬ ‫•‬
‫يتم رسد العمليات اليت تدعمها هذه املكررات في الجدول ‪. 10.2‬‬ ‫•‬

‫الجدول ‪ .10.2‬عمليات مكرر اإلدراج‬

‫‪Inserts the value t at the current position denoted by it.‬‬


‫‪Depending on the kind of insert iterator, and assuming c‬‬
‫‪it = t‬‬ ‫‪is the container to which is bound, calls c.push_back(t),‬‬
‫‪c.push_front(t) or c.insert(t,p) where p is the iterator‬‬
‫‪position given to inserter.‬‬

‫‪*it, ++it,‬‬ ‫‪These operation exist but do nothing to it.‬‬


‫‪it++‬‬ ‫‪Each operator returns it.‬‬

‫الـمد ِرجات‪ .‬تختلف كل منها عن األخريات فيما يتعلق بمكان إدراج العنارص ‪:‬‬
‫هناك ثالثة أنواع من ُ‬
‫مكررا يستخدم دفع_للخلف ‪.Push_back‬‬
‫ً‬ ‫ُمدرج_خلف ‪ : back_inserter‬ينئش‬ ‫•‬
‫مكررا يستخدم دفع_للمقدمة ‪.push_front‬‬
‫ً‬ ‫ُمدرج_مقدمة ‪ : front_inserter‬ينئش‬ ‫•‬
‫مكررا يستخدم إدراج_ ‪ . insert‬تأخذ هذه الدالة وسيطة ثانية ‪،‬‬ ‫ً‬ ‫ُمدرج_ ‪ : inserter‬ينئش‬ ‫•‬
‫مكرر ا في الحاوية املحددة‪ .‬يتم إدراج العنارص قبل العنرص املشار إليه باملكرر املحدد‪.‬‬
‫ً‬ ‫واليت يجب أن تكون‬ ‫•‬
‫ملحوظة‬

‫لن يمكننا استخدام ُمدرج_مقدمة إال لحاوية تملك عضو دفع_للمقدمة ‪.push_front‬‬ ‫•‬
‫وباملثل ‪ ،‬ال يمكن استخدام ُمدرج_خلف إال على حاوية تملك دفع_للخلف ‪.push_back‬‬ ‫•‬

‫من املهم أن نفهم أنه عندما نستدعي مدرج_ )‪، inserter(c, iter‬‬ ‫•‬
‫نحصل على مكرر يقوم ‪ ،‬عند استخدامه تباعاً ‪ ،‬بإدراج عنارص قبل املشار إليه في األصل بواسطة ‪.iter‬‬ ‫•‬
‫مكررا تم إنشاؤه بواسطة ُمدرج_ ‪ ،‬فإن تعييناً مثل‬
‫ً‬ ‫بمعىن أنه ‪ ،‬إذا كان ‪it‬‬ ‫•‬

‫;‪* it = va1‬‬

‫سيترصف مثل‬

‫‪it = c.insert(it, val); // it points to newly added element‬‬


‫‪++it; // increment it so that it denotes same element as before‬‬

‫تماما عن الذي تم إنشاؤه بواسطة ُمدرج_‪.‬‬


‫ً‬ ‫يترصف مكرر تم إنشاؤه بواسطة ُمدرج_مقدمة بشكل مختلف‬ ‫•‬
‫دائما إدراج العنارص قبل أول عنرص في الحاوية‪.‬‬
‫ً‬ ‫فعندما نستخدم ُمدرج_مقدمة ‪ ،‬يتم‬ ‫•‬
‫فحىت لو كان املوضع الذي نمرره إلى ُمدرج_ يشري مبدئياً إلى أول عنرص ‪،‬‬ ‫•‬
‫فبمجرد إدراج عنرص أمامه ‪ ،‬فلن يعود ذلك العنرص في مقدمة الحاوية ‪:‬‬ ‫•‬

‫;}‪list<int> 1st = {1,2,3,4‬‬


‫;‪list<int> lst2, lst3‬‬ ‫‪// empty lists‬‬
‫‪// after copy completes, 1st2 contains 4 3 2 1‬‬
‫;))‪copy(1st.cbegin(), lst.cend(), front_inserter(lst2‬‬
‫‪// after copy completes, 1st3 contains 1 2 3 4‬‬
‫;)))(‪copy(1st.cbegin(), lst.cend(), inserter(lst3, lst3.begin‬‬

‫عندما نستدعي )‪ ، front_inserter(c‬نحصل على مكرر إدراج يستدعي تباعاً دفع_للمقدمة‪.‬‬ ‫•‬
‫وكل عنرص يتم إدراجه ‪ ،‬سيصبح العنرص األول الجديد في ‪.c‬‬ ‫•‬
‫مكررا يعكس ترتيب التسلسل الذي يُدرجه ؛‬
‫ً‬ ‫لذلك ‪ ،‬ينتج ُمدرج_مقدمة‬ ‫•‬
‫ومدرج_خلف ذلك‪.‬‬
‫بينما ﻻ يفعل ُمدرج_ ُ‬ ‫•‬

‫تمارين القسم ‪10.4.1‬‬

‫التمرين ‪:10.26‬‬
‫ارشح االختالفات بني األنواع الثالثة ملكررات اإلدراج‪.‬‬

‫التمرين ‪:10.27‬‬
‫‪ -‬باإلضافة إلى "فريد_ ‪ ، "unique‬تعرف املكتبة دالة تسمى "نسخ_فريد ‪"unique_copy‬‬
‫مكررا ثالثًا يشري إلى الوجهة اليت يتم نسخ العنارص الفريدة إليها‪.‬‬
‫ً‬ ‫‪ -‬تأخذ‬
‫برنامجا يستخدم ‪ unique_copy‬لنسخ العنارص الفريدة من متجه إلى قائمة فارغة أولياً‪.‬‬
‫ً‬ ‫‪ -‬اكتب‬

‫التمرين ‪:10.28‬‬
‫متجها يحمل القيم من ‪ 1‬إلى ‪ 9‬في ثالث حاويات أخرى‪.‬‬
‫ً‬ ‫‪ -‬انسخ‬
‫ومدرجاً خلفياً ‪ ،‬ومدرجا أماميا ‪ ،‬على الرتتيب إلضافة عنارص إلى هذه الحاويات‪.‬‬
‫‪ -‬استخدم ُمدرجاً ‪ُ ،‬‬
‫‪ -‬توقع كيف يختلف تسلسل املخرجات حسب نوع املُدرج وتحقق من تنبؤاتك عن طريق تشغيل برامجك‪.‬‬

‫‪10.4.2 iostream Iterators‬‬ ‫‪ .10.4.2‬مكررات قنوات املدخالت واملخرجات‬

‫على الرغم من أن أنواع قناة املدخالت واملخرجات ليست حاويات ‪،‬‬


‫إﻻ أن هناك مكررات يمكن استخدامها مع كائنات من أنواعها‪.‬‬ ‫•‬
‫يقرأ مكرر قناة_املدخالت (الجدول ‪ )10.3‬إلى قناة_املدخالت ‪،‬‬ ‫•‬
‫ويكتب مكرر قناة_املخرجات (الجدول ‪ ) 10.4‬على قناة املخرجات‪.‬‬ ‫•‬
‫تعامل هذه املكررات القناة املقابلة لها كأنها سلسلة عنارص من نوع محدد‪.‬‬ ‫•‬
‫باستخدام مكرر القناة ‪ ،‬يمكننا استخدام خوارزميات شاملة لقراءة بيانات من أو كتابتها على كائنات القناة‪.‬‬ ‫•‬

‫الجدول ‪ .10.3‬عمليات مكرر قناة_املدخالت‬

‫‪in reads values of type T from input‬‬


‫;)‪istream_iterator<T>in(is‬‬
‫‪stream is.‬‬

‫‪Off-the-end iterator for an‬‬


‫;‪istream_iterator<T>end‬‬ ‫‪istream_iterator that reads values of type‬‬
‫‪T.‬‬

‫‪in1 and in2 must read the same type.‬‬


‫‪in1 == in2‬‬
‫‪They are equal if they are both the end value or are bound‬‬
‫‪in1 != in2‬‬
‫‪to the same input stream.‬‬

‫‪*in‬‬ ‫‪Return the value read from the stream.‬‬

‫‪in→mem‬‬ ‫‪Synonym for (*in).mem.‬‬

‫>> ‪Reads the next value from the input stream using the‬‬
‫‪operator for the element type.‬‬
‫‪++in, in++‬‬ ‫‪As usual, the prefix version returns a reference to the‬‬
‫‪incremented iterator.‬‬
‫‪The postfix version returns the old value.‬‬

‫الجدول ‪ .10.4‬عمليات مكرر قناة_املخرجات‬


out writes value of type T to output
ostream_iterator<T>out(os);
stream os.

out writes value of type T followed by


d to output stream os.
ostream_iterator<T>out(os,d);
d points to a null-terminated character
array.

Writes val to the ostream to which out is bound using


the << operator.
Out = val
Val must have a type that is compatible with the type
that out can write.

*out, ++out, These operations exist but do nothing to out.


out++ Each operator returns out.

Operations on istream_iterators ‫العمليات على مكررات قناة_املدخالت‬

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

istream_iterator<int> int_it(cin); // reads ints from cin


istream_iterator<int> int_eof; // end iterator value
ifstream in("afile");
istream_iterator<string> str_it(in); // reads strings from "afile"

:‫ يمكننا استخدام مكرر قناة_املدخالت لقراءة املدخالت القياسية إلى متجه‬، ‫كمثال‬

istream_iterator<int> in_iter(cin); // read ints from cin


istream_iterator<int> eof; // istream “end” iterator
while (in_iter != eof) // while there's valid input to read
    // postfix increment reads stream and returns old value of iterator
    // we dereference that iterator to get previous value read from stream
    vec.push_back(*in_iter++);

.vec ‫ وتخزن ما تمت قراءته في‬، cin ‫تقرأ هذه الحلقة أعداداً صحيحة من‬ •
.eof‫ مماثلة لـ‬in_iter ‫ تتحقق الحلقة ما إذا كانت‬، ‫وفي كل تكرار‬ •
.‫ والذي يستخدم كمكرر ما بعد النهاية‬، ‫تم تعريف ذلك املكرر على أنه مكرر قناة_مدخالت فارغ‬ •
‫مكرر مرتبط بقناة سيساوي مكرر النهاية بمجرد أن تصادف القناة املرتبط به نهاية ملف أو تواجه خطأ في‬ •
‫املدخالت أو املخرجات‪.‬‬

‫الجزء األصعب من هذا الربنامج هو وسيطة ‪ ، push_back‬واليت تستخدم عوامل إلغاء مرجع وتزايد الحقة‪.‬‬
‫تماما مثل تعابري أخرى كتبناها تجمع بني إلغاء مرجعية وتزايد الحق‪.‬‬
‫ً‬ ‫يعمل هذا التعبري‬ ‫•‬
‫يعمل الزتايد الالحق على تقدم القناة عرب قراءة القيمة التالية لكنها تُعيد قيمة املكرر القديمة‪.‬‬ ‫•‬
‫تحتوي تلك القيمة القديمة على القيمة السابقة املقروءة من القناة‪.‬‬ ‫•‬
‫نلغي املرجع عن ذلك املكرر لنحصل على تلك القيمة‪.‬‬ ‫•‬
‫األكرث فائدة هو أنه يمكننا إعادة كتابة هذا الربنامج كالتالي ‪:‬‬

‫;‪istream_iterator<int> in_iter(cin), eof‬‬ ‫‪// read ints from cin‬‬


‫;)‪vector<int> vec(in_iter, eof‬‬ ‫‪// construct vec from an iterator range‬‬

‫نحن هنا نبين ‪ vec‬من زوج مكررات تشري إلى مجموعة من العنارص‪.‬‬ ‫•‬
‫هذه املكررات عبارة عن مكررات قناة_املدخالت ‪،‬‬ ‫•‬
‫ما يعين أنه يتم الحصول على النطاق من خالل قراءة القناة املرتبطة‪.‬‬ ‫•‬
‫ٍ‬
‫مدخالت ليس بعدد صحيح‪.‬‬ ‫يقرأ هذا املُنئش ‪ cin‬حىت يصل لنهاية امللف أو يصادف‬ ‫•‬
‫يتم استخدام العنارص اليت تتم قراءتها لبناء ‪.vec‬‬ ‫•‬

‫استخدام مكررات القناة مع الخوارزميات‬


‫‪Using Stream Iterators with the Algorithms‬‬

‫نظرًا ألن الخوارزميات تعمل من ناحية عمليات املكرر ‪ ،‬وﻷن مكررات القناة تدعم على األقل بعض عمليات املكرر ‪،‬‬
‫فبإمكاننا استخدام مكررات القناة مع بعض الخوارزميات على األقل‪.‬‬ ‫•‬
‫سرنى في الفقرة ‪ 10.5.1‬كيف نعرف أي الخوارزميات اليت يمكن استخدامها مع مكررات القناة‪.‬‬ ‫•‬
‫كمثال ‪ ،‬يمكننا استدعاء تجميع_ ‪ accumulate‬مع زوج من مكررات قناة_املدخالت ‪:‬‬ ‫•‬

‫;‪istream_iterator<int> in(cin), eof‬‬


‫;‪cout << accumulate(in, eof, 0) << endl‬‬

‫سينئش هذا االستدعاء مجموع القيم املقروءة من املدخالت القياسية‪ .‬إذا كانت املدخالت إلى هذا الربنامج هي‬

‫‪23‬‬ ‫‪109 45‬‬ ‫‪89‬‬ ‫‪6‬‬ ‫‪34‬‬ ‫‪12‬‬ ‫‪90‬‬ ‫‪34‬‬ ‫‪23‬‬ ‫‪56‬‬ ‫‪23‬‬ ‫‪8‬‬ ‫‪89‬‬ ‫‪23‬‬

‫إذن ‪ ،‬سيكون الناتج ‪.664‬‬

‫مكررات قناة_املدخالت مرصحة أن تستخدم تقييماً متساهالً‬


‫‪istream_iterators Are Permitted to Use Lazy Evaluation‬‬

‫عندما نربط مكرر قناة_املدخالت إلى قناة ‪ ،‬فال نضمن أنه سيقرأ القناة على الفور‪.‬‬
‫يُسمح للتطبيق بتأخري قراءة القناة حىت نستخدم املكرر‪.‬‬ ‫•‬
‫لكن نضمن أنه قبل إلغاء مرجع املكرر ألول مرة ‪ ،‬ستـتم قراءة القناة‪.‬‬ ‫•‬
‫بالنسبة ملعظم الربامج ‪ ،‬سواء كانت القراءة فورية أو متأخرة فال تشكل فرقاً‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬إذا أنشأنا مكرر قناة_املدخالت دمرناه بدون استخدام ؛‬ ‫•‬
‫أو إذا كنا نزامن القراءات إلى نفس القناة من كائنني مختلفني ‪ ،‬فحينها قد نهتم كثريًا عند حدوث القراءة‪.‬‬ ‫•‬

‫‪Operations on ostream_iterators‬‬ ‫العمليات على مكررات قناة_املخرجات‬

‫يمكن تعريف مكرر قناة_املخرجات ألي نوع لديه عامل مخرجات (العامل >>)‪.‬‬
‫فعندما نقوم بإنشاء مكرر قناة_املخرجات ‪،‬‬ ‫•‬
‫ثانيا يحدد سلسلة أحرف لتطبع بعد كل عنرص‪.‬‬
‫ً‬ ‫وسيطا‬
‫ً‬ ‫(اختياريا)‬
‫ً‬ ‫قد نوفر‬ ‫•‬
‫يجب أن تكون تلك السلسلة سلسلة أحرف نمط‪C-‬‬ ‫•‬
‫(أي حرفية سلسلة أو مؤرشاً ملصفوفة منتهية بقيمة خالية)‪.‬‬ ‫•‬
‫يتوجب علينا ربط مكرر قناة_املخرجات إلى قناة محددة‪.‬‬ ‫•‬
‫ال يوجد هناك مكرر قناة_مخرجات فارغ أو ما بعد النهاية‪.‬‬ ‫•‬
‫يمكننا استخدام مكرر قناة_املخرجات لكتابة سلسلة من القيم ‪: sequence of values‬‬

‫;)" " ‪ostream_iterator<int> out_iter(cout,‬‬


‫)‪for (auto e : vec‬‬
‫;‪    *out_iter++ = e‬‬ ‫‪// assignment writes this element to cout‬‬
‫;‪cout << endl‬‬

‫يقوم هذا الربنامج بكتابة كل عنرص من ‪ vec‬على ‪ cout‬كل عنرص متبوع بمسافة‪.‬‬ ‫•‬
‫في كل مرة نقوم فيها بتعيني قيمة إلى ‪ ، out_iter‬يتم االلزتام بالكتابة‪.‬‬ ‫•‬
‫من الجدير بالذكر أنه يمكننا حذف إلغاء املرجع والزتايد عندما نعني إلى ‪.out_iter‬‬
‫أي يمكننا كتابة هذه الحلقة متكافئة كالتالي ‪:‬‬

‫)‪for (auto e : vec‬‬


‫;‪    out_iter = e‬‬ ‫‪// assignment writes this element to cout‬‬
‫;‪cout << endl‬‬

‫ال يقوم العامالن * و ‪ ++‬بعمل أي يشء على مكرر قناة_املخرجات ‪،‬‬ ‫•‬
‫لذا فإن حذفهما ليس له أي تأثري على برنامجنا‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فنحن نفضل كتابة الحلقة كما قدمت أول مرة‪.‬‬ ‫•‬
‫تستخدم هذه الحلقة املكرر باستمرار مع كيفية استخدامنا ألنواع مكررات أخرى‪.‬‬
‫يمكننا بسهولة تغيري هذه الحلقة لتنفيذها على نوع مكرر آخر‪.‬‬ ‫•‬
‫وضوحا لقراء كودنا‪.‬‬
‫ً‬ ‫عالوة على ذلك ‪ ،‬سيكون سلوك هذه الحلقة أكرث‬ ‫•‬
‫بدال ً من كتابة الحلقة بأنفسنا ‪ ،‬يمكننا بسهولة أكرث طباعة العنارص في ‪ vec‬عن طريق استدعاء ‪: copy‬‬

‫;)‪copy(vec.begin(), vec.end(), out_iter‬‬


‫;‪cout << endl‬‬
‫‪Using Stream Iterators with Class Types‬‬ ‫استخدام مكررات القناة مع أنواع الفئة‬

‫يمكننا إنشاء مكرر قناة_املدخالت ألي نوع لديه عامل مدخالت (<<)‪.‬‬
‫وباملثل ‪ ،‬يمكننا تعريف مكرر قناة_املخرجات طاملا أن النوع يملك عامل مخرجات (>>)‪.‬‬ ‫•‬
‫ونظرًا ألن فئة عنرص_املبيعات تملك عوامل مدخالت ومخرجات ‪،‬‬ ‫•‬
‫فيمكننا استخدام مكررات املدخالت واملخرجات إلعادة كتابة برنامج متجر الكتب من الفقرة ‪: 1.6‬‬ ‫•‬

‫;‪istream_iterator<Sales_item> item_iter(cin), eof‬‬


‫;)"‪ostream_iterator<Sales_item> out_iter(cout, "\n‬‬
‫‪// store first transaction in sum and read next record‬‬
‫;‪Sales_item sum = *item_iter++‬‬
‫{ )‪while (item_iter != eof‬‬
‫‪    // if current transaction (which stored in item_iter) has same ISBN‬‬
‫))(‪    if (item_iter->isbn() == sum.isbn‬‬
‫‪        sum += *item_iter++; // add it to sum and read next transaction‬‬
‫{ ‪    else‬‬
‫;‪        out_iter = sum‬‬ ‫‪// write current sum‬‬
‫;‪        sum = *item_iter++‬‬ ‫‪} // read next transaction‬‬
‫;‪} out_iter = sum‬‬ ‫‪// remember to print last set of records‬‬

‫يستخدم هذا الربنامج ‪ item_iter‬لقراءة معامالت ‪ Sales_item‬من ‪.cin‬‬ ‫•‬


‫يستخدم ‪ out_iter‬لكتابة املجموع الناتج إلى ‪ ، cout‬كل مخرجات متبوعة بسطر جديد‪.‬‬ ‫•‬
‫بعد تعريف مكرراتنا ‪ ،‬نستخدم ‪ item_iter‬لتهيئة ‪ sum‬بقيمة أول معاملة ‪:‬‬

‫‪// store first transaction in sum and read next record‬‬


‫;‪Sales_item sum = *item_iter++‬‬

‫هنا ‪ ،‬نلغي املرجع إلى نتيجة الزتايد الالحق في ‪.item_iter‬‬ ‫•‬


‫يقرأ هذا التعبري املعاملة التالية ‪ ،‬ويقوم بتهيئة ‪ sum‬على القيمة املخزنة مسب ًقا في ‪.item_iter‬‬ ‫•‬

‫يتم تنفيذ حلقة ‪ while‬حىت نصطدم بنهاية امللف على ‪.cin‬‬ ‫•‬
‫داخل ‪ ، while‬نتحقق مما إذا كان ‪ sum‬والسجل الذي قرأناه للتو يشريان إلى نفس الكتاب‪.‬‬ ‫•‬
‫إذا كانا كذلك ‪ ،‬فإننا نضيف أحدث عنرص قرأه ‪ Sales_item‬إلى ‪. sum‬‬ ‫•‬
‫أما إذا كانت أرقام ‪ ISBN‬مختلفة ‪ ،‬فإننا نعني ‪ sum‬على ‪، out_iter‬‬ ‫•‬
‫واليت تطبع القيمة الحالية لـ‪ sum‬متبوعة بسطر جديد‪.‬‬ ‫•‬

‫بعد طباعة املجموع للكتاب السابق ‪ ،‬نقوم بتعيني ‪ sum‬نسخة من أحدث معاملة تمت قراءتها ونزايد املكرر ‪،‬‬ ‫•‬
‫والذي يقرأ املعاملة التالية‪.‬‬
‫تستمر الحلقة حىت يحدث خطأ أو نصطدم بنهاية امللف‪.‬‬ ‫•‬
‫قبل الخروج ‪ ،‬نتذكر أن نطبع القيم املرتبطة بآخر كتاب في املدخالت‪.‬‬ ‫•‬
‫تمارين القسم ‪10.4.2‬‬

‫التمرين ‪:10.29‬‬
‫برنامج ا باستخدام مكررات القناة لقراءة ملف نيص في متجه من السالسل‪.‬‬
‫ً‬ ‫اكتب‬

‫التمرين ‪:10.30‬‬
‫‪ -‬استخدم مكررات القناة وفرزها ونسخها لقراءة سلسلة من األعداد الصحيحة من املدخالت القياسية وفرزها‬
‫‪ -‬ثم إعادة كتابتها إلى املخرجات القيايس‪.‬‬

‫التمرين ‪:10.31‬‬
‫‪ -‬قم بتحديث الربنامج من التمرين السابق بحيث يطبع العنارص الفريدة فقط‪.‬‬
‫‪ -‬يجب أن يستخدم برنامجك ‪.unqiue_copy‬‬

‫التمرين ‪:10.32‬‬
‫‪ -‬أعد كتابة مشكلة مكتبة الكتب من الفقرة ‪ 1.6‬باستخدام متجه إلجراء املعامالت والخوارزميات املختلفة إلجراء‬
‫املعالجة‪.‬‬
‫‪ -‬استخدم الفرز باستخدام دالة ‪ CompareIsbn‬الخاصة بك من الفقرة ‪ 10.3.1‬لرتتيب املعامالت بالرتتيب ‪،‬‬
‫‪ -‬ثم استخدم إيجاد_ وتجميع_ لعمل املجموع‪.‬‬

‫التمرين ‪:10.33‬‬
‫برنامجا يأخذ أسماء ملف مدخالت وملفي مخرجات‪.‬‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬يجب أن يحتوي ملف املدخالت على أعداد صحيحة‪.‬‬
‫‪ -‬باستخدام مكرر قناة_املدخالت ‪ ،‬اقرأ ملف املدخالت‪.‬‬
‫‪ -‬باستخدام مكررات قناة_املخرجات ‪ ،‬اكتب األرقام الفردية في ملف املخرجات األول‪.‬‬
‫‪ -‬يجب أن يتبع كل قيمة مسافة‪.‬‬
‫‪ -‬اكتب األرقام الزوجية في امللف الثاني‪ .‬يجب وضع كل من هذه القيم في سطر منفصل‪.‬‬

‫‪10.4.3. Reverse Iterators‬‬ ‫‪ .10.4.3‬املكررات العكسية‬

‫املكرر العكيس هو مكرر يجتاز حاوية للخلف ‪ ،‬بدءاً من آخر عنرص باتجاه األول‪.‬‬
‫يقلب مكرر عكيس معىن الزتايد (والتناقص)‪.‬‬ ‫•‬
‫تزايد (‪ )it ++‬مكرر عكيس يحرك املكرر إلى العنرص السابق ؛‬ ‫•‬
‫بينما تناقصه (‪ )it--‬يحرك املكرر إلى العنرص التالي‪.‬‬ ‫•‬

‫تحتوي جميع الحاويات ‪ ،‬ما عدا القائمة_اﻷمامية ‪ ،‬على مكررات عكسية‪.‬‬


‫نحصل على مكرر عكيس عن طريق استدعاء األعضاء ‪ rbegin‬و ‪ rend‬و ‪ crbegin‬و ‪.crend‬‬ ‫•‬
‫تعيد هذه األعضاء مكررات عكسية آلخر عنرص في الحاوية وعنرص ما "بعد" (أي ما قبل) بداية الحاوية‪.‬‬ ‫•‬
‫وكما هو الحال مع املكررات العادية ‪ ،‬سيكون لدينا مكررات ثابتة وغري ثابتة‪.‬‬ ‫•‬

‫سيوضح الشكل ‪ 10.1‬العالقة بني هذه املكررات األربعة على متجه افرتايض يسمى ‪.vec‬‬

‫)(‪Vec.cbegin‬‬ ‫)(‪Vec.cend‬‬

‫‪...‬‬ ‫‪...‬‬

‫)(‪Vec.crend‬‬ ‫)(‪Vec.crbegin‬‬

‫الشكل ‪ .10.1‬مقارنة مكررات ‪ cbegin/cend‬مــع ‪crbegin/crend‬‬

‫كمثال ‪ ،‬تطبع الحلقة التالية عنارص ‪ vec‬في ترتيب عكيس ‪:‬‬

‫;}‪vector<int> vec = {0,1,2,3,4,5,6,7,8,9‬‬


‫‪// reverse iterator of vector from back to front‬‬
‫‪for (auto r_iter = vec.crbegin(); // binds r_iter to last element‬‬
‫;)(‪r_iter != vec.crend‬‬ ‫‪// crend refers 1 before 1st element‬‬
‫)‪++r_iter‬‬ ‫‪// decrements iterator one element‬‬
‫;‪cout << *r_iter << endl‬‬ ‫‪// prints 9, 8, 7,... 0‬‬

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

‫‪// sorts vec in “normal” order‬‬


‫;))(‪sort(vec.begin(), vec.end‬‬
‫‪// sorts in reverse: puts smallest element at end of vec‬‬
‫;))(‪sort(vec.rbegin(), vec.rend‬‬

‫تتطلب املكررات العكسية عوامل تناقص‬


‫‪Reverse Iterators Require Decrement Operators‬‬

‫ليس من املستغرب أنه ال يمكننا تعريف مكرر عكيس إال من مكرر يدعم التناقص ‪ --‬كما يدعم الزتايد ‪.++‬‬
‫فبعد كل يشء ‪ ،‬فالغرض منه تحريك املكرر للخلف عرب التسلسل‪.‬‬ ‫•‬
‫كل املكررات على الحاويات القياسية ما عدا القائمة اﻷمامية تدعم التناقص وكذلك الزتايد‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فال تدعم مكررات قناة_املدخالت واملخرجات التناقص ‪ ،‬حيث ال يمكنها التحرك للخلف عرب القناة‪.‬‬ ‫•‬
‫ولذلك ‪ ،‬من غري الـممكن إنشاء مكرر عكيس من قائمة_أمامية أو من مكرر قناة‪.‬‬ ‫•‬
‫العالقة بني املكررات العكسية واملكررات األخرى‬
‫‪Relationship between Reverse Iterators and Other Iterators‬‬

‫لنفرتض أن لدينا سلسلة باسم سطر ‪ line‬يحتوي على قائمة كلمات مفصولة بفواصل ‪،‬‬
‫ونريد أن نطبع الكلمة األولى فيها‪ .‬فباستخدام إيجاد_ ‪ ، find‬ستكون هذه املهمة سهلة ‪:‬‬

‫‪// find first element in a comma-separated list‬‬


‫;)'‪auto comma = find(line.cbegin(), line.cend(), ',‬‬
‫;‪cout << string(line.cbegin(), comma) << endl‬‬

‫إن كانت هناك فاصلة في ‪ ، line‬ستشري ‪ comma‬إلى تلك الفاصلة ؛ وإال فستشري إلى ‪. line.cend‬‬ ‫•‬
‫عندما نطبع السلسلة من ‪ line.cbegin‬إلى ‪، comma‬‬ ‫•‬
‫فإننا سنطبع األحرف حىت الفاصلة ‪ ،‬أو السلسلة بأكملها إذا لم تكن هناك فاصلة‪.‬‬ ‫•‬
‫أما إذا أردنا الكلمة األخرية ‪ ،‬فيمكننا استخدام املكررات العكسية بدال ً من ذلك ‪:‬‬ ‫•‬

‫‪// find last element in a comma-separated list‬‬


‫;)'‪auto rcomma = find(line.crbegin(), line.crend(), ',‬‬

‫ونظرًا ألننا مررنا ‪ crbegin‬و ‪ ، crend‬فإن هذا االستدعاء يبدأ بآخر حرف في ‪ line‬ويبحث للخلف‪.‬‬ ‫•‬
‫عند اكتمال ‪ ، find‬إن كانت هناك فاصلة ‪ ،‬فستشري ‪ rcomma‬إلى آخر فاصلة في السطر ‪-‬‬ ‫•‬
‫أي أنها تشري إلى أول فاصلة تم العثور عليها في البحث العكيس‪.‬‬ ‫•‬
‫إذا لم تكن هناك فاصلة ‪ ،‬فـ ‪ rcomma‬ستكون ‪. line.crend‬‬ ‫•‬

‫يأتي الجزء املثري لالهتمام عندما نحاول أن نطبع الكلمة اليت وجدناها‪ .‬الطريقة اليت تبدو واضحة‬

‫‪// WRONG: will generate word in reverse order‬‬


‫;‪cout << string(line.crbegin(), rcomma) << endl‬‬

‫ستولد مخرجات زائفة‪ .‬على سبيل املثال ‪ ،‬فلو كانت مدخالتنا‬

‫‪FIRST,MIDDLE,LAST‬‬

‫إذن ستطبع هذه الجملة ‪! TSAL‬‬

‫يوضح الشكل ‪ 10.2‬املشكلة ‪ :‬فنحن نستخدم املكررات العكسية ‪ ،‬واليت تعالج السلسلة نحو الخلف‪.‬‬ ‫•‬
‫لذا ‪ ،‬فإن جملة املخرجات تطبع من ‪ crbegin‬نحو الخلف عرب ‪.line‬‬ ‫•‬
‫نريد أن نطبع بدال ً من ذلك من ‪ rcomma‬نحو اﻷمام حىت نهاية ‪.line‬‬ ‫•‬
‫مع ذلك ‪ ،‬ال يمكننا استخدام ‪ rcomma‬مبارشة‪.‬‬ ‫•‬
‫ذلك املكرر هو مكرر عكيس ‪ ،‬مما يعين أنه يميض للخلف نحو بداية السلسلة‪.‬‬ ‫•‬

‫ما يتعني علينا القيام به هو تحويل ‪ rcomma‬مرة أخرى إلى مكرر عادي يتقدم عرب ‪.line‬‬ ‫•‬
‫يمكننا القيام بذلك عن طريق استدعاء العضو ‪: reverse_iterator‬‬ ‫•‬
‫يسمى ‪ ، base‬والذي يعطينا مكرره العادي املقابل ‪:‬‬ ‫•‬

‫‪// ok: get a forward iterator and read to end of line‬‬


‫;‪cout << string(rcomma.base(), line.cend()) << endl‬‬

‫)(‪cbegin‬‬ ‫‪comma‬‬ ‫‪rcomma.base‬‬ ‫)(‪crend‬‬

‫‪F I R S T‬‬ ‫‪,‬‬ ‫‪MIDDLE‬‬ ‫‪,‬‬ ‫‪L A S T‬‬

‫‪rcomma‬‬ ‫)(‪crbegin‬‬

‫الشكل ‪ .10.2‬العالقة بني املكررات العكسية والعادية‬

‫بالنظر إلى نفس املدخالت السابقة ‪ ،‬سيطبع هذا البيان ‪ LAST‬كما هو متوقع‪.‬‬

‫توضح الكائنات املوضحة في الشكل ‪ 10.2‬العالقة بني املكررات العادية والعكسية‪.‬‬ ‫•‬
‫فمثالً ‪ ،‬يشري ‪ rcomma‬و ‪ rcomma.base‬إلى عنارص مختلفة ‪ ،‬مثل ‪ line.crbegin‬و ‪.line.cend‬‬ ‫•‬
‫هذه االختالفات رضورية للتأكد من أن نطاق العنارص ‪ ،‬سواء تمت معالجته ملقدمة أو لخلف ‪ ،‬هو نفسه‪.‬‬ ‫•‬

‫من الناحية الفنية ‪ ،‬فإن العالقة بني املكررات العادية والعكسية تستوعب خصائص نطاق‪-‬أيرس‪-‬شامل‪.‬‬ ‫•‬
‫املقصد هو أن كالً من [‪ )line.crbegin()، rcomma‬و [‪) rcomma.base()، line.cend‬‬ ‫•‬
‫سيشريان إلى العنارص نفسها في ‪.line‬‬ ‫•‬
‫ولكي يحدث ذلك ‪ ،‬يجب أن ينتج عن ‪ rcomma‬و ‪ rcomma.base‬مواضع متجاورة ‪،‬‬ ‫•‬
‫بدال ً من نفس املوضع ‪ ،‬كما يتوجب أن يؤدي ‪ crbegin‬و ‪.cend‬‬ ‫•‬

‫ملحوظة‬

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

‫تمارين القسم ‪10.4.3‬‬

‫التمرين ‪:10.34‬‬
‫استخدم ‪ reverse_iterators‬لطباعة متجه برتتيب عكيس‪.‬‬

‫التمرين ‪:10.35‬‬
‫قم اآلن بطباعة العنارص برتتيب عكيس باستخدام املكررات العادية‪.‬‬
‫التمرين ‪:10.36‬‬
‫استخدم ‪ find‬إليجاد آخر عنرص في قائمة أعداد صحيحة بالقيمة ‪.0‬‬

‫التمرين ‪:10.37‬‬
‫‪ -‬نظرًا لوجود متجه يحتوي على عرشة عنارص ‪،‬‬
‫‪ -‬قم بنسخ العنارص من املواضع ‪ 3‬إلى ‪ 7‬برتتيب عكيس إلى قائمة‪.‬‬
‫‪ 10٫5‬هيكــــــلة الخــــــــــوارزميــــــــــات الشــــــــــاملة‬
‫‪10.5 Structure of Generic Algorithms‬‬

‫الخاصية األساسية ألي خوارزمية هي قائمة العمليات اليت تتطلبها من مكررها (مكرراتها)‪.‬‬
‫• تتطلب بعض الخوارزميات ‪ ،‬كإيجاد_ ‪ ،‬فقط القدرة على الوصول إلى عنرص عرب املكرر ‪ ،‬وتزايد املكرر ‪،‬‬
‫ومقارنة مكررين من أجل التساوي‪.‬‬
‫• تتطلب خوارزميات أخرى ‪ ،‬كالفرز ‪ ،‬القدرة على القراءة والكتابة والوصول العشوائي للعنارص‪.‬‬
‫يتم تصنيف عمليات املكرر اليت تتطلبها الخوارزميات ‪،‬‬ ‫•‬
‫إلى خمس فئات مكرر ‪ iterator categories‬مدرجة في الجدول ‪.10.5‬‬ ‫•‬
‫تحدد كل خوارزمية أية نوع مكرر يتوجب توفريه لكل من معلمات مكررها‪.‬‬ ‫•‬

‫الجدول ‪ .10.5‬تصنيفات املكرر‬

‫;‪Read, but not write‬‬


‫‪input iterator‬‬
‫‪single-pass, increment only.‬‬

‫;‪Write, but not read‬‬


‫‪output iterator‬‬
‫‪single-pass, increment only.‬‬

‫;‪Read and write‬‬


‫‪forward iterator‬‬
‫‪multi-pass, increment only.‬‬

‫;‪Read and write‬‬


‫‪bidirectional iterator‬‬
‫‪multi-pass, increment and decrement‬‬

‫;‪Read and write‬‬


‫‪random-access iterator‬‬
‫‪multi-pass, full iterator arithmetic‬‬

‫الطريقة الثانية هي تصنيف الخوارزميات (كما فعلنا في بداية هذا الفصل)‬ ‫•‬
‫حسب ما إذا كانت تقرأ أو تكتب أو تُعيد ترتيب العنارص في التسلسل‪.‬‬ ‫•‬
‫يغطي امللحق أ جميع الخوارزميات وف ًقا لهذا التصنيف ‪.‬‬ ‫•‬

‫أيض ا في مجموعة من اصطالحات تمرير املعلمات ومجموعة من اصطالحات التسمية ‪،‬‬


‫تشرتك الخوارزميات ً‬
‫واليت سنغطيها بعد النظر في فئات املكرر‪.‬‬ ‫•‬

‫‪10.5.1. The Five Iterator Categories‬‬ ‫‪ .10.5.1‬تصنيفات املكرر الخمسة‬

‫تعرف املكررات مجموعة مشرتكة من العمليات‪.‬‬


‫مثل الحاويات ‪ّ ،‬‬
‫تتوفر بعض العمليات بواسطة كل املكررات ؛ بينما يتم دعم أخرى عرب أنواع محددة فقط من املكررات‪.‬‬ ‫•‬
‫فعلى سبيل املثال ‪ ،‬مكررات قناة_املخرجات لديها فقط الزتايد ‪ ،‬وإلغاء املرجع ‪ ،‬والتعيني‪.‬‬ ‫•‬
‫بينما تدعم مكررات على متجه وسلسلة وطابور تلك العمليات مع عوامل التناقص والعالئقية والحسابية‪.‬‬ ‫•‬

‫نوعا من التسلسل الهرمي‪.‬‬


‫يتم تصنيف املكررات من خالل العمليات اليت تقدمها ‪ ،‬وتشكل التصنيفات ً‬
‫فباستثناء مكررات املخرجات ‪ ،‬يوفر مكرر تصنيف أعلى جميع عمليات املكررات من التصنيف األدنى‪.‬‬ ‫•‬

‫يحدد املعيار التصنيف اﻷدنى لكل معلمة مكرر للخوارزميات الشاملة والعددية‪.‬‬
‫فمثالً ‪ ،‬يتطلب إيجاد_ ‪ -‬الذي ينفذ اجتيازًا ملرور واحد ‪ ،‬للقراءة فقط عرب تسلسل ‪ -‬ح ًدا أدنى مكرر مدخالت‪.‬‬ ‫•‬
‫زوجا من املكررات اليت تكون على األقل مكررات_أمامية‪.‬‬
‫ً‬ ‫بينما تتطلب دالة استبدال_‬ ‫•‬
‫وباملثل ‪ ،‬تتطلب ‪ replace_copy‬مكررات أمامية ألول مكررين لها‪.‬‬ ‫•‬
‫مكررها الثالث ‪ ،‬الذي يمثل وجهة ‪ ،‬يجب أن يكون على األقل مكرر مخرجات ‪ ،‬وهكذا‪.‬‬ ‫•‬
‫لكل معلمة ‪ ،‬يجب أن يكون املكرر على األقل بنفس قوة الحد األدنى املنصوص عليه‪.‬‬ ‫•‬
‫يعد تمرير مكرر بقوة أقل خطأ‪.‬‬ ‫•‬

‫تحذير‬

‫لن تشتكي العديد من املرتجمات عندما نمرر تصنيف مكرر خاطئ إلى خوارزمية‪.‬‬

‫‪The Iterator Categories‬‬ ‫فئات املكرر‬

‫مكررات املدخالت ‪:‬‬


‫يمكنها قراءة العنارص في تسلسل‪ .‬ويجب أن يوفر مكرر املدخالت‬
‫عوامل التساوي وعدم التساوي (== ‪ )!= ،‬ملقارنة اثنني من املكررات‬ ‫•‬
‫تزايد البادئة والالحقة (‪ )++‬من أجل تقدم املكرر‬ ‫•‬
‫عامل إلغاء املرجع (*) لقراءة عنرص‪ .‬قد يظهر إلغاء املرجع فقط على الجانب األيمن من تعيني‬ ‫•‬
‫عامل السهم (<‪ )-‬الذي يلغي املرجع عن املكرر ويجلب عضوا من الكائن األسايس وهو مرادف لـ‬ ‫•‬
‫‪(* it).member‬‬

‫يمكن استخدام مكررات املدخالت بالتسلسل فقط‪.‬‬ ‫•‬


‫نحن نضمن أن تكون ‪ *it++‬صالحة ‪،‬‬ ‫•‬
‫لكن مزايدة مكرر املدخالت قد يؤدي إلى إبطال كل مكررات القناة األخرى‪ .‬نتيجة لذلك ‪،‬‬ ‫•‬
‫ليس هناك ما يضمن أنه يمكننا حفظ حالة مكرر مدخالت وفحص عنرص من خالل هذا املكرر املحفوظ‪.‬‬ ‫•‬
‫بالتالي ‪ ،‬يمكن استخدام ُمك ِّررات املدخالت فقط لخوارزميات املرور الفردي‪.‬‬ ‫•‬
‫تتطلب خوارزميات إيجاد_ وتجميع_ ُمكررات مدخالت ؛ مكررات قناة_املدخالت عبارة عن مكررات مدخالت‪.‬‬ ‫•‬

‫مكررات املخرجات ‪:‬‬


‫يمكن اعتبارها ذات وظائف تكميلية ملكررات املدخالت ؛ حيث تكتب العنارص بدال ً من قراءتها‪ .‬ويجب أن توفر ‪:‬‬
‫تزايد البادئة والالحقة (‪ )++‬لتقدم املكرر‬ ‫•‬
‫عامل إلغاء املرجع (*) ‪ ،‬قد يظهر فقط على يسار تعيني (التعيني إلى مكرر مخرجات ملغى مرجعياً سيكتب‬ ‫•‬
‫على العنرص األسايس‪).‬‬

‫قد نقوم بتعيني قيمة معينة ملكرر مخرجات مرة واحدة فقط‪.‬‬ ‫•‬
‫ومثل ُمكرِّرات املدخالت ‪ ،‬يمكن استخدام ُمكرِّرات املخرجات فقط لخوارزميات املرور الفردي‪.‬‬ ‫•‬
‫املكررات املستخدمة كوجهة عادة ما تكون مكررات مخرجات‪.‬‬ ‫•‬
‫مثالً ‪ ،‬معلمة نسخ_ ‪ copy‬الثالثة عبارة عن مكرر مخرجات‪ .‬نوع مكرر قناة_املخرجات هو مكرر مخرجات‪.‬‬ ‫•‬

‫املكررات اﻷمامية ‪:‬‬


‫يمكنها قراءة وكتابة تسلسل معني‪ .‬تتحرك في اتجاه واحد فقط عرب التسلسل‪.‬‬
‫تدعم املكررات اﻷمامية جميع عمليات مكررات املدخالت ومكررات املخرجات‪.‬‬ ‫•‬
‫عالوة على ذلك ‪ ،‬يمكنها قراءة أو كتابة نفس العنرص عدة مرات‪.‬‬ ‫•‬
‫لذا ‪ ،‬يمكننا استخدام الحالة املحفوظة ملكرر أمامي‪.‬‬ ‫•‬
‫ومن ثم ‪ ،‬فإن الخوارزميات اليت تستخدم مكررات أمامية قد تقوم بتمريرات متعددة عرب التسلسل‪.‬‬ ‫•‬
‫مكررا أمامياً ؛ تعد املكررات على القائمة اﻷمامية هي مكررات أمامية‪.‬‬
‫ً‬ ‫تتطلب خوارزمية االستبدال‬ ‫•‬

‫املكررات ثنائية االتجاه ‪:‬‬


‫يمكنها قراءة وكتابة تسلسل لألمام أو للخلف‪.‬‬
‫أيضا عوامل تناقص البادئة‬
‫• وباإلضافة إلى دعمها جميع عمليات املكرر اﻷمامي ‪ ،‬يدعم مكرر ثنائي االتجاه ً‬
‫و الالحقة (‪.)--‬‬
‫• تتطلب الخوارزمية عكس_ مكررات ثنائية االتجاه ‪،‬‬
‫وبخالف القائمة اﻷمامية ‪ ،‬توفر حاويات املكتبة مكررات تفي بمتطلبات املكرر ثنائي االتجاه‪.‬‬ ‫•‬

‫مكررات الوصول العشوائي ‪:‬‬


‫توفر وصوال ً ثاب ًتا إلى أي موضع في التسلسل‪.‬‬
‫تدعم هذه املكررات جميع وظائف املكررات ثنائية االتجاه‪.‬‬ ‫•‬
‫إضافة إلى ذلك ‪ ،‬تدعم مكررات الوصول العشوائي العمليات من الجدول ‪:3.7‬‬ ‫•‬
‫العوامل العالئقية (<‪ )= >، >، =< ،‬ملقارنة املواضع النسبية ملكررين‪.‬‬ ‫•‬
‫عوامل الجمع والطرح (‪ ، - ، = + ، +‬و ‪ )= -‬على مكرر وقيمة صحيحة‪.‬‬ ‫•‬
‫والنتيجة هي أن املكرر يتقدم (أو يرتاجع) عددا صحيحا للعنارص داخل التسلسل‪.‬‬ ‫•‬
‫عامل الطرح (‪ )-‬عند تطبيقه على مكررين ‪ ،‬مما ينتج عنه املسافة بينهما‪.‬‬ ‫•‬
‫عامل الفهرسة (]‪ )iter[n‬املرادف لـ‬ ‫•‬

‫)‪* (iter + n‬‬

‫تتطلب خوارزمية الفرز مكررات الوصول العشوائي‪.‬‬ ‫•‬


‫املكررات للمصفوفة ‪ ،‬الطابور ‪ ،‬السلسلة ‪ ،‬واملتجه هي مكررات وصول عشوائي ‪،‬‬ ‫•‬
‫وهي مثلها مثل املؤرشات عند استخدامها للوصول إلى عنارص من مصفوفة مدمجة‪.‬‬ ‫•‬
‫تمارين القسم ‪10.5.1‬‬

‫التمرين ‪:10.38‬‬
‫قم بعمل قائمة لتصنيفات املكرر الخمس والعمليات اليت تدعمها كل منها‪.‬‬

‫التمرين ‪:10.39‬‬
‫ما هو نوع مكرر القائمة؟ ماذا عن املتجه؟‬

‫التمرين ‪:10.40‬‬
‫ما أنواع املُكرِّرات اليت تعتقد أن نسخ_ يتطلبها؟ ماذا عن عكس_ أو فريد_؟‬

‫‪10.5.2. Algorithm Parameter Patterns‬‬ ‫‪ .10.5.2‬أنماط معلمات الخوارزمية‬

‫يتم فرض مجموعة من اصطالحات املعلمات على أي تصنيف آخر للخوارزميات‪.‬‬


‫يمكن أن يساعد فهم اصطالحات املعلمات على تعلم خوارزميات جديدة —‬ ‫•‬
‫فمن خالل معرفة ما تعنيه املعلمات ‪ ،‬يمكنك الرتكزي على فهم العملية اليت تقوم بها الخوارزمية‪.‬‬ ‫•‬
‫تحتوي معظم الخوارزميات على أحد األشكال األربعة التالية‪:‬‬ ‫•‬

‫;)‪alg(beg, end, other args‬‬


‫;)‪alg(beg, end, dest, other args‬‬
‫;)‪alg(beg, end, beg2, other args‬‬
‫;)‪alg(beg, end, beg2, end2, other args‬‬

‫حيث ‪ alg‬عبارة عن اسم الخوارزمية ‪،‬‬ ‫•‬


‫وتشري ‪ beg‬و ‪ end‬إلى نطاق املدخالت الذي تعمل عليه الخوارزمية‪.‬‬ ‫•‬
‫تقريبا تأخذ نطاق مدخالت ‪،‬‬
‫ً‬ ‫وبالرغم من أن جميع الخوارزميات‬ ‫•‬
‫فإن وجود املعلمات األخرى يعتمد على العمل الذي يتم تنفيذه‪.‬‬ ‫•‬
‫العنارص الشائعة املدرجة هنا كلها مكررات ‪ ، dest -‬و ‪ ، beg2‬و ‪.- end2‬‬ ‫•‬
‫أدوارا مشابهة‪.‬‬
‫ً‬ ‫وعند استخدامها ‪ ،‬تمأل هذه املكررات‬ ‫•‬
‫وباإلضافة إلى معلمات املكرر هذه ‪،‬‬ ‫•‬
‫تأخذ بعض الخوارزميات معلمات إضافية ليست‪-‬مكررات خاصة بالخوارزمية‪.‬‬ ‫•‬

‫خوارزميات ذات مكرر وجهة وحيد‬


‫‪Algorithms with a Single Destination Iterator‬‬

‫املعلمة ‪ dest‬هو مكرر يشري إلى وجهة يمكن للخوارزمية أن تكتب مخرجاتها عليه‪.‬‬
‫تفرتض الخوارزميات أنه من اآلمن كتابة عدد ما تحتاجه من العنارص ‪.‬‬
‫تحذير‬

‫تفرتض خوارزميات تكتب إلى مكرر مخرجات أن الوجهة كبرية بما يكفي لتحمل املخرجات‪.‬‬

‫إذا كان ‪ dest‬مكرراً يشري مبارشة لحاوية ‪ ،‬فإن الخوارزمية تكتب مخرجاتها على العنارص داخل الحاوية‪.‬‬ ‫•‬
‫شيوعا ‪ ،‬أن ‪ dest‬ترتبط بمكرر مدخالت أو مكرر قناة_مخرجات‪.‬‬
‫ً‬ ‫األكرث‬ ‫•‬
‫يضيف مكرر املدخالت عنارص جديدة إلى الحاوية ‪ ،‬مما يضمن أن هناك مساحة كافية‪.‬‬ ‫•‬
‫يكتب مكرر قناة_مخرجات على قناة مخرجات ‪،‬‬ ‫•‬
‫مرة أخرى لن تكون هناك أي مشكلة بغض النظر كم عدد العنارص اليت تمت كتابتها‪.‬‬ ‫•‬

‫‪Algorithms with a Second Input Sequence‬‬ ‫خوارزميات ذات تسلسل مدخالت ثان‬

‫الخوارزميات اليت تأخذ إما ‪ beg2‬بمفردها أو ‪ beg2‬مع ‪ end2‬تستخدمها لتشري إلى نطاق مدخالت ثانٍ ‪.‬‬
‫تستخدم تلك الخوارزميات عاد ًة عنارص النطاق الثاني إلى جانب نطاق املدخالت إلجراء عملية حسابية‪.‬‬ ‫•‬

‫عندما تأخذ خوارزمية كالً من ‪ beg2‬مع ‪ ، end2‬فإن هذه املكررات تشري إلى نطاق ثان‪.‬‬
‫تماما‪:‬‬
‫ً‬ ‫تأخذ مثل هذه الخوارزميات نطاقني محددين‬ ‫•‬
‫نطاق املدخالت املشار إليه بواسطة [‪، )beg ، end‬‬ ‫•‬
‫ونطاق مدخالت ثانٍ يُشار إليه بـ [‪.)beg2 ، end2‬‬ ‫•‬

‫الخوارزميات اليت تأخذ ‪ beg2‬فقط (بدون ‪ )end2‬تعامل ‪ beg2‬كأول عنرص في نطاق مدخالت ثانٍ ‪.‬‬
‫لم يتم تحديد نهاية ذلك النطاق‪.‬‬ ‫•‬
‫بل ستفرتض أن حجم النطاق البادئ من ‪ beg2‬يكون على األقل بحجم النطاق املشار إليه بـ ‪. beg, end‬‬ ‫•‬

‫تحذير‬

‫تفرتض الخوارزميات اليت تأخذ ‪ beg2‬وحده أن حجم التسلسل البادئ من ‪ beg2‬بحجم نطاق ‪.beg, end‬‬

‫‪10.5.3. Algorithm Naming Conventions‬‬ ‫‪ .10.5.3‬اصطالحات تسمية الخوارزمية‬

‫منفصلة عن اصطالحات املعلمات ‪،‬‬


‫أيضا مع مجموعة من اصطالحات التسمية والتعدد (زائدة‪-‬التعبئة)‪.‬‬
‫تتوافق الخوارزميات ً‬ ‫•‬
‫تتعامل هذه االصطالحات مع كيفية توفري عملية الستخدامها بدال ً من العامل االفرتايض > أو == ‪،‬‬ ‫•‬
‫وما إذا كانت الخوارزمية تكتب على تسلسل مدخالتها أو إلى وجهة منفصلة‪.‬‬ ‫•‬

‫تستخدم بعض الخوارزميات التعبئة الزائدة لتمرير محمولة‬


‫‪Some Algorithms Use Overloading to Pass a Predicate‬‬

‫الخوارزميات اليت تأخذ محمولة تستخدمه بدال ً من العامل > أو == ‪ ،‬واليت ال تأخذ وسيطات أخرى ‪ ،‬عاد ًة ما تكون‬
‫زائدة‪-‬التعبئة‪.‬‬
‫• فإصدار منها يستخدم عامل نوع العنرص ملقارنة العنارص ؛‬
‫بينما يأخذ إصدار ثان معلمة إضافية عبارة عن محمولة تستخدمه مكان > أو == ‪:‬‬ ‫•‬

‫;)‪unique(beg, end‬‬ ‫‪// uses == operator to compare elements‬‬


‫‪unique(beg, end, comp); // uses comp to compare elements‬‬

‫كال االستدعاءان يعيدان ترتيب التسلسل املحدد عن طريق إزالة العنارص املكررة املتجاورة‪.‬‬ ‫•‬
‫األول يستخدم عامل نوع العنرص == للتحقق من التكرارات ؛‬ ‫•‬
‫بينما يستدعي الثاني ‪ comp‬ليقرر ما إذا كان عنرصان متساويان‪.‬‬ ‫•‬
‫ونظرًا الختالف نسخيت الدالة من حيث عدد الوسيطات ‪،‬‬ ‫•‬
‫فال غموض محتمل بشأن الدالة اليت يتم استدعاؤها‪.‬‬ ‫•‬

‫‪Algorithms with _if Versions‬‬ ‫خوارزميات ذات إصدارات إذا_‬

‫تملك خوارزميات تأخذ قيمة عنرص عادة إصداراً ثانياً مسمى (غري زائد‪-‬التعبئة) يأخذ محمولة بدال ً من قيمة‪.‬‬
‫تلك الخوارزميات اليت تأخذ محمولة تملك امتداد _‪ if‬ملحقة ‪:‬‬ ‫•‬

‫;)‪find(beg, end, val‬‬ ‫‪// find first instance of val in input range‬‬
‫‪find_if(beg, end, pred); // find first instance for which pred is true‬‬

‫تبحث هاتان الخوارزميتان عن أول مثيل لعنرص محدد في نطاق املدخالت‪.‬‬ ‫•‬
‫تبحث الخوارزمية أوجد_ ‪ find‬عن قيمة محددة ؛‬ ‫•‬
‫بينما تبحث خوارزمية أوجد_إذا ‪ find_if‬عن قيمة من أجل أن تُعيد ‪ pred‬لها قيمة غري صفرية‪.‬‬ ‫•‬

‫إصدارا مسمى بدال ً من إصدار زائد‪-‬التعبئة ؛‬


‫ً‬ ‫توفر هذه الخوارزميات‬ ‫•‬
‫وذلك ألن كال اإلصدارين من الخوارزمية يأخذان نفس عدد الوسيطات‪.‬‬ ‫•‬
‫نادرا‪.‬‬
‫ً‬ ‫وبالتالي ‪ ،‬فإن غموض زائد‪-‬التعبئة سيكون ممكنًا ‪ ،‬وإن كان‬ ‫•‬
‫لكن لتجنب أي غموض محتمل ‪ ،‬توفر املكتبة إصدارات مسماة ومنفصلة لهذه الخوارزميات‪.‬‬ ‫•‬

‫تميزي اﻹصدارات اليت تنسخ من تلك اليت ال تنسخ‬


‫‪Distinguishing Versions That Copy from Those That Do Not‬‬

‫افرتاضياً ‪ ،‬تكتب الخوارزميات اليت تُعيد ترتيب عنارصها العنارص املرتبة مرة أخرى على نطاق املدخالت املحدد‪.‬‬
‫ثانيا يكتب على وجهة مخرجات محددة‪.‬‬
‫ً‬ ‫إصدارا‬
‫ً‬ ‫توفر هذه الخوارزميات‬ ‫•‬
‫وكما رأينا ‪ ،‬فإن الخوارزميات اليت تكتب على وجهة تُلحق _‪ copy‬إلى أسمائها ‪:‬‬ ‫•‬

‫;)‪reverse(beg, end‬‬ ‫‪// reverse elements in input range‬‬


‫‪reverse_copy(beg, end, dest);// copy elements in reverse order into dest‬‬

‫توفر بعض الخوارزميات كالً من إصداري _‪ copy‬و _‪ .if‬تأخذ هذه اإلصدارات مكرر وجهة ومحمولة ‪:‬‬
‫‪// removes odd elements from v1‬‬
‫;)} ;‪remove_if(v1.begin(), v1.end(),[](int i) { return i % 2‬‬
‫‪// copies only even elements from v1 into v2; v1 is unchanged‬‬
‫‪remove_copy_if(v1.begin(), v1.end(), back_inserter(v2),‬‬
‫;)} ;‪[](int i) { return i % 2‬‬

‫فرديا‪.‬‬
‫ً‬ ‫يستخدم كال االستدعاءين المدا لتحديد ما إذا كان العنرص‬ ‫•‬
‫في الحالة األولى ‪ ،‬نقوم بإزالة العنارص الفردية من تسلسل املدخالت نفسه‪.‬‬ ‫•‬
‫أما في الثانية ‪ ،‬فنقوم بنسخ العنارص غري الفردية (أو الزوجية) من نطاق املدخالت إلى اإلصدار ‪.2‬‬ ‫•‬

‫تمارين القسم ‪10.5.3‬‬

‫التمرين ‪:10.41‬‬
‫بناء على أسماء الخوارزمية والوسيطات فقط ‪،‬‬
‫ً‬ ‫‪-‬‬
‫‪ -‬قم بوصف العملية اليت تنفذها كل من خوارزميات املكتبة التالية‪:‬‬
‫;)‪replace(beg, end, old_val, new_val‬‬
‫;)‪replace_if(beg, end, pred, new_val‬‬
‫;)‪replace_copy(beg, end, dest, old_val, new_val‬‬
‫;)‪replace_copy_if(beg, end, dest, pred, new_val‬‬
‫‪ 10٫6‬خــــــــــوارزميــــــــــات الحــــــاوية الخــــــــــاصة‬
‫‪10.6 Container-Specific Algorithms‬‬

‫تعرف القائمة والقائمة_األمامية عدة خوارزميات كأعضاء‪.‬‬


‫على عكس الحاويات األخرى ‪ّ ،‬‬
‫تعرف أنواع القائمة إصداراتها الخاصة من‪:‬‬
‫ولكن تحديداً ‪ّ ،‬‬ ‫•‬
‫فرز_‪ ،‬دمج_‪ ،‬إزالة_ ‪ ،‬عكس_ وفريد_ ‪. sort, merge, remove, reverse, and unique‬‬ ‫•‬
‫يتطلب اإلصدار الشامل من فرز_ مكررات وصول عشوائي‪.‬‬ ‫•‬
‫نتيجة لذلك ‪ ،‬ال يمكن استخدام فرز_ مع القائمة و القائمة_اﻷمامية ؛‬ ‫•‬
‫وذلك ألن هذين النوعني يقدمان مكررات ثنائية االتجاه ومكررات أمامية ‪ ،‬على التوالي‪.‬‬ ‫•‬

‫تعرفها أنواع القائمة مع القائمة ‪ ،‬لكن بتكلفة في األداء‪.‬‬


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

‫يتم وصف هذه العمليات الخاصة بالقائمة في الجدول ‪.10.6‬‬


‫الخوارزميات الشاملة غري مدرجة في الجدول واليت تأخذ مكررات مناسبة ‪،‬‬ ‫•‬
‫تنفذ بكفاءة متساوية على القوائم والقوائم اﻷمامية كما هو الحال على الحاويات األخرى‪.‬‬ ‫•‬

‫الجدول ‪ .10.6‬الخوارزميات أعضاء القائمة وقائمة اﻷمامية‬

‫‪These operations return void.‬‬

‫‪Merges elements from lst2 onto lst.‬‬


‫‪Both lst and lst2 must be sorted.‬‬
‫)‪lst.merge(lst2‬‬ ‫‪After the merge, lst2 is empty.‬‬
‫)‪lst.merge(lst2, comp‬‬ ‫‪The first version uses the < operator; the‬‬
‫‪second version uses the given comparison‬‬
‫‪operation.‬‬

‫‪Calls erase to remove each element that is == to‬‬


‫)‪lst.remove(val‬‬
‫‪the given value or for which the given unary‬‬
‫)‪lst.remove_if(pred‬‬
‫‪predicate succeeds.‬‬

‫)(‪lst.reverse‬‬ ‫‪Reverse the order of the elements in lst.‬‬

‫)(‪lst.sort‬‬ ‫‪Sorts the elements of the lst using < or the‬‬


‫)‪lst.sort(comp‬‬ ‫‪given comparison operation.‬‬

‫)(‪lst.unique‬‬ ‫‪Calls erase to remove consecutive of the same‬‬


‫)‪lst.unique(pred‬‬ ‫‪value.‬‬
‫‪The first version uses ==; the second uses the‬‬
‫‪given binary predicate.‬‬

‫أفضل املمارسات‬

‫ينبغي استخدام إصدارات أعضاء القائمة بتفضيل على الخوارزميات الشاملة للقائمة والقوائم اﻷمامية‪.‬‬

‫‪The splice Members‬‬ ‫أعضاء اللصق‬

‫أيضا خوارزمية لصق_ ‪ ، splice‬واملوضحة في الجدول ‪.10.7‬‬


‫تعرف أنواع القائمة ً‬
‫ّ‬
‫هذه الخوارزمية خاصة لهياكل بيانات القائمة‪ .‬ومن ثم ال حاجة لنسخة شاملة منها‪.‬‬ ‫•‬

‫الجدول ‪ .10.7‬وسيطات أعضاء لصق للقائمة والقائمة اﻷمامية‬

‫)‪lst.splice(args) or flst.splice_after(args‬‬

‫‪p is an iterator to an element in lst or an iterator‬‬


‫‪just before an element in flst.‬‬
‫‪Moves all the element(s) from lst2 into lst just‬‬
‫)‪(p, lst2‬‬ ‫‪before p or into flst just after p.‬‬
‫‪Removes the element(s) from lst2.‬‬
‫‪Lst2 must have the same type as lst or flst and may‬‬
‫‪not be the same list.‬‬

‫‪P2 is valid iterator into lst2.‬‬


‫‪Moves the element denoted by p2 into lst or moves the‬‬
‫)‪(p, lst2, p2‬‬
‫‪element just after p2 into flst.‬‬
‫‪Lst2 can be the same list as lst or flst.‬‬

‫‪B and e must denote a valid range in lst2.‬‬


‫‪Moves the elements in the given range from lst2.‬‬
‫)‪(p, lst2, b, e‬‬
‫‪Lst2 and lst (or flst) can be the same list but p must‬‬
‫‪not denote an element in the given range.‬‬

‫العمليات الخاصة بالقائمة تقوم فعالً بتغيري الحاويات‬


‫‪The List-Specific Operations Do Change the Containers‬‬

‫معظم الخوارزميات الخاصة بالقائمة متشابهة ‪ -‬لكن ليست متطابقة ‪ -‬مع نظرياتها الشاملة‪.‬‬
‫مع ذلك ‪ ،‬فإن االختالف املهم للغاية بني اإلصدارات الخاصة بالقائمة واإلصدارات الشاملة هو ‪:‬‬ ‫•‬
‫أن إصدارات القائمة تغري الحاوية األساسية‪.‬‬ ‫•‬
‫فعلى سبيل املثال ‪ ،‬يزيل إصدار إزالة_ للقائمة العنارص املشار إليها‪.‬‬ ‫•‬
‫كما يزيل إصدار فريد_ للقائمة العنارص املتكررة الثانية والالحقة‪.‬‬ ‫•‬

‫وباملثل ‪ ،‬فإن دمج_ وربط_ مدمران لوسيطاتهما‪.‬‬


‫فمثالً ‪ ،‬يكتب اإلصدار الشامل من دمج_ التسلسل املدمج إلى مكرر وجهة محدد ؛‬ ‫•‬
‫ويبقي تسلسلي املدخالت دون تغيري‪.‬‬ ‫•‬
‫بينما تعمل نسخة الدالة دمج_ للقائمة على تدمري القائمة املحددة ‪-‬‬ ‫•‬
‫تتم إزالة العنارص من قائمة الوسيطات حيث يتم دمجها في الكائن الذي تم استدعاء الدمج إليه‪.‬‬ ‫•‬
‫بعد الدمج ‪ ،‬تستمر العنارص من كلتا القائمتني موجودة ‪ ،‬لكن كلها عنارص من نفس القائمة‪.‬‬ ‫•‬

‫تمارين القسم ‪10.6‬‬

‫التمرين ‪:10.42‬‬
‫أعد تنفيذ الربنامج الذي حذف الكلمات املكررة اليت كتبناها في الفقرة ‪ 10.2.3‬لتستخدم قائمة بدال ً من املتجه‪.‬‬
‫ملخــــــــــص الفصــــــــــل‬
‫‪Chapter Summary‬‬

‫تعرف املكتبة القياسية ما يقارب من ‪ 100‬خوارزمية مستقلة عن النوع تعمل على التسلسالت‪.‬‬
‫ّ‬
‫يمكن أن تكون التسلسالت عنارص في نوع مكتبة حاوية ‪ ،‬أو مصفوفة مدمجة ‪،‬‬ ‫•‬
‫أو يتم إنشاؤها (على سبيل املثال) عن طريق القراءة أو الكتابة على قناة‪.‬‬ ‫•‬

‫تحقق الخوارزميات استقاللها النوعي من خالل العمل بأسلوب ومنهجية املكررات‪.‬‬


‫زوجا من املكررات يشريان إلى مجموعة من العنارص‪.‬‬
‫ً‬ ‫تأخذ معظم الخوارزميات كأول وسيطتني‬ ‫•‬
‫قد تشتمل وسيطات املكرر اإلضافية على مكرر مخرجات يشري إلى وجهة ‪،‬‬ ‫•‬
‫أو مكرر آخر أو زوج مكرر يشريان إلى تسلسل مدخالت ثانٍ ‪.‬‬ ‫•‬

‫يتم تصنيف املكررات إلى واحدة من خمس فئات اعتما ًدا على العمليات اليت تدعمها‪.‬‬
‫فئات املكرر هي املدخالت واملخرجات واﻷمامية وثنائية االتجاه والوصول العشوائي‪.‬‬ ‫•‬
‫ينتمي املكرر إلى فئة معينة إذا كان يدعم العمليات املطلوبة لفئة املكرر هذه‪.‬‬ ‫•‬

‫تماما كما يتم تصنيف املكررات من خالل عملياتها ‪،‬‬


‫ً‬
‫يتم تصنيف معلمات املكرر إلى الخوارزميات من خالل عمليات املكرر اليت تتطلبها‪.‬‬ ‫•‬
‫تتطلب الخوارزميات اليت تقرأ تسلسلها فقط عمليات مكرر مدخالت‪.‬‬ ‫•‬
‫تلك اليت تكتب على مكرر الوجهة ال تتطلب سوى إجراءات مكرر مخرجات ‪ ،‬وهكذا‪.‬‬ ‫•‬

‫ال تغري الخوارزميات بشكل مبارش أبداً حجم التسلسالت اليت تعمل عليها‪.‬‬
‫قد تقوم بنسخ العنارص من موضع إلى آخر ‪،‬‬ ‫•‬
‫لكن لن يمكنها إضافة عنارص أو إزالتها بشكل مبارش‪.‬‬ ‫•‬

‫وعلى الرغم من أن الخوارزميات ال يمكنها إضافة عنارص إلى تسلسل ‪ ،‬إال أن مكرر اإلدراج قد يقوم بذلك‪.‬‬
‫مكرر املدخالت مرتبط بحاوية‪.‬‬ ‫•‬
‫وعندما نقوم بتعيني قيمة نوع عنرص حاوية على مكرر إدراج ‪،‬‬ ‫•‬
‫يضيف املكرر العنرص املحدد إلى الحاوية‪.‬‬ ‫•‬

‫تعرف حاويات القائمة_اﻷمامية والقائمة إصداراتها الخاصة من بعض الخوارزميات الشاملة‪.‬‬


‫ّ‬
‫لكن على عكس الخوارزميات الشاملة ‪ ،‬تعدل هذه اإلصدارات الخاصة بالقائمة القوائم املحددة‪.‬‬ ‫•‬
‫مصطلحــــــــــات معــــــــــرفة‬
‫‪Defined Terms‬‬

‫ُمدرج_خلف‪ :‬مكيف مكرر يأخذ إشارة إلى الحاوية ويقوم بإنشاء مكرر إدراج‬
‫‪back_inserter‬‬
‫يستخدم دفع_للخلف ‪ push_back‬إلضافة عنارص إلى الحاوية املحددة‪.‬‬

‫مكرر ثنائي االتجاه‪ :‬نفس عمليات املكرر األمامية باإلضافة إلى‬


‫‪bidirectional iterator‬‬
‫القدرة على استخدام عالمة الطرح ‪ -‬لالنتقال للخلف خالل التسلسل‪.‬‬

‫‪binary predicate‬‬ ‫املحمولة الثنائية‪ :‬محمولة تحتوي على معلمتني‪.‬‬

‫ربط_‪ :‬دالة مكتبة تربط وسيطة واحدة أو أكرث بتعبري قابل لالستدعاء‪.‬‬
‫‪bind‬‬
‫يتم تعريف ربط_ في العنوان الدالي‪.‬‬

‫كائن قابل لالستدعاء‪ :‬كائن يمكن أن يظهر كمعامل يسار لعامل االستدعاء‪.‬‬
‫‪callable object‬‬ ‫تعرف عامل استدعاء دالة زائد التعبئة ‪،‬‬
‫املؤرشات للدوال ‪ ،‬و المدا_ ‪ ،‬وكائنات فئة ّ‬
‫كلها كائنات قابلة لالستدعاء‪.‬‬

‫قائمة_التقاط‪:‬‬
‫‪capture list‬‬ ‫جزء من تعبري المدا يعرف متغريات من دالة متضمنة يمكن لتعبري المدا الوصول‬
‫إليها‪.‬‬

‫دالة مكتبة تقوم بإعادة كائن قابل للنسخ يحتوي على مرجع لكائن ثابت من نوع ال‬
‫‪cref‬‬
‫يمكن نسخه‪.‬‬

‫‪forward iterator‬‬ ‫مطلوبا لدعم الطرح ‪.-‬‬


‫ً‬ ‫مكرر أمامي‪ :‬مكرر يمكنه قراءة العنارص وكتابتها ولكن ليس‬

‫ُم درج_مقدمة‪ :‬مكيف مكرر ‪ ،‬عند إعطائه حاوية ‪ ،‬يولد مكرر مدخالت يستخدم‬
‫‪front_inserter‬‬
‫دفع_للمقدمة ‪ push_front‬إلضافة عنارص إلى بداية تلك الحاوية‪.‬‬

‫‪generic algorithms‬‬ ‫الخوارزميات الشاملة‪ :‬خوارزميات مستقلة عن األنواع‪.‬‬


‫‪input iterator‬‬ ‫مكرر املدخالت‪ :‬مكرر يمكنه قراءة عنارص التسلسل دون الكتابة‪.‬‬

‫مكرر إدراج ‪:‬‬


‫‪insert iterator‬‬
‫مكرر ا يستخدم عملية الحاوية إلضافة عنارص إلى حاوية معينة‪.‬‬
‫ً‬ ‫ينئش‬ ‫مكيف مكرر‬

‫ومرجعا إلى حاوية ويقوم بإنشاء مكرر إدراج‬


‫ً‬ ‫مكررا‬
‫ً‬ ‫ُمدرج ‪ :‬مكيف مكرر يأخذ‬
‫‪inserter‬‬
‫يستخدم إدراج_ إلضافة عنارص قبل العنرص املشار إليه بواسطة مكرر معني‪.‬‬

‫‪istream_iterator‬‬ ‫مكرر قناة_املدخالت‪ :‬مكرر قناة يقرأ قناة_املدخالت‪.‬‬

‫بناء على العمليات اليت يدعمها املكرر‪.‬‬


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

‫تعبري المدا‪ :‬وحدة أكواد قابلة لالستدعاء‪.‬‬


‫تعترب المدا إلى حد ما مثل دالة مدمجة غري مسماة‪.‬‬
‫تبدأ المدا بقائمة االلتقاط ‪ ،‬واليت تسمح بالوصول إلى املتغريات في دالة التضمني‪.‬‬
‫‪lambda expression‬‬ ‫مثل الدالة ‪ ،‬تحتوي على قائمة معلمات (ربما فارغة) ونوع إعادة وبنية دالة‪.‬‬
‫يمكن أن تحذف المدا نوع اإلعادة‪.‬‬
‫أعد واحدة ‪ ،‬يستنتج نوع اإلعادة من نوع الكائن املعاد‪.‬‬‫إذا كانت بنية الدالة جملة ِ‬
‫خالف ذلك ‪ ،‬يتم اإلعداد االفرتايض لنوع اإلعادة لتصبح فراغاً‪.‬‬

‫مكررا يحرك العنارص بدال ً من نسخها‪.‬‬


‫ً‬ ‫مكرر حركة‪ :‬مكيف مكرر يولد‬
‫‪move iterator‬‬
‫يتم تناول مكررات الحركة في الفصل الثالث عرش‪.‬‬

‫‪ostream_iterator‬‬ ‫مكرر قناة_مخرجات‪ :‬مكرر يكتب على قناة املخرجات‪.‬‬

‫‪output iterator‬‬ ‫مكرر مخرجات‪ :‬مكرر يمكنه الكتابة على العنارص ‪ ،‬ولكن ليس بالرضورة قراءتها‪.‬‬
‫نوعا يمكن تحويله إلى منطقي‪.‬‬
‫محمولة ‪ :‬دالة تُعيد ً‬
‫غالبا ما تستخدم بواسطة الخوارزميات الشاملة الختبار العنارص‪.‬‬
‫ً‬
‫‪predicate‬‬
‫املحموالت املستخدمة من قبل املكتبة هي‬
‫إما أحادية (تأخذ وسيطة واحدة) أو ثنائية (تأخذ وسيطتني)‪.‬‬

‫مكرر الوصول العشوائي‪ :‬نفس عمليات املكررات ثنائية االتجاه‬


‫‪random-access iterator‬‬ ‫إضافة إلى العوامل العالئقية ملقارنة قيم املكرر ‪ ،‬وعامل الفهرسة‬
‫والعمليات الحسابية على املكررات ‪ ،‬وبالتالي دعم الوصول العشوائي إلى العنارص‪.‬‬

‫‪ref‬‬ ‫دالة مكتبة تنئش كائنًا قاباًل للنسخ من مرجع إلى كائن من نوع ال يمكن نسخه‪.‬‬

‫مكرر عكيس يتحرك للخلف عرب تسلسل‪.‬‬


‫‪reverse iterator‬‬
‫تتبادل هذه املكررات معىن الزتايد والتناقص‪.‬‬

‫‪stream iterator‬‬ ‫مكرر قناة ‪ :‬مكرر يمكن ربطه بقناة‪.‬‬

‫‪unary predicate‬‬ ‫محمولة أحادية‪ :‬محمولة تحتوي على معلمة واحدة‪.‬‬

You might also like