ما معنى Matrix (المصفوفة) في الخوارزميات وهياكل البيانات؟ شرح عملي مبسّط

شروحات تقنية

في مجال الخوارزميات وهياكل البيانات، تعني كلمة Matrix (المصفوفة) جدولًا مكوّنًا من صفوف وأعمدة تُخزَّن فيه البيانات، ويُوصَل إلى كل عنصر عبر رقمين: رقم الصف ورقم العمود. بعبارة أبسط، هي مصفوفة ثنائية الأبعاد (2D Array): صندوق منظّم على شكل شبكة، كل خانة فيه لها عنوان محدّد مثل M[i][j]. هذا هو جوهر المفهوم، وكل ما تبقّى مجرد تفصيل لكيفية استخدامه.

من المهم عدم الخلط بين معنيين للكلمة: هناك المصفوفة الرياضية في الجبر الخطي (كائن رياضي له قواعد ضرب وجمع محدّدة)، وهناك المصفوفة كهيكل بيانات في البرمجة (طريقة لتخزين قيم في شبكة داخل الذاكرة). المفهومان مترابطان لكنهما ليسا الشيء نفسه؛ ففي كثير من مسائل البرمجة نستخدم "المصفوفة" لتمثيل شبكة ألعاب أو خريطة أو جدول، دون أي علاقة بالضرب الرياضي إطلاقًا.

كيف تُخزَّن المصفوفة فعليًا في الذاكرة؟

قد تتخيّل المصفوفة كشبكة مربّعات، لكن ذاكرة الحاسوب في الحقيقة خط مستقيم واحد. لذلك يقوم المترجم بترتيب عناصر المصفوفة في الذاكرة بإحدى طريقتين:

  • حسب الصفوف (Row-major): تُخزَّن عناصر الصف الأول كاملة، ثم الصف الثاني، وهكذا. تعتمده لغات مثل C و C++ و Python.
  • حسب الأعمدة (Column-major): تُخزَّن الأعمدة أولًا. تعتمده لغات مثل Fortran و MATLAB.

هذا التفصيل ليس ترفًا نظريًا: عندما تمرّ على المصفوفة بترتيب مطابق لطريقة تخزينها، يعمل الكود أسرع بشكل ملموس بفضل كفاءة الذاكرة المؤقتة (Cache). لذلك ينصح المبرمجون المتمرّسون بجعل الحلقة الخارجية على الصفوف والداخلية على الأعمدة في لغات مثل C.

أشهر استخدامات المصفوفة في الخوارزميات

المصفوفة أحد أكثر الهياكل حضورًا في المسائل العملية، ومن أبرز استخداماتها:

  1. الشبكات والخرائط: تمثيل رقعة شطرنج، لعبة، متاهة، أو خريطة مواقع كل خانة فيها حالة (فارغة/مشغولة).
  2. مصفوفة الجوار (Adjacency Matrix): تمثيل الروابط بين عُقد الرسوم البيانية (Graphs)، حيث تعني M[i][j] = 1 وجود حافة بين العقدة i والعقدة j.
  3. البرمجة الديناميكية (Dynamic Programming): بناء جداول لحفظ الحلول الجزئية، كما في مسائل أطول سلسلة فرعية مشتركة أو مسافة التحرير.
  4. معالجة الصور: كل صورة رقمية هي في جوهرها مصفوفة من البكسلات، وكل قيمة تمثّل درجة لون أو شدة إضاءة.

العمليات الأساسية وتكلفتها الزمنية

فهم "تكلفة" العملية أهم من حفظ خطواتها. إليك أبرزها لمصفوفة أبعادها n × n:

  • الوصول لعنصر عبر M[i][j]: فوري، بتعقيد ثابت O(1). هذه أقوى ميزات المصفوفة.
  • الجمع والطرح: يتطلبان مرور المصفوفتين بنفس الأبعاد، وتعقيدهما O(n²).
  • الضرب: العملية الأثقل، وتعقيدها المباشر O(n³)، ولها خوارزميات متقدمة تخفّضه.
  • البحث عن قيمة في مصفوفة غير مرتّبة: O(n²) لأنه يتطلب فحص كل خانة.

مصفوفة الجوار أم قائمة الجوار لتمثيل الرسوم البيانية؟

عند تمثيل رسم بياني، يحتار المبتدئ بين المصفوفة والقائمة. الاختيار يعتمد على كثافة الروابط:

المعيارمصفوفة الجوارقائمة الجوار
استهلاك الذاكرةO(n²) دائمًاO(n + عدد الحواف)
التحقق من وجود حافةفوري O(1)أبطأ O(درجة العقدة)
الأنسب لـالرسوم الكثيفة الروابطالرسوم المتفرّقة الروابط
المرور على جيران عقدةO(n)سريع بقدر عدد الجيران

الخلاصة: إن كانت الروابط كثيفة وتحتاج فحصًا سريعًا للحواف، فالمصفوفة أنسب. أما إن كان الرسم كبيرًا ومتفرّق الروابط، فقائمة الجوار توفّر ذاكرة هائلة.

نصيحة عملية وخطأ شائع

الخطأ الأكثر تكرارًا بين المبتدئين هو الخلط بين ترتيب الفهرسين. في معظم اللغات M[i][j] تعني الصف i ثم العمود j، لكن كثيرين يكتبونها بالعكس فتظهر أخطاء "خارج الحدود" (Index out of bounds) أو نتائج مقلوبة.

نصيحة من التجربة: عند إنشاء مصفوفة في لغة مثل Python، لا تنشئها بالطريقة [[0]*n]*n، لأنها تنشئ إشارات لنفس الصف فيتغيّر كل الصفوف معًا عند تعديل خانة واحدة. استخدم بدلًا منها [[0]*n for _ in range(n)] لضمان صفوف مستقلة. هذا الخطأ يضيّع ساعات من التصحيح على من لا ينتبه له.

الأسئلة الشائعة

ما الفرق بين المصفوفة والمصفوفة الأحادية (Array)؟ المصفوفة الأحادية سطر واحد من العناصر تُفهرَس برقم واحد، بينما المصفوفة ثنائية الأبعاد شبكة تُفهرَس برقمين (صف وعمود). عمليًا، المصفوفة ثنائية الأبعاد ليست إلا مصفوفة أحادية "من مصفوفات أحادية".

هل يجب أن تكون المصفوفة مربّعة الشكل؟ لا. المصفوفة المربّعة عدد صفوفها يساوي أعمدتها، لكن يمكن أن تكون مستطيلة (m × n) بأي أبعاد. بعض العمليات كالضرب في نفسها تتطلب الشكل المربّع فقط.

متى أستخدم مصفوفة ومتى أستخدم هيكلًا آخر؟ استخدم المصفوفة حين تكون بياناتك منظّمة طبيعيًا في شبكة والوصول العشوائي السريع مهمًا. أما إن كانت البيانات متفرّقة (أغلبها أصفار)، ففكّر في المصفوفات المتفرّقة (Sparse Matrix) أو جداول التجزئة لتوفير الذاكرة.

هل تدعم كل لغات البرمجة المصفوفات متعددة الأبعاد؟ معظمها نعم، لكن بطرق مختلفة: بعضها يوفّرها أصلية مثل C، وبعضها عبر مكتبات مثل NumPy في Python التي تجعل التعامل معها أسرع وأسهل بكثير من القوائم العادية.