0Pricing
C Academy · درس

Mergesort

ترتيب مستقر

Mergesort درس مجاني في C Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C Academy 4 دروس في المجموع.

الفرز المستقر

يُعدّ Mergesort خوارزمية فرز بالتقسيم والدمج؛ إذ تقسّم المصفوفة إلى نصفين، وتفرز كل نصف، ثم تدمجهما مجددًا. تبلغ كلفته O(n log n) في جميع الحالات، وهو مستقر.

خطوة التقسيم

قسّم المصفوفة递递يًا عند نقطة المنتصف حتى يحتوي كل جزء على عنصر واحد. يكون العنصر الواحد مرتبًا تلقائيًا، وهذه هي حالة الأساس.

خطوة الدمج

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

#include <stdio.h>

void merge(int a[], int lo, int mid, int hi, int tmp[]) {
    int i = lo, j = mid + 1, k = lo;
    while (i <= mid && j <= hi)
        tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++];
    while (i <= mid) tmp[k++] = a[i++];
    while (j <= hi)  tmp[k++] = a[j++];
    for (int t = lo; t <= hi; t++) a[t] = tmp[t];
}

int main(void) {
    int a[] = {1, 4, 6, 2, 3, 5}; /* two sorted runs */
    int tmp[6];
    merge(a, 0, 2, 5, tmp);
    for (int i = 0; i < 6; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

سبب استقراره

يستخدم الدمج a[i] <= a[j]، لذلك عندما يتساوى عنصران، يختار العنصر من السلسلة اليسرى أولًا. وبما أن السلسلة اليسرى كانت تحتوي على العناصر الأسبق، يُحافَظ على الترتيب الأصلي.

المشغّل递递ي

يستدعي Mergesort نفسه递递يًا على كل نصف، ثم يدمجهما. نمرّر مخزنًا مؤقتًا مشتركًا لتجنب تخصيص الذاكرة في كل استدعاء.

#include <stdio.h>

void merge(int a[], int lo, int mid, int hi, int tmp[]) {
    int i=lo, j=mid+1, k=lo;
    while (i<=mid && j<=hi) tmp[k++] = (a[i]<=a[j]) ? a[i++] : a[j++];
    while (i<=mid) tmp[k++]=a[i++];
    while (j<=hi)  tmp[k++]=a[j++];
    for (int t=lo;t<=hi;t++) a[t]=tmp[t];
}
void msort(int a[], int lo, int hi, int tmp[]) {
    if (lo >= hi) return;
    int mid = lo + (hi - lo) / 2;
    msort(a, lo, mid, tmp);
    msort(a, mid + 1, hi, tmp);
    merge(a, lo, mid, hi, tmp);
}

int main(void) {
    int a[] = {5, 2, 9, 1, 3, 8, 4};
    int tmp[7];
    msort(a, 0, 6, tmp);
    for (int i = 0; i < 7; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

استخدام الذاكرة

على خلاف quicksort، يحتاج mergesort إلى ذاكرة إضافية بحجم O(n) لمخزن الدمج المؤقت. وهذا هو عيبه الرئيسي عند التعامل مع مصفوفات كبيرة جدًا مع محدودية الذاكرة.

‏O(n log n) مضمون

يقسّم الاستدعاء递递ي المصفوفة دائمًا إلى نصفين، مما ينتج مستويات عددها log n، ويدمج كل مستوى n من العناصر. لذلك تكون كلفة mergesort هي O(n log n) في حالات الأفضل والمتوسط والأسوأ، على خلاف quicksort.

حساب مستويات الدمج

يبلغ عدد مستويات الاستدعاء递递ي ceil(log2 n). لنحسبه لعدة أحجام.

#include <stdio.h>

int levels(int n) {
    int L = 0;
    while (n > 1) { n = (n + 1) / 2; L++; }
    return L;
}

int main(void) {
    int sizes[] = {1, 2, 8, 100, 1000};
    for (int i = 0; i < 5; i++)
        printf("n=%d levels=%d\n", sizes[i], levels(sizes[i]));
    return 0;
}

Mergesort من الأسفل إلى الأعلى

تدمج نسخة تكرارية سلاسل بحجم 1، ثم 2، ثم 4، مع مضاعفة الحجم في كل مرور. وهي تتجنب الاستدعاء递递ي تمامًا، وتناسب القوائم المترابطة.

#include <stdio.h>

void merge(int a[], int lo, int mid, int hi, int tmp[]) {
    int i=lo,j=mid+1,k=lo;
    while(i<=mid&&j<=hi) tmp[k++]=(a[i]<=a[j])?a[i++]:a[j++];
    while(i<=mid) tmp[k++]=a[i++];
    while(j<=hi) tmp[k++]=a[j++];
    for(int t=lo;t<=hi;t++) a[t]=tmp[t];
}

int main(void) {
    int a[] = {5, 2, 9, 1, 3, 8}, n = 6, tmp[6];
    for (int width = 1; width < n; width *= 2)
        for (int lo = 0; lo < n - width; lo += 2 * width) {
            int mid = lo + width - 1;
            int hi = (lo + 2*width - 1 < n-1) ? lo + 2*width - 1 : n-1;
            merge(a, lo, mid, hi, tmp);
        }
    for (int i = 0; i < n; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

متى تختار Mergesort

فضّل mergesort عندما تحتاج إلى:

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

Mergesort مقارنةً بـ Quicksort

يكون Quicksort عادةً أسرع عمليًا ويفرز داخل المصفوفة نفسها، لكنه غير مستقر وقد تكون له حالة أسوأ سيئة. أما Mergesort فهو مستقر وذو حد أداء مضمون، لكنه يستخدم ذاكرة إضافية. اختر الخوارزمية وفقًا لقيودك.

اختبار سريع

اختبر مدى فهمك لخوارزمية mergesort.

مراجعة

لقد تعلّمت خوارزمية mergesort.

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

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

هل درس «Mergesort» مجاني؟

نعم — نص درس «Mergesort» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.

ماذا ستتعلم في «Mergesort»؟

ترتيب مستقر تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟

لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «Mergesort»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟

نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ترتيبا الفقاعات والإدراج
  2. Quicksort
  3. Mergesort
  4. استخدام qsort
← العودة إلى C Academy