0Pricing
C Academy · درس

qsort مع المقارِنات

Callbacks من المكتبة القياسية

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

الدالة القياسية qsort

توفر المكتبة القياسية الدالة qsort في <stdlib.h>، وهي دالة فرز عامة تعمل مع أي نوع من المصفوفات باستخدام استدعاء عكسي للمقارنة.

#include <stdio.h>
#include <stdlib.h>

int cmp_int(const void *a, const void *b) {
    int x = *(const int *)a;
    int y = *(const int *)b;
    return (x > y) - (x < y);
}

int main(void) {
    int a[] = {3, 1, 2};
    qsort(a, 3, sizeof(int), cmp_int);
    printf("%d %d %d\n", a[0], a[1], a[2]);
    return 0;
}

توقيع qsort

تستقبل qsort(base, count, size, compare) بداية المصفوفة، وعدد العناصر، وحجم العنصر، ودالة مقارنة.

وهي عامة لأنها تعمل مع البايتات الخام بالإضافة إلى دالة المقارنة التي توفرها.

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    return *(const int*)a - *(const int*)b;
}

int main(void) {
    int a[] = {9, 4, 7, 1};
    qsort(a, 4, sizeof(int), cmp);
    for (int i = 0; i < 4; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

عقد المقارنة

تُرجع دالة المقارنة قيمة سالبة إذا كان ينبغي أن يسبق العنصر الأول العنصر الثاني، وقيمة صفر إذا كانا متساويين، وقيمة موجبة إذا كان ينبغي أن يأتي بعده.

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    int x = *(const int*)a, y = *(const int*)b;
    if (x < y) return -1;
    if (x > y) return 1;
    return 0;
}

int main(void) {
    int a[] = {5, 2, 8, 2};
    qsort(a, 4, sizeof(int), cmp);
    for (int i = 0; i < 4; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

تحويل مؤشرات void

تستقبل دالة المقارنة const void * لكل عنصر. حوّل هذه المؤشرات إلى النوع الصحيح، ثم أزل الإشارة المرجعية لقراءة القيم.

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    double x = *(const double*)a;
    double y = *(const double*)b;
    return (x > y) - (x < y);
}

int main(void) {
    double d[] = {2.5, 1.1, 3.3};
    qsort(d, 3, sizeof(double), cmp);
    printf("%.1f %.1f %.1f\n", d[0], d[1], d[2]);
    return 0;
}

الترتيب التنازلي

اعكس المقارنة للفرز من الأكبر إلى الأصغر.

#include <stdio.h>
#include <stdlib.h>

int desc(const void *a, const void *b) {
    int x = *(const int*)a, y = *(const int*)b;
    return (y > x) - (y < x);
}

int main(void) {
    int a[] = {1, 5, 3, 2};
    qsort(a, 4, sizeof(int), desc);
    for (int i = 0; i < 4; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

تجنّب فيضان الطرح

قد يؤدي إرجاع x - y إلى فيضان عند التعامل مع أعداد صحيحة كبيرة. وتتجنب الصيغة الآمنة (x > y) - (x < y) ذلك.

#include <stdio.h>
#include <stdlib.h>

int safe_cmp(const void *a, const void *b) {
    int x = *(const int*)a, y = *(const int*)b;
    return (x > y) - (x < y);
}

int main(void) {
    int a[] = {100, -100, 0};
    qsort(a, 3, sizeof(int), safe_cmp);
    for (int i = 0; i < 3; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

فرز السلاسل النصية

في مصفوفة من النوع char *، يكون كل عنصر مؤشرًا بحد ذاته؛ لذا حوّله إلى const char * const * وقارنه باستخدام strcmp.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp_str(const void *a, const void *b) {
    const char *sa = *(const char * const *)a;
    const char *sb = *(const char * const *)b;
    return strcmp(sa, sb);
}

int main(void) {
    const char *w[] = {"pear", "apple", "fig"};
    qsort(w, 3, sizeof(char*), cmp_str);
    for (int i = 0; i < 3; i++) printf("%s ", w[i]);
    printf("\n");
    return 0;
}

فرز البنى

تتعامل qsort أيضًا مع مصفوفات البنى. قارن حقلًا محددًا داخل دالة المقارنة.

#include <stdio.h>
#include <stdlib.h>

typedef struct { char name; int age; } Person;

int by_age(const void *a, const void *b) {
    int x = ((const Person*)a)->age;
    int y = ((const Person*)b)->age;
    return (x > y) - (x < y);
}

int main(void) {
    Person p[] = {{'C',30},{'A',20},{'B',25}};
    qsort(p, 3, sizeof(Person), by_age);
    for (int i = 0; i < 3; i++) printf("%c:%d ", p[i].name, p[i].age);
    printf("\n");
    return 0;
}

تستخدم bsearch الفكرة نفسها

تنفّذ bsearch بحثًا ثنائيًا في مصفوفة مرتبة، باستخدام دالة مقارنة لها العقد نفسه المستخدم في qsort.

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    return (*(const int*)a) - (*(const int*)b);
}

int main(void) {
    int a[] = {1, 3, 5, 7, 9};
    int key = 7;
    int *found = bsearch(&key, a, 5, sizeof(int), cmp);
    printf("found: %d\n", found ? *found : -1);
    return 0;
}

مفاتيح فرز متعددة

يمكن لدالة المقارنة مقارنة حقل أساسي، ثم حقل ثانوي عندما تتساوى قيم الحقل الأول.

#include <stdio.h>
#include <stdlib.h>

typedef struct { int grade; int id; } Rec;

int cmp(const void *a, const void *b) {
    const Rec *x = a, *y = b;
    if (x->grade != y->grade) return x->grade - y->grade;
    return x->id - y->id;
}

int main(void) {
    Rec r[] = {{90,2},{90,1},{80,3}};
    qsort(r, 3, sizeof(Rec), cmp);
    for (int i = 0; i < 3; i++) printf("%d/%d ", r[i].grade, r[i].id);
    printf("\n");
    return 0;
}

أهمية الفرز العام

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

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    char x = *(const char*)a, y = *(const char*)b;
    return (x > y) - (x < y);
}

int main(void) {
    char s[] = "dcba";
    qsort(s, 4, sizeof(char), cmp);
    printf("%s\n", s);
    return 0;
}

اختبار سريع

اختبر مدى فهمك لدوال المقارنة في qsort.

مراجعة

تعلّمتَ استخدام qsort مع دوال المقارنة:

  • تفرز qsort(base, count, size, compare) أي مصفوفة بطريقة عامة.
  • تستقبل دالة المقارنة مؤشرين من النوع const void *، وتُرجع قيمة سالبة أو صفرًا أو موجبة.
  • استخدم (x > y) - (x < y) لتجنّب الفيضان.
  • يُستخدم عقد المقارنة نفسه مع bsearch وفرز البنى والفرز باستخدام مفاتيح متعددة.

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

هل درس «qsort مع المقارِنات» مجاني؟

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

ماذا ستتعلم في «qsort مع المقارِنات»؟

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

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

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

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

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

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

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

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

  1. التصريح بمؤشرات الدوال
  2. تمرير الدوال
  3. qsort مع المقارِنات
  4. جداول مؤشرات الدوال
← العودة إلى C Academy