🎯 ترتيب الدمج

دليل دراسة شامل

📚 جدول المحتويات

📖 نظرة عامة

ما هو ترتيب الدمج؟

ترتيب الدمج هو خوارزمية ترتيب كلاسيكية تعتمد على استراتيجية "فرّق تسد" وكانت واحدة من أولى الخوارزميات التي حققت تعقيدًا زمنيًا O(N log N). تُعتبر واحدة من أفضل 10 خوارزميات في القرن العشرين في العلوم والهندسة.

🎯 الخطة الأساسية

  1. الفرق: تقسيم المصفوفة إلى نصفين
  2. التسيّد: ترتيب كل نصف بشكل متكرر
  3. الجمع: دمج النصفين المرتّبين معًا

مثال: ترتيب "MERGESORTEXAMPLE"

المدخلات:

M E R G E S O R T E X A M P L E

⬇️ بعد ترتيب النصف الأيسر ⬇️

E E G M O R R S T E X A M P L E

⬇️ بعد ترتيب النصف الأيمن ⬇️

E E G M O R R S A E E L M P T X

⬇️ بعد الدمج ⬇️

A E E E E G L M M O P R R S T X

⚙️ كيف يعمل ترتيب الدمج

عملية الدمج

الهدف: إعطاء مصفوفتين فرعيتين مرتبتين a[lo] إلى a[mid] وa[mid+1] إلى a[hi]، استبدلهما بمصفوفة فرعية مرتبة واحدة a[lo] إلى a[hi].

مثال الدمج

مصفوفتان فرعيتان مرتبتان:

E E G M R | A C E R T

⬇️ بعد الدمج ⬇️

A C E E E G M R R T

خطوات خوارزمية الدمج

  1. نسخ المصفوفتين الفرعيتين إلى مصفوفة مساعدة
  2. مقارنة العناصر من كل مصفوفة فرعية
  3. اختيار العنصر الأصغر ووضعه في النتيجة
  4. تكرار حتى يتم دمج جميع العناصر

💻 التنفيذ بلغة جافا

دالة الدمج

private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
    // نسخ العناصر إلى المصفوفة المساعدة
    for (int k = lo; k <= hi; k++)
        aux[k] = a[k];
    
    // الدمج مرة أخرى إلى المصفوفة الأصلية
    int i = lo, j = mid + 1;
    for (int k = lo; k <= hi; k++) {
        if      (i > mid)              a[k] = aux[j++];  // الجزء الأيسر نفد
        else if (j > hi)               a[k] = aux[i++];  // الجزء الأيمن نفد
        else if (less(aux[j], aux[i])) a[k] = aux[j++];  // الجزء الأيمن أصغر
        else                            a[k] = aux[i++];  // الجزء الأيسر أصغر أو مساوي
    }
}

ترتيب الدمج من الأعلى للأسفل

public class Merge {
    private static void merge(...) { /* كما بالأعلى */ }
    
    private static void sort(Comparable[] a, Comparable[] aux, 
                                   int lo, int hi) {
        if (hi <= lo) return;                // الحالة الأساسية
        
        int mid = lo + (hi - lo) / 2;      // إيجاد المنتصف
        
        sort(a, aux, lo, mid);                // ترتيب النصف الأيسر
        sort(a, aux, mid + 1, hi);            // ترتيب النصف الأيمن
        merge(a, aux, lo, mid, hi);           // دمج النتائج
    }
    
    public static void sort(Comparable[] a) {
        Comparable[] aux = new Comparable[a.length];
        sort(a, aux, 0, a.length - 1);
    }
}

📝 ملاحظات مهمة في التنفيذ

  • يتم إنشاء المصفوفة المساعدة مرة واحدة وإعادة استخدامها خلال التكرار
  • عملية الدمج في نفس المكان (تعدل المصفوفة الأصلية)
  • الخوارزمية ليست في نفس المكان تمامًا (تحتاج إلى مساحة إضافية O(N))
  • الحالة الأساسية: عندما تحتوي المصفوفة الفرعية على 1 أو 0 عناصر، فهي مرتبة بالفعل

📊 تحليل التعقيد

التعقيد الزمني

O(N log N)

أفضل حالة، متوسط حالة، وأسوأ حالة

التعقيد المكاني

O(N)

للمصفوفة المساعدة

المقارنات

≤ N lg N

