مقدمة: لماذا دمج المتجهات ولماذا هو صعب؟
\n\nمرحباً أيها الزميل! إذا كنت قد كتبت يوماً ما كوداً بلغة C++ يعالج قوائم البيانات، فبالتأكيد واجهت هذه المهمة: "لدي اثنان من std::vector، كيف أجعلهما واحداً؟" هذا السؤال هو ضربة حقيقية على Stack Overflow (آلاف المشاهدات!)، وليس من دون سبب. للوهلة الأولى يبدو: ما الصعوبة في ذلك؟ vector1 + vector2، كما في Python؟ لكن لا. في C++، عامل التشغيل + غير مُعرّف للمتجهات. عليك أن تحتال.
اليوم سنشرح دمج اثنين من std::vectors بالكامل. سأريك 3 طرق مجربة، وسأشرح متى تستخدم كل منها، وسأحذرك من المزالق التي يقع فيها حتى المطورون ذوو الخبرة. هيا بنا!
\n\nالطريقة رقم 1: insert() — الكلاسيكية
\n\nالطريقة الأكثر وضوحاً والأكثر استخداماً هي طريقة insert(). تسمح لك بإدراج جميع عناصر متجه واحد في نهاية متجه آخر. الصيغة بسيطة وأنيقة:
#include <iostream>\n#include <vector>\n\nint main() {\n std::vector<int> vec1 = {1, 2, 3};\n std::vector<int> vec2 = {4, 5, 6};\n\n // الدمج: إدراج vec2 في نهاية vec1\n vec1.insert(vec1.end(), vec2.begin(), vec2.end());\n\n // الإخراج: 1 2 3 4 5 6\n for (int v : vec1) std::cout << v << " ";\n return 0;\n}\n\nكيف يعمل هذا: نقول للمترجم: "بدءاً من الموضع vec1.end() (أي بعد العنصر الأخير من المتجه الأول)، انسخ كل ما هو موجود بين vec2.begin() و vec2.end()". وهكذا — تم دمج المتجهات في C++.
إيجابيات وسلبيات insert()
\n- \n
- ✅ الإيجابيات: البساطة، سهولة القراءة، تعمل مع أي أنواع. \n
- ❌ السلبيات: إذا كان
vec1صغيراً وvec2ضخماً، فقد يحدث عدة عمليات إعادة توزيع للذاكرة أثناء الإدراج. هذا يقلل من الأداء عند دمج المتجهات ذات الأحجام الكبيرة. \n
نصيحة: إذا كنت تعرف الحجم النهائي، قم باستدعاء vec1.reserve(vec1.size() + vec2.size()) مسبقاً. هذا سيوفر عليك التخصيصات الزائدة.
الطريقة رقم 2: std::merge() — للبيانات المرتبة
\n\nماذا لو كانت متجهاتك مرتبة بالفعل؟ أو إذا كنت لا تحتاج فقط إلى الدمج، بل إلى الحصول على مصفوفة مرتبة واحدة؟ هنا يأتي دور خوارزمية std::merge من ملف الرأس <algorithm>.
#include <iostream>\n#include <vector>\n#include <algorithm> // لـ std::merge\n\nint main() {\n std::vector<int> vec1 = {1, 3, 5};\n std::vector<int> vec2 = {2, 4, 6};\n std::vector<int> result;\n\n // حجز مساحة لتجنب النسخ الزائد\n result.reserve(vec1.size() + vec2.size());\n\n // دمج نطاقين مرتبين\n std::merge(vec1.begin(), vec1.end(),\n vec2.begin(), vec2.end(),\n std::back_inserter(result));\n\n // الإخراج: 1 2 3 4 5 6\n for (int v : result) std::cout << v << " ";\n return 0;\n}\n\nلاحظ: std::merge يتطلب أن يكون كلا النطاقين المدخلين مرتبين تصاعدياً. إذا لم يكن الأمر كذلك، ستكون النتيجة غير متوقعة. لكن إذا كانت البيانات مرتبة، فهذه الطريقة هي ملك الأداء: التعقيد O(n + m).
متى تستخدم std::merge؟
\n- \n
- إذا كنت تدمج نتائج استعلامين من SQL أو سجلات مرتبة حسب الوقت. \n
- عندما تحتاج ليس فقط إلى دمج اثنين من std::vectors، بل إلى دمج مرتب تحديداً. \n
- إذا كان لا يمكن تعديل المتجهات الأصلية (نقوم بإنشاء متجه ثالث
result). \n
الطريقة رقم 3: Move semantics — السرعة لـ C++11 والإصدارات الأحدث
\n\nلنفترض أنك لا تحتاج إلى المتجهات الأصلية بعد