Sets

الـ set هو حاوية في C++ تخزّن قيمًا من نفس النوع بحيث:

  • كل قيمة تظهر مرة واحدة فقط.
  • القيم مرتّبة دائمًا (افتراضيًا، من الأصغر إلى الأكبر).
  • يمكنك التحقق بسرعة مما إذا كان شيء ما موجودًا فيها.
#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> numbers = {5, 2, 9, 2, 1};
    for (int x : numbers)
        cout << x << " ";
}
الناتج:
1 2 5 9

لاحظ أن الـ 2 الثانية اختفت — لأن الـ set لا يسمح بالقيم المكررة.

إنشاء set

لاستخدام الـ set، أضف الـ header التالي:
#include <set>
ثم يمكنك إنشاء set بهذه الطريقة:
set<int> mySet;              // empty set of integers
set<string> names;           // set of strings
set<char> letters = {'a','b','c'};
Note

يمكنك أيضًا تهيئته بقيم باستخدام الأقواس المعقوفة { }.

العمليات الأساسية

العملية مثال الشرح
insert(x) s.insert(5); يضيف 5 إلى الـ set. (إذا كان 5 موجودًا مسبقًا، لا يحدث شيء.)
erase(x) s.erase(5); يحذف 5 إن كان موجودًا.
find(x) if (s.find(5) != s.end()) يتحقق من وجود 5. يُعيد iterator (يشبه المؤشر).
count(x) if (s.count(5)) يُعيد 1 إن وُجد، و0 إن لم يوجد. أسهل للمبتدئين.
size() s.size(); عدد العناصر.
empty() s.empty(); يتحقق مما إذا كان الـ set فارغًا.
clear() s.clear(); يحذف جميع العناصر من الـ set.

مثال: استخدام الـ set

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s;

    s.insert(3);
    s.insert(1);
    s.insert(4);
    s.insert(3); // duplicate ignored

    cout << "Elements: ";
    for (int x : s) cout << x << " ";
    cout << endl;

    if (s.count(3))
        cout << "3 is in the set" << endl;

    s.erase(1);

    cout << "After removing 1: ";
    for (int x : s) cout << x << " ";
}
الناتج:
Elements: 1 3 4
3 is in the set
After removing 1: 3 4

التنقل عبر عناصر الـ set

يمكنك المرور على عناصر الـ set باستخدام حلقة range-based for أو iterator.

for (int x : s)
    cout << x << " ";
أو:
for (auto it = s.begin(); it != s.end(); it++)
    cout << *it << " ";

بما أن الـ set مرتّب، ستظهر العناصر دائمًا بترتيب معيّن.

أنواع الـ sets

النوع مرتّب؟ يسمح بالمكررات؟ السرعة (تقريبًا) ملاحظات
set نعم لا O(log n) يعمل داخليًا بشجرة متوازنة
multiset نعم نعم O(log n) يحتفظ بنسخ متعددة من نفس القيمة
unordered_set لا لا O(1) متوسطًا يستخدم الـ hashing، أسرع لكن الترتيب عشوائي

نصائح: إذا كان الترتيب مهمًا — استخدم set.
إذا احتجت لتخزين مكررات — استخدم multiset.
إذا كانت السرعة هي همّك الوحيد — استخدم unordered_set.

مثال: إزالة المكررات

#include <iostream>
#include <set>
#include <vector>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 2, 3, 4, 3, 1};
    set<int> unique;

    for (int x : nums)
        unique.insert(x);

    for (int x : unique)
        cout << x << " ";
}
الناتج:
1 2 3 4