C++الكلاس set
- تعريف الكلاس
set
- دوال الكلاس
set
- أمثلة شاملة حول التعامل مع الكلاس
set
تعريف الكلاس set
يستخدم لإنشاء كائن يمثل حاوية تخزن العناصر التي نضيفها فيها بشكل متسلسل وراء بعضها البعض و بترتيب معين حيث يتم وضع العنصر الذي يملك القيمة الأصغر في البداية و العنصر الذي يملك القيمة الأكبر في النهاية أو العكس, مع الإشارة إلى أنه لا يمكن تخزين قيم مكررة فيها كالتالي.
الآن, عليك معرفة أن العناصر الموجودة في هذه الحاوية لا يمكن تعديل قيمها لأن ترتيب أماكن عناصرها يتم على أساس قيمها.
في حال أردت تعديل قيمة عنصر, فيجب أن تحذفه من الحاوية و تقوم بإجراء تعديل عليه و من بعدها تقوم بإضافته فيها من جديد.
كما أنك تستطيع تخصيص الطريقة التي يتم فيها ترتيب العناصر حتى تتناسب مع أنواع العناصر التي ستقوم بتخزينها لأنك على الأغلب لن تتعامل مع عناصر قيمتها int
فقط. كمثال بسيط قد تكون العناصر التي تريد تخزينها عبارة كائنات من كلاس إسمه Product
يمثل منتج, هنا يكون كل منتج يملك عدة معلومات مثل إسمه, رقم التعرفة الخاص به, سعره و تاريخ إنتاجه. في هذه الحالة يمكنك تخصيص الطريقة التي سيتم فيها ترتيب العناصر فمثلاً يمكنك جعل العناصر (التي تمثل منتجات) يتم ترتيبها على أساس رقم التعرفة الخاص بكل منتج.
لاستخدام الكلاس set
- أي حتى تتمكن من إنشاء كائنات منه - يجب تضمين الملف لأنه موجود فيه.
بناء الكلاس
template < class T, // set::key_type/value_type class Compare = less<T>, // set::key_compare/value_compare class Alloc = allocator<T> // set::allocator_type > class set;
إذاً عند إنشاء كائن من الكلاس set
يجب أن نمرر له نوع البيانات الذي نريد تخزينه فيه مكان الباراميتر T
.
دوال الكلاس set
الجدول التالي يحتوي على دوال الكلاس set
التي تستخدم للحصول على عداد يتيح المرور على عناصره.
الدالة مع تعريفها | |
---|---|
1 | iterator begin()
ترجع كائن iterator يشير لمكان أول عنصر في الكائن الذي قام باستدعائها.إذا كنا ننوي استخدام الدالة begin() بداخل حلقة فإننا نستخدم معها الدالة end() من أجل البدء من أول عنصر و الوقوف عند آخر عنصر. |
2 | iterator end()
ترجع كائن iterator يشير لمكان آخر عنصر في الكائن الذي قام باستدعائها.إذا كنا ننوي استخدام الدالة begin() بداخل حلقة فإننا نستخدم معها الدالة end() من أجل البدء من أول عنصر و الوقوف عند آخر عنصر. |
3 | iterator rbegin()
ترجع كائن iterator يشير لمكان آخر عنصر في الكائن الذي قام باستدعائها.إذا كنا ننوي استخدام الدالة rbegin() بداخل حلقة فإننا نستخدم معها الدالة rend() من أجل البدء من آخر عنصر و الوقوف عند أول عنصر. |
4 | iterator rend()
ترجع كائن iterator يشير لمكان أول عنصر في الكائن الذي قام باستدعائها.إذا كنا ننوي استخدام الدالة rbegin() بداخل حلقة فإننا نستخدم معها الدالة rend() من أجل البدء من آخر عنصر و الوقوف عند أول عنصر. |
الجدول التالي يحتوي على دوال الكلاس set
التي تستخدم للحصول على عدد عناصره.
الدالة مع تعريفها | |
---|---|
1 | bool empty()
تستخدم لمعرفة ما إن كان الكائن الذي قام باستدعائها فارغاً أم لا.ترجع false في حال كان يوجد فيه عنصر أو أكثر, و ترجع true إن لم يكن كذلك. |
2 | size_t size()
تستخدم للحصول على عدد العناصر الموجودة في الكائن الذي قام باستدعائها. |
3 | size_t max_size()
تستخدم للحصول على أكبر عدد عناصر يمكن تخزينها في الكائن الذي قام باستدعائها. |
الجدول التالي يحتوي على دوال الكلاس set
التي تستخدم للتحكم بعناصره.
الدالة مع تعريفها | |
---|---|
1 | iterator insert(const_iterator position, T& val)
تستخدم لإضافة عنصر جديد في مكان محدد - أي عند عنوان محدد - في الكائن الذي قام باستدعائها.مكان الباراميتر position نمرر كائن أصله من Iterator يشير لعنوان المكان الذي سيتم إضافة العنصر عنده في الذاكرة.مكان الباراميتر val نمرر القيمة التي نريد وضعها في العنصر الذي سيتم إضافته.كما أنها ترجع كائن أصله من Iterator يمثل عنوان العنصر الذي تم إضافته. |
2 | iterator erase(const_iterator position)
تستخدم لحذف عنصر محدد من الكائن الذي قام باستدعائها.مكان الباراميتر position نمرر كائن أصله من Iterator يشير لعنوان العنصر الذي سيتم حذفه. |
3 | iterator erase(const_iterator first, const_iterator last)
تستخدم لحذف مجموعة عناصر من الكائن الذي قام باستدعائها.مكان الباراميتر first نمرر كائن أصله من const_iterator يشير لعنوان العنصر الذي سيتم بدء الحذف من عنده.مكان الباراميتر last نمرر كائن أصله من const_iterator يشير لعنوان العنصر الذي سيتم إيقاف الحذف عنده. |
4 | void swap(set& anotherSet)
تستخدم لتبديل قيم عناصر الكائن الذي قام باستدعائها بقيم عناصر الكائن الذي نمرره لها.مكان الباراميتر anotherSet نمرر لها كائن من الكلاس set يملك نفس نوع عناصر الكائن الذي قام باستدعائها. |
5 | void emplace(T& val)
تستخدم لإضافة عنصر جديد في الكائن الذي قام باستدعائها. |
الجدول التالي يحتوي على دوال الكلاس set
التي تستخدم للبحث فيه.
الدالة مع تعريفها | |
---|---|
1 | size_t count(T& val)
تستخدم للبحث في الكائن الذي قام باستدعائها عن عنصر يملك قيمة محددة.مكان الباراميتر val نمرر القيمة التي نريد البحث عنها.في حال تم إيجاد عنصر يملك نفس القيمة التي تم تمريرها لها ترجع القيمة 1 و في حال لم يتم إيجاد عنصر يملك نفس القيمة ترجع القيمة 0 . |
2 | iterator find(const T& val)
تستخدم للبحث في الكائن الذي قام باستدعائها عن عنصر يملك قيمة محددة.مكان الباراميتر val نمرر القيمة التي نريد البحث عنها.في حال تم إيجاد عنصر يملك نفس القيمة التي تم تمريرها لها ترجع كائن من Iterator يشير لعنوان العنصر في الذاكرة.و في حال لم يتم إيجاد عنصر يملك نفس القيمة التي تم تمريرها لها ترجع كائن من Iterator قيمته تساوي القيمة التي ترجعها الدالة end() . |
أمثلة شاملة حول التعامل مع الكلاس set
في كل مثال موضوع قمنا باستخدام دوال جديدة حتى تعرف كيف تستخدم جميع الدوال التي ذكرناها في الجدول.
في المثال التالي قمنا بتعريف كائن من set
مع تحديد أنه يمكن أن يحتوي على عناصر نوعها int
.
بعدها قمنا بإضافة بعض العناصر فيه و من ثم طباعة عدد العناصر التي قمنا بإضافتها.
بعدها قمنا بعرض جميع قيم العناصر الموجودة فيه بواسطة حلقة.
ملاحظة: قمنا باستخدام الدالة emplace()
لإضافة العناصر, الدالة size()
لمعرفة عدد العناصر التي تم إضافتها. عند عرض جميع قيم عناصر الكائن, قمنا باستخدام الدالة begin()
للحصول على مؤشر للعنصر الأول لأننا سنبدأ من عنده و الدالة end()
للحصول على مؤشر للعنصر الأخير لأننا سنتوقف عنده.
المثال الأول
using namespace std; int main() { // int يمكنه أن يحتوي على قيم نوعها set هنا قمنا بتعريف كائن من الكلاس set<int> mySet; // مع الإشارة إلى أننا تعمدنا إدخال نفس القيمة أكثر من مرة emplace() باستخدام الدالة mySet هنا حاولنا إضافة 7 عناصر في الكائن // العناصر التي أضفناها سيتم ترتيبها بشكل تلقائي من الأصغر إلى الأكبر كالتالي {5, 4, 3, 2, 1} و ستلاحظ ذلك لاحقاً عند عرض قيمهم mySet.emplace(3); mySet.emplace(1); mySet.emplace(5); mySet.emplace(2); mySet.emplace(5); // بما أنه يوجد القيمة 5 مسبقاً, لن يتم إضافتها من جديد mySet.emplace(4); mySet.emplace(1); // بما أنه يوجد القيمة 1 مسبقاً, لن يتم إضافتها من جديد // size() باستخدام الدالة mySet هنا قمنا بطباعة عدد عناصر الكائن cout << "mySet size = " << mySet.size() << endl; cout << "mySet values ="; // إبتداءاً من أول عنصر وصولاً لآخر عنصر فيه mySet هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيمة عنصر جديد من العناصر الموجودة في الكائن for (auto it = mySet.begin(); it != mySet.end(); ++it) { cout << " " << *it; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
mySet size = 5 mySet values = 1 2 3 4 5
في المثال التالي قمنا بتعريف كائن من set
مخصص لتخزين قيم نوعها int
مع إضافة عدة قيم فيه عند تعريفه.
بعدها قمنا بعرض القيم الموجودة فيه بواسطة حلقة بشكل عكسي, أي من الآخر إلى الأول.
ملاحظة: قمنا باستخدام الدالة rbegin()
للحصول على مؤشر للعنصر الأخير لأننا سنبدأ من عنده و الدالة rend()
للحصول على مؤشر للعنصر الأول لأننا سنتوقف عنده.
المثال الثاني
using namespace std; int main() { // بالإضافة إلى أننا قمنا بإضافة عدة قيم فيه int يمكنه أن يحتوي على عناصر نوعها set هنا قمنا بتعريف كائن من الكلاس // العناصر التي أضفناها سيتم ترتيبها بشكل تلقائي من الأصغر إلى الأكبر كالتالي {5, 4, 3, 2, 1} و ستلاحظ ذلك لاحقاً عند عرض قيمهم set<int> mySet = {1, 4, 2, 4, 5, 3, 1, 5}; cout << "mySet values ="; // إبتداءاً من آخر عنصر وصولاً لأول عنصر فيه mySet هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيمة عنصر جديد من العناصر الموجودة في الكائن for (auto it = mySet.rbegin(); it != mySet.rend(); ++it) { cout << " " << *it; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
mySet values = 5 4 3 2 1
في المثال التالي قمنا بتعريف كائن من set
مخصص لتخزين قيم نوعها int
بشكل تنازلي (أي من الأكبر إلى الأصغر) مع إضافة عدة قيم فيه عند تعريفه.
بعدها قمنا بعرض القيم الموجودة فيه بواسطة حلقة.
المثال الثالث
using namespace std; int main() { // بالإضافة إلى أننا قمنا بإضافة عدة قيم فيه int يمكنه أن يحتوي على عناصر نوعها set هنا قمنا بتعريف كائن من الكلاس // من أجل ترتيب القيم greater قيم هذا الكائن سيتم ترتيبها من الأكبر إلى الأصغر و سبب ذلك أننا جعلناه يعتمد على الكلاس // العناصر التي أضفناها سيتم ترتيبها بشكل تلقائي كالتالي {5, 4, 3, 2, 1} و ستلاحظ ذلك لاحقاً عند عرض قيمهم set<int, greater<int>> mySet = {1, 4, 2, 4, 5, 3, 1, 5}; cout << "mySet values ="; // إبتداءاً من أول عنصر وصولاً لآخر عنصر فيه mySet هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيمة عنصر جديد من العناصر الموجودة في الكائن for (auto it = mySet.begin(); it != mySet.end(); ++it) { cout << " " << *it; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
mySet values = 5 4 3 2 1
في المثال التالي قمنا بتعريف كائن من set
مخصص لتخزين قيم نوعها int
مع إضافة عدة قيم فيه عند تعريفه.
بعدها قمنا بالبحث عن قيمة محددة فيه لمعرفة ما إن كانت موجودة فيه أم لا.
ملاحظة: قمنا باستخدام الدالة count()
للبحث عن القيمة في الكائن.
المثال الرابع
using namespace std; int main() { // بالإضافة إلى أننا قمنا بإضافة عدة قيم فيه int يمكنه أن يحتوي على عناصر نوعها set هنا قمنا بتعريف كائن من الكلاس set<int> mySet = {1, 2, 3, 4, 5}; // يوجد فيه عنصر قيمته تساوي 4 mySet هنا قمنا بطباعة ما إن كان الكائن if (mySet.count(4)) { // إن كان فيه سيتم تنفيذ أمر الطباعة التالي cout << "4 is exist in myset"; } else { // إن لم يكن فيه سيتم تنفيذ أمر الطباعة التالي cout << "4 is not exist in myset"; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
4 is exist in myset
في المثال التالي قمنا بتعريف كائن من set
مخصص لتخزين قيم نوعها int
مع إضافة عدة قيم فيه عند تعريفه.
بعدها قمنا بالبحث عن قيمة محددة فيه و في حال كانت موجودة سنقوم بحذف العنصر الذي يملكها من الكائن.
ملاحظة: قمنا باستخدام الدالة find()
للبحث عن القيمة في الكائن و الدالة erase()
لحذف العنصر من الكائن.
المثال الخامس
using namespace std; int main() { // بالإضافة إلى أننا قمنا بإضافة عدة قيم فيه int يمكنه أن يحتوي على عناصر نوعها set هنا قمنا بتعريف كائن من الكلاس set<int> mySet = {1, 2, 3, 4, 5}; // لتخزين مكان العنصر الذي نجد القيمة التي نبحث عنها فيه set<int>::iterator منا قمنا بتعريف كائن من set<int>::iterator it; // it عن عنصر يملك القيمة 4, و بالتالي في حال وجود عنصر يملك القيمة 4 سيتم تخزين عنوانه في الكائن mySet هنا قمنا بالبحث في الكائن // فيه للإشارة إلى أنه لم يتم إيجاد أي عنصر يملك هذه القيمة mySet.end() في حال عدم وجود عنصر يملك القيمة 4 سيتم تخزين القيمة التي ترجعها it = mySet.find(4); // فهذا يعني أنه تم إيجاد القيمة و بالتالي سيتم تنفيذ الكود الموضوع فيها mySet.end() لا تساوي القيمة التي ترجعها الدالة it في حال كانت قيمة if (it != mySet.end()) { // و من ثم قمنا بحذفه mySet هنا قمنا بطباعة قيمة العنصر الذي تم إيجاده في الكائن cout << "element with value '"<< *it << "' is removed from mySet\n"; mySet.erase(it); } cout << "mySet values ="; // إبتداءاً من أول عنصر وصولاً لآخر عنصر فيه mySet هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيمة عنصر جديد من العناصر الموجودة في الكائن for (auto it = mySet.begin(); it != mySet.end(); ++it) { cout << " " << *it; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
element with value '4' is removed from mySet mySet values = 1 2 3 5
في المثال التالي قمنا بتعريف كائنين من set
مع تحديد أنه يمكن أن يحتويان على عناصر نوعها int
.
بعدها قمنا بتبديل عناصرهما و من ثم طباعة القيم التي أصبحت موجودة في كلٍّ منهما.
ملاحظة: قمنا باستخدام الدالة swap()
لتبديل قيمهما.
المثال السادس
using namespace std; int main() { // بالإضافة إلى أننا قمنا بإضافة عدة قيم فيهما int يمكنهما أن يحتويان على قيم نوعها set هنا قمنا بتعريف كائنين من الكلاس set<int> set1 = {1, 2, 3, 4}; set<int> set2 = {5, 6, 7, 8}; // set2 مع قيم الكائن set1 هنا قمنا بتبديل قيم الكائن set1.swap(set2); cout << "set1 values = "; // إبتداءاً من أول عنصر وصولاً لآخر عنصر فيه set1 هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيمة عنصر جديد من العناصر الموجودة في الكائن for (auto it = set1.begin(); it != set1.end(); ++it) { cout << *it << " "; } cout << "\nset2 values = "; // إبتداءاً من أول عنصر وصولاً لآخر عنصر فيه set2 هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيمة عنصر جديد من العناصر الموجودة في الكائن for (auto it = set2.begin(); it != set2.end(); ++it) { cout << *it << " "; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
set1 values = 5 6 7 8 set2 values = 1 2 3 4
في المثال التالي قمنا بتخصيص الطريقة التي سيقوم فيها الكائن الذي ننشئه من الكلاس set
حتى يتناسب مع نوع العناصر التي سنقوم بتخزينها فيه.
في البداية قمنا بتعريف كلاس إسمه Book
يمثل الشكل العام لأي كتاب و هو يحتوي على خاصيّتين و هما إسم الكتاب title
و رقم التعرفة id
الخاص به.
بعدها قمنا بإنشاء كلاس إسمه Compare
سنستخدمه لنحدد الطريقة التي سيتم على أساسها ترتيب قيم العناصر.
في هذا الكلاس قمنا بإنشاء عامل ( Operator ) يملك باراميترين نوعهما Book
لأن فكرة هذا العامل أنه يقارن أي عنصر جديد ( عبارة عن كائن من Book
) نقوم بإضافته مع أول عنصر موجود في الكائن. لذا الباراميتر الأول يعتبر العنصر الأول الموجود في الكائن و الباراميتر الثاني يعتبر العنصر الجديد الذي سيتم إضافته.
على هذا الأساس قمنا بتحديد أنه في حال كانت قيمة id
في الباراميتر الأول أصغر من قيمة id
في الباراميتر الثاني سيتم وضع العنصر الذي تم تمريره في الباراميتر الأول في بداية الكائن.
في الأخير قمنا بإنشاء ثلاث كائنات من الكلاس Book
لأنها ستكون بمثابة العناصر التي سنقوم بتخزينها في الحاوية.
و من ثم قمنا بإنشاء كائن من set
مع تحديد أنه سيتم تخزين عناصر نوعها Book
فيه و أنه سيستخدم العامل الموجود في الكلاس Compare
حتى يرتب العناصر التي نضيفها فيه و من بعدها أضفنا العناصر فيه, ثم قمنا بعرضها بواسطة حلقة.
ملاحظة: قمنا باستخدام الحلقة Foreach عند عرض قيم العناصر.
المثال السابع
using namespace std; // Book هنا قمنا بتعريف الكلاس class Book { public: // هنا قمنا بتعريف خصائص الكلاس int id; string title; // هنا قمنا بتعريف كونستكتور للكلاس حتى نستطيع تمرير قيم للخصائص بشكل مباشر عند إنشاء كائن منه Book(int id, string title) { this->id = id; this->title = title; } }; // set و الذي سنستخدمه لاحقاً لتحديد كيف ستترتب العناصر في الحاوية التي ننشئها من الكلاس Compare هنا قمنا بتعريف الكلاس class Compare { public: // id حتى يقارن قيمة set هنا قمنا بتعريف العامل الذي سيستخدمه الكائن الذي ننشئه من الكلاس // الموجودة في أول عنصر فيها id في الكائن الذي سيتم إضافته في الحاوية مع قيمة bool operator() (Book b1, Book b2) { // الموجودة في العنصر الجديد أصغر من id هنا كأننا نعلم المترجم بأنه في حال كانت قيمة // الموجودة في العنصر الأول في الحاوية, فإننا نريد وضعها هي في البداية id قيمة return (b1.id < b2.id); } }; // main() هنا قمنا بتعريف الدالة int main() { // بالإضافة إلى Book يمكنه أن يحتوي على كائنات من الكلاس set هنا قمنا بتعريف كائن من الكلاس // من أجل تحديد الطريقة التي سيتم فيها ترتيب الكائنات التي نضيفها فيه Compare أنه يعتمد على الكلاس set<Book, Compare> mySet; // mySet لأننا سنضعها كعناصر في الحاوية Book هنا قمنا بإنشاء 3 كائنات من الكلاس Book book1(2, "C++ for beginner"); Book book2(1, "HTML5 for dummies"); Book book3(3, "Building Android apps"); // emplace() باستخدام الدالة mySet في الكائن book3, book2 و book1 هنا قمنا بإضافة الكائنات // {book2, book1, book3} فيها كالتالي id العناصر سيتم ترتيبها من الأسغر إلى الأكبر على حسب قيمة الخاصية mySet.emplace(book1); mySet.emplace(book2); mySet.emplace(book3); cout << "All books in mySet:\n"; // إبتداءاً من أول عنصر وصولاً لآخر عنصر فيه mySet هنا قمنا بإنشاء حلقة تقوم في كل دورة بطباعة قيم عنصر جديد من العناصر الموجودة في الكائن for (auto const &e: mySet) { cout << e.id << " - " << e.title << endl; } return 0; }
سنحصل على النتيجة التالية عند التشغيل.
All books in mySet: 1 - HTML5 for dummies 2 - C++ for beginner 3 - Building Android apps