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

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