Kodax

STL Algorithms — C++ المتقدم

خوارزميات STL

بدلاً من كتابة حلقة لكل مهمة، توفر <algorithm> و <numeric> أكثر من 100 خوارزمية مختبرة ومسمّاة. الكود يصبح يصف ماذا تريد:

vector<int> v = {40, 85, 62, 97};
// حلقة يدوية: عليك قراءتها لتفهم أنها تعدّ
int c = 0; for (int x : v) if (x > 50) c++;
// خوارزمية: الاسم يقول كل شيء
auto c2 = count_if(v.begin(), v.end(), [](int x) { return x > 50; });

الفكرة: نطاق [begin, end)

كل خوارزمية تعمل على نطاق من مكرِّرين: الأول مشمول والثاني غير مشمول. لذلك تعمل مع vector و deque و array و list وحتى المصفوفات العادية.

أهم الخوارزميات

| المهمة | الخوارزمية |

|---|---|

| بحث عن قيمة / شرط | find / find_if |

| هل يوجد/الكل/لا أحد | any_of / all_of / none_of |

| عدّ | count / count_if |

| ترتيب | sort، stable_sort، partial_sort |

| بحث ثنائي (في مرتّب) | binary_search، lower_bound |

| أكبر/أصغر | max_element، min_element، minmax_element |

| تحويل | transform |

| جمع/طي | accumulate (في <numeric>) |

| عكس / إزالة المكرر المتجاور | reverse / unique |

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {40, 85, 62, 97, 55, 30};

    sort(v.begin(), v.end());                                    // 30 40 55 62 85 97
    bool anyFail = any_of(v.begin(), v.end(), [](int x) { return x < 50; });
    int total = accumulate(v.begin(), v.end(), 0);               // ابدأ بـ 0 (int)
    auto it = find_if(v.begin(), v.end(), [](int x) { return x > 60; });

    vector<int> curved(v.size());
    transform(v.begin(), v.end(), curved.begin(), [](int x) { return min(x + 5, 100); });

    cout << boolalpha << anyFail << ' ' << total << ' ' << *it << ' ' << curved.back() << '\n';
    // true 369 62 100
}

⚠️ accumulate(v.begin(), v.end(), 0) مع أعداد عشرية يعطي ناتجاً صحيحاً مقطوعاً لأن النوع يُؤخذ من القيمة الابتدائية. استخدم 0.0.

الحذف: erase-remove

remove_if لا تحذف فعلاً؛ تنقل العناصر المحتفظ بها للأمام وتعيد مكرِّراً لبداية "البقايا". الحذف الحقيقي بـ erase:

#include <algorithm>
#include <vector>
using namespace std;

vector<int> nums = {1, 2, 3, 4, 5, 6};
// الطريقة الكلاسيكية:
// nums.erase(remove_if(nums.begin(), nums.end(), [](int x){ return x % 2 == 0; }), nums.end());
// C++20 — أبسط بكثير:
auto removed = erase_if(nums, [](int x) { return x % 2 == 0; });   // nums = {1, 3, 5}

الترتيب بمعيار مخصص

#include <algorithm>
#include <string>
#include <vector>
using namespace std;

struct Student { string name; int score; };
vector<Student> st = {{"سارة", 91}, {"عمر", 78}, {"ليلى", 91}};
// الأعلى درجة أولاً، وعند التساوي أبجدياً
// sort(st.begin(), st.end(), [](const Student& a, const Student& b) {
//     return a.score != b.score ? a.score > b.score : a.name < b.name;
// });

المقارنة يجب أن تكون "أصغر تماماً" (strict): استخدام >= بدل > يكسر sort (سلوك غير معرّف).

C++20 Ranges

نسخ أبسط تأخذ الحاوية مباشرة، وتدعم التركيب بـ |:

#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {5, 3, 8, 1, 9, 2};
    ranges::sort(v);                                         // بدون begin/end
    for (int x : v | views::filter([](int x) { return x % 2 == 1; })
                   | views::transform([](int x) { return x * x; }))
        cout << x << ' ';                                    // 1 9 25 81
    cout << '\n';
}

الـ views كسولة: لا تنشئ vector وسيطاً، بل تحسب كل عنصر عند الطلب.

تمرين

لديك vector<int> لدرجات: احذف الدرجات غير الصالحة (خارج 0–100) بـ erase_if، ثم احسب المتوسط بـ accumulate و نسبة الناجحين (≥ 50) بـ count_if، واطبع أعلى 3 درجات بـ partial_sort.

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;

int main() {
    vector<int> nums = {5, 2, 8, 1, 9, 3, 7, 4, 6};
    
    // ===== Non-modifying =====
    cout << "=== Non-modifying ===" << endl;
    
    // find
    auto it = find(nums.begin(), nums.end(), 8);
    if (it != nums.end()) {
        cout << "وجدنا 8 في الموقع: " << (it - nums.begin()) << endl;
    }
    
    // count
    vector<int> data = {1, 2, 2, 3, 2, 4, 2};
    cout << "عدد مرات 2: " << count(data.begin(), data.end(), 2) << endl;
    
    // all_of, any_of, none_of
    bool allPositive = all_of(nums.begin(), nums.end(), [](int x) { return x > 0; });
    bool hasEven = any_of(nums.begin(), nums.end(), [](int x) { return x % 2 == 0; });
    bool noNegative = none_of(nums.begin(), nums.end(), [](int x) { return x < 0; });
    
    cout << "كلها موجبة: " << (allPositive ? "نعم" : "لا") << endl;
    cout << "يوجد زوجي: " << (hasEven ? "نعم" : "لا") << endl;
    
    // ===== Modifying =====
    cout << "\n=== Modifying ===" << endl;
    
    // transform
    vector<int> squared(nums.size());
    transform(nums.begin(), nums.end(), squared.begin(), 
              [](int x) { return x * x; });
    
    cout << "مربعات: ";
    for (int n : squared) cout << n << " ";
    cout << endl;
    
    // replace
    vector<int> replaced = nums;
    replace(replaced.begin(), replaced.end(), 5, 50);
    cout << "بعد استبدال 5 بـ 50: ";
    for (int n : replaced) cout << n << " ";
    cout << endl;
    
    // fill
    vector<int> filled(5);
    fill(filled.begin(), filled.end(), 7);
    cout << "ملء بـ 7: ";
    for (int n : filled) cout << n << " ";
    cout << endl;
    
    // ===== Sorting =====
    cout << "\n=== Sorting ===" << endl;
    
    vector<int> toSort = nums;
    sort(toSort.begin(), toSort.end());
    cout << "تصاعدي: ";
    for (int n : toSort) cout << n << " ";
    cout << endl;
    
    sort(toSort.begin(), toSort.end(), greater<int>());
    cout << "تنازلي: ";
    for (int n : toSort) cout << n << " ";
    cout << endl;
    
    // partial_sort (أصغر 3)
    vector<int> partial = nums;
    partial_sort(partial.begin(), partial.begin() + 3, partial.end());
    cout << "أصغر 3: ";
    for (int i = 0; i < 3; i++) cout << partial[i] << " ";
    cout << endl;
    
    // ===== Numeric =====
    cout << "\n=== Numeric ===" << endl;
    
    int sum = accumulate(nums.begin(), nums.end(), 0);
    cout << "المجموع: " << sum << endl;
    
    int product = accumulate(nums.begin(), nums.end(), 1, multiplies<int>());
    cout << "الضرب: " << product << endl;
    
    // ===== Lambda المتقدمة =====
    cout << "\n=== Lambda ===" << endl;
    
    // Lambda مع capture
    int threshold = 5;
    int countAbove = count_if(nums.begin(), nums.end(), 
                              [threshold](int x) { return x > threshold; });
    cout << "أكبر من " << threshold << ": " << countAbove << endl;
    
    // Lambda مع modify
    vector<int> modified = nums;
    int multiplier = 2;
    for_each(modified.begin(), modified.end(), 
             [multiplier](int& x) { x *= multiplier; });
    cout << "مضروب في 2: ";
    for (int n : modified) cout << n << " ";
    cout << endl;
    
    return 0;
}
اختبر فهمك