الحد الأعلى

وصولات المصفوفة

≤ 6N lg N

الحد الأعلى

لماذا O(N log N)؟

علاقة التكرار:

T(N) = 2T(N/2) + N

  • 2T(N/2): مكالمتين متكررتين على أنصاف المصفوفة
  • N: وقت خطي لدمج النصفين
  • عمق شجرة التكرار: log₂ N (القسمة على 2 في كل مرة)
  • العمل في كل مستوى: N (عمليات الدمج)
  • إجمالي العمل: N × log₂ N = O(N log N)

التحليل التجريبي

الحاسوب ألف (10³) مليون (10⁶) مليار (10⁹)
منزلي (10⁸ مقارنة/ثانية) لحظي ثانية واحدة 18 دقيقة
خارق (10¹² مقارنة/ثانية) لحظي لحظي لحظي

✨ النتيجة الأساسية

الخوارزميات الجيدة أفضل من الحواسيب الخارقة!

ترتيب الدمج على حاسوب منزلي يتفوق على ترتيب الإدراج (O(N²)) على حاسوب خارق للمجموعات الكبيرة.

🔄 ترتيب الدمج من الأسفل للأعلى

نهج بديل: غير متكرر

بدلاً من تقسيم المصفوفة بشكل متكرر، ابدأ بمصفوفات فرعية صغيرة وادمجها بشكل تكراري.

الخوارزمية

  1. مرّر المصفوفة، وادمج المصفوفات الفرعية بحجم 1
  2. كرّر للمصفوفات الفرعية بحجم 2، 4، 8، 16، ...
  3. استمر حتى يتم ترتيب المصفوفة بالكامل

التنفيذ

public static void sort(Comparable[] a) {
    int N = a.length;
    Comparable[] aux = new Comparable[N];
    
    // sz: حجم المصفوفات الفرعية للدمج (1, 2, 4, 8, ...)
    for (int sz = 1; sz < N; sz = sz + sz) {
        // lo: بداية المصفوفة الفرعية اليسرى
        for (int lo = 0; lo < N - sz; lo += sz + sz) {
            merge(a, aux, lo, lo + sz - 1, 
                  Math.min(lo + sz + sz - 1, N - 1));
        }
    }
}

✅ المزايا

  • بسيط وأنيق
  • لا توجد تكلفة إضافية للتكرار
  • نفس ضمان O(N log N)
  • جيد للأنظمة التي لا تدعم التكرار

❌ العيوب

  • أبطأ بحوالي 10% من النسخة من الأعلى للأسفل على الأنظمة النموذجية
  • أقل توافقية مع الذاكرة المخبئية
  • أصعب لتحسينه باستخدام القطع لترتيب الإدراج

⚖️ الاستقرار

ما هو الاستقرار؟

خوارزمية الترتيب مستقرة إذا حافظت على الترتيب النسبي للعناصر ذات المفاتيح المتساوية.

لماذا يهم الاستقرار؟

حالة استخدام نموذجية: الترتيب بمعايير متعددة

  1. أولاً، الترتيب حسب الاسم (أبجديًا)
  2. ثم، الترتيب حسب رقم القسم

مع خوارزمية ترتيب مستقرة، يبقى الطلاب في نفس القسم مرتبين حسب الاسم!

مثال: سجلات الطلاب

الاسم القسم بعد الترتيب حسب القسم (مستقر)
Andrews 3 Andrews (3) ← لا يزال مرتبًا!
Chen 3 Chen (3) ← لا يزال مرتبًا!
Fox 3 Fox (3) ← لا يزال مرتبًا!

هل ترتيب الدمج مستقر؟

✅ نعم! ترتيب الدمج مستقر

الفكرة الرئيسية: عملية الدمج تأخذ من المصفوفة الفرعية اليسرى عندما تكون المفاتيح متساوية.

if (less(aux[j], aux[i])) a[k] = aux[j++];
else                      a[k] = aux[i++];  // تأخذ من اليسار إذا تساوت

مقارنة الاستقرار

الخوارزمية مستقر؟ السبب
ترتيب الإدراج ✓ نعم العناصر المتساوية لا تتحرك بعد بعضها
ترتيب الاختيار ✗ لا التبادلات بعيدة المدى قد تحرك العناصر المتساوية
ترتيب الدمج ✓ نعم عملية الدمج تحافظ على الترتيب
ترتيب شيل ✗ لا تبادلات بعيدة المدى

🔧 المقارنات

ما هو المقارن؟

المقارن هو واجهة في جافا تسمح لك بتحديد منطق مقارنة مخصص، منفصل عن الترتيب الطبيعي للنوع.

Comparable مقابل Comparator

Comparable Comparator
ترتيب طبيعي (جزء من الفئة) ترتيب بديل (فئة منفصلة)
طريقة compareTo() طريقة compare()
ترتيب واحد لكل فئة ترتيبات متعددة ممكنة
Arrays.sort(array) Arrays.sort(array, comparator)

مثال: مقارنات الطلاب

public class Student {
    private final String name;
    private final int section;
    
    // مقارن للترتيب حسب الاسم
    public static class ByName implements Comparator<Student> {
        public int compare(Student v, Student w) {
            return v.name.compareTo(w.name);
        }
    }
    
    // مقارن للترتيب حسب القسم
    public static class BySection implements Comparator<Student> {
        public int compare(Student v, Student w) {
            return v.section - w.section;
        }
    }
}

// الاستخدام:
Arrays.sort(students, new Student.ByName());
Arrays.sort(students, new Student.BySection());

ترتيبات النصوص الشائعة

نوع الترتيب مثال
طبيعي Now is the time
غير حساس لحالة الأحرف is Now the time
إسباني café cafetero churro cuarto nube ñoño
دليل الهاتف البريطاني McKinley Mackintosh

📝 الملخّص والمقارنة

مقارنة خوارزميات الترتيب

الخوارزمية في نفس المكان؟ مستقر؟ أفضل متوسط أسوأ ملاحظات
ترتيب الاختيار ½N² ½N² ½N² N تبادل
ترتيب الإدراج N ¼N² ½N² استخدم لـ N صغيرة أو مرتبة جزئيًا
ترتيب شيل N log N ؟ N^(3/2) كود مضغوط؛ تحت تربيعي
ترتيب الدمج ½N log N N log N N log N ضمان N log N؛ مستقر

✅ مزايا ترتيب الدمج

  • ضمان O(N log N) في جميع الحالات
  • مستقر - يحافظ على الترتيب النسبي
  • أداء متوقع
  • قابل للتوزيع الموازي
  • جيد للترتيب الخارجي
  • مستخدم في Arrays.sort() في جافا للكائنات

❌ عيوب ترتيب الدمج

  • ليس في نفس المكان - يحتاج مساحة إضافية O(N)
  • أبطأ من الترتيب السريع عمليًا
  • غير تكيّفي للبيانات المرتبة مسبقًا
  • تكلفة إضافية من نسخ المصفوفات

🎯 متى تستخدم ترتيب الدمج

  • الاستقرار مطلوب (الترتيب بمفاتيح متعددة)
  • ضمان O(N log N) ضروري
  • العمل مع قوائم متصلة (يمكن أن يكون في نفس المكان مع القوائم)
  • الترتيب الخارجي (البيانات لا تتسع في الذاكرة)
  • الترتيب الموازي (سهل التوزيع الموازي)
  • المساحة الإضافية ليست مشكلة

🔑 نقاط رئيسية

  1. يحقق ترتيب الدمج O(N log N) من خلال فرّق تسد
  2. عملية الدمج هي المفتاح للخوارزمية
  3. إنه مستقر وله أداء مضمون
  4. مقايضة: مساحة O(N) مقابل وقت O(N log N)
  5. النسخة من الأسفل للأعلى تلغي تكلفة التكرار
  6. مستخدم على نطاق واسع عمليًا (جافا، بايثون، إلخ)

🎓 نصائح الدراسة

  • ✏️ تدرب على تتبع الخوارزمية على الورق بأمثلة صغيرة
  • 💡 افهم علاقة التكرار: T(N) = 2T(N/2) + N
  • 🔍 ركز على عملية الدمج - إنها قلب الخوارزمية
  • 📊 قارن مع خوارزميات ترتيب أخرى - اعرف المقايضات
  • 💻 نفّذ كلا النسختين - من الأعلى للأسفل ومن الأسفل للأعلى
  • 🎯 تذكّر الاستقرار - ميزة رئيسية على الترتيب السريع
  • 📝 تدرب على تحليل التعقيد - الوقت والمساحة