المصفوفات و vector في C++
في C تعلمت المصفوفات التقليدية: ثابتة الحجم، ولا تعرف حجمها، ولا تحميك من تجاوز حدودها. C++ تحتفظ بها، لكنها تقدم بديلاً أذكى بكثير يستخدمه المبرمجون في الأغلبية العظمى من الحالات: vector. في هذا الدرس ستتعرف على الاثنين، ومعهما أدوات جاهزة للترتيب والبحث والجمع.
المصفوفة التقليدية
Section titled “المصفوفة التقليدية”int scores[4] = {85, 92, 78, 64};cout << scores[0] << endl;cout << size(scores) << endl;854نفس المصفوفة التي عرفتها في C: الترقيم من صفر، والحجم ثابت. و size() (من C++17) تعطيك عدد العناصر بسهولة بدلاً من حيلة sizeof.
vector: المصفوفة المرنة
Section titled “vector: المصفوفة المرنة”#include <vector>
vector<int> marks = {85, 92, 78};marks.push_back(64);marks[1] = 95;cout << marks.size() << endl;for (int m : marks) cout << m << " ";cout << endl;485 95 78 64vector<int>: قائمة من الأعداد الصحيحة، ونوع العناصر بين< >.push_back: إضافة عنصر في النهاية، فيكبر الـ vector تلقائياً.size(): عدد العناصر.[ ]: الوصول للعناصر كالمصفوفة تماماً.
تخيّل المصفوفة التقليدية مثل علبة بيض بعدد ثابت من الأماكن، و vector مثل حقيبة قابلة للتمدد: تكبر كلما أضفت إليها، وتدير مساحتها بنفسها.
المزيد من دوال vector
Section titled “المزيد من دوال vector”marks.pop_back();cout << marks.size() << " " << marks.back() << endl;cout << marks.front() << endl;3 7885| الدالة | وظيفتها |
|---|---|
push_back(x) |
إضافة في النهاية |
pop_back() |
حذف آخر عنصر |
front() و back() |
أول وآخر عنصر |
size() و empty() |
العدد، وهل هو فارغ |
erase(v.begin() + i) |
حذف العنصر رقم i |
at(i) |
الوصول الآمن للعنصر |
at: الوصول الآمن
Section titled “at: الوصول الآمن”try { cout << marks.at(10) << endl;} catch (const out_of_range& e) { cout << "خطأ: رقم خارج الحدود" << endl;}خطأ: رقم خارج الحدودمع [ ]، تجاوز الحدود سلوك غير محدد خطير كما في C. أما at() فتفحص الحدود، وترمي استثناءً يمكن التقاطه بـ try و catch. استخدمها عندما لا تكون متأكداً من الرقم، مثل رقم أدخله المستخدم.
مكتبة algorithm
Section titled “مكتبة algorithm”C++ تأتي مع مكتبة ضخمة من الخوارزميات الجاهزة:
#include <algorithm>#include <numeric>
vector<int> nums = {5, 3, 9, 1};sort(nums.begin(), nums.end());for (int x : nums) cout << x << " ";cout << endl;cout << accumulate(nums.begin(), nums.end(), 0) << endl;cout << *max_element(nums.begin(), nums.end()) << endl;1 3 5 9189sort: ترتيب تصاعدي.accumulate: المجموع، بدءاً من القيمة 0.max_element: يُرجع مكان أكبر عنصر، والنجمة*تعطينا قيمته.begin()وend()تحددان النطاق: من أول عنصر حتى ما بعد آخر عنصر. وهي طريقة المكتبة القياسية في التعامل مع أي مجموعة.
ومع الـ Lambda التي تعلمتها في الدرس السابق:
vector<int> grades = {85, 92, 78, 64, 50};int passed = count_if(grades.begin(), grades.end(), [](int g) { return g >= 75; });cout << passed << endl;3count_if تعد العناصر التي تحقق شرطاً تعطيه لها كـ Lambda.
vector ثنائي الأبعاد
Section titled “vector ثنائي الأبعاد”vector<vector<int>> grid = {{1, 2, 3}, {4, 5, 6}};cout << grid[1][2] << endl;for (const auto& row : grid) { for (int v : row) cout << v << " "; cout << endl;}61 2 34 5 6vector كل عنصر فيه vector: جدول بصفوف وأعمدة. و auto هنا توفر عليك كتابة النوع الطويل vector<int>.
array: الحجم الثابت الحديث
Section titled “array: الحجم الثابت الحديث”إذا كان الحجم ثابتاً فعلاً ومعروفاً، هناك array من المكتبة القياسية:
#include <array>
array<int, 3> fixedArr = {7, 8, 9};cout << fixedArr.size() << endl;3مثل المصفوفة التقليدية في السرعة، لكنها تعرف حجمها، وتدعم at() وكل دوال algorithm.
جرّب بنفسك
Section titled “جرّب بنفسك”- أنشئ
vector<string>لقائمة مهام، أضف 4 مهام بـpush_back، واحذف الأولى بـerase، واطبع الباقي. - أنشئ vector بدرجات 6 طلاب، ورتبها، واطبع أعلى وأقل درجة والمتوسط.
- استخدم
count_ifلعد الدرجات الأقل من 50. - تحدٍّ: اطلب من المستخدم أرقاماً بـ
cinحتى يدخل صفراً، وخزنها في vector، ثم اطبع مجموعها مرتبة.
أخطاء شائعة
Section titled “أخطاء شائعة”- تجاوز الحدود بـ [ ]: لا تحذير ولا خطأ واضح. استخدم
at()عند الشك. - نسيان #include:
vectorتحتاج<vector>، وsortتحتاج<algorithm>، وaccumulateتحتاج<numeric>. - حذف عناصر أثناء المرور عليها بحلقة range-for: يسبب أخطاء خطيرة. اجمع ما تريد حذفه أولاً، أو استخدم دوال المكتبة المخصصة لذلك.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
ما الفرق بين v[10] و v.at(10) إذا كان الـ vector فيه 4 عناصر؟
at() آمنة لأنها تفحص الحدود، أما [ ] فلا تفحص، وتجاوز الحدود بها سلوك غير محدد.
سؤال
أي دالة تضيف عنصراً في نهاية vector؟
push_back تضيف في النهاية، و pop_back تحذف آخر عنصر.
الخلاصة
Section titled “الخلاصة”- المصفوفة التقليدية ثابتة الحجم، و
size()تعطي عدد عناصرها. vectorمصفوفة مرنة:push_backوpop_backوsizeوfrontوback.at()للوصول الآمن مع فحص الحدود.algorithmوnumericفيهماsortوaccumulateوmax_elementوcount_if.vector<vector<int>>للجداول، وarrayللحجم الثابت الحديث.