تمرين من المصدر الأصلي · تطبيق عملي

الجريان السطحي

استخدم الشرح العربي للفهم، واعتمد صفحة CS50 الأصلية مرجعًا نهائيًا للمواصفات والتسليم.

جلسة دراسة مقترحة: حتى 60 دقيقةالجهد الكلي التقريبي: 120 دقيقة · أكمل من حيث توقفت لاحقًا.Week 3
محاور هذه الخطوة
  • البحث
  • الترتيب
  • الاستدعاء الذاتي
  • Big O

ترجمة آلية تحت المراجعة

الجريان السطحي

المصدر الأصلي

قائمة تنفيذ التمرين

تُحفظ علامات هذه القائمة على هذا الجهاز والمتصفح فقط. أنشئ حسابًا مفعّلًا لحفظ إنجاز التمرين في مسارك.

الجريان السطحي

مشكلة بحاجة إلى حل

أنت تعرف بالفعل عن الانتخابات التعددية، التي تتبع خوارزمية بسيطة للغاية لتحديد الفائز في الانتخابات: يحصل كل ناخب على صوت واحد، ويفوز المرشح الذي حصل على أكبر عدد من الأصوات.

لكن التصويت الأغلبي له بعض العيوب. ماذا يحدث، على سبيل المثال، في انتخابات تضم ثلاثة مرشحين، ويتم الإدلاء بالأصوات أدناه؟

Five ballots, tie betweeen Alice and Bob

سيؤدي التصويت بالأغلبية هنا إلى إعلان التعادل بين أليس وبوب، حيث أن لكل منهما صوتين. لكن هل هذه هي النتيجة الصحيحة؟

هناك نوع آخر من أنظمة التصويت يُعرف بنظام التصويت على أساس الاختيار المُرتب. في نظام الاختيار المُرتب، يمكن للناخبين التصويت لأكثر من مرشح واحد. بدلاً من مجرد التصويت لاختيارهم الأفضل، يمكنهم ترتيب المرشحين حسب التفضيل. ولذلك قد تبدو بطاقات الاقتراع الناتجة كما يلي.

Five ballots, with ranked preferences

هنا، قام كل ناخب، بالإضافة إلى تحديد مرشحه الأول، بالإشارة أيضًا إلى اختياريه الثاني والثالث. والآن، ما كان في السابق انتخابات متعادلة يمكن أن يكون له الآن فائز. كان السباق في الأصل متعادلًا بين أليس وبوب، لذلك كان تشارلي خارج السباق. لكن الناخب الذي اختار تشارلي فضل أليس على بوب، لذلك يمكن إعلان أليس الفائزة هنا.

يمكن أن يؤدي التصويت بالاختيار المُصنف أيضًا إلى حل عيب محتمل آخر للتصويت التعددي. ألق نظرة على صناديق الاقتراع التالية.

Nine ballots, with ranked preferences

من يجب أن يفوز في هذه الانتخابات؟ في تصويت أكثري يختار فيه كل ناخب تفضيله الأول فقط، يفوز تشارلي في هذه الانتخابات بأربعة أصوات مقارنة بثلاثة فقط لبوب واثنتين لأليس. لكن أغلبية الناخبين (5 من أصل 9) سيكونون أكثر سعادة مع أليس أو بوب بدلاً من تشارلي. من خلال النظر في التفضيلات المرتبة، قد يتمكن نظام التصويت من اختيار فائز يعكس تفضيلات الناخبين بشكل أفضل.

أحد أنظمة التصويت على الاختيارات المرتبة هو نظام جولة الإعادة الفورية. في انتخابات الإعادة الفورية، يمكن للناخبين تصنيف أي عدد من المرشحين يرغبون فيه. إذا حصل أي مرشح على أغلبية (أكثر من 50%) من أصوات التفضيل الأول، فسيتم إعلان فوز هذا المرشح في الانتخابات.

إذا لم يحصل أي مرشح على أكثر من 50% من الأصوات، فستحدث "جولة إعادة فورية". يتم استبعاد المرشح الذي حصل على أقل عدد من الأصوات من الانتخابات، وأي شخص اختار هذا المرشح في الأصل كتفضيله الأول يتم الآن أخذ تفضيله الثاني في الاعتبار. لماذا تفعل ذلك بهذه الطريقة؟ وعلى نحو فعال، يحاكي هذا ما كان سيحدث لو لم يكن المرشح الأقل شعبية موجودًا في الانتخابات منذ البداية.

تتكرر العملية: إذا لم يحصل أي مرشح على أغلبية الأصوات، فسيتم استبعاد المرشح الذي حصل على المركز الأخير، وسيصوت أي شخص قام بالتصويت لصالحه بدلاً من ذلك لتفضيله التالي (الذي لم يتم استبعاده بالفعل). بمجرد حصول المرشح على الأغلبية، يتم إعلان فوز هذا المرشح.

يبدو الأمر أكثر تعقيدًا بعض الشيء من التصويت الأغلبي، أليس كذلك؟ ولكن يمكن القول إن له فائدة كونه نظامًا انتخابيًا يمثل فيه الفائز في الانتخابات تفضيلات الناخبين بشكل أكثر دقة. في ملف اسمه runoff.c في مجلد يسمى runoff، قم بإنشاء برنامج لمحاكاة انتخابات الإعادة.

تجريبي

رمز التوزيع

قم بتنزيل كود التوزيع

قم بتسجيل الدخول cs50.dev، انقر على نافذتك الطرفية، وقم بالتنفيذ cd بمفرده. يجب أن تجد أن مطالبة النافذة الطرفية الخاصة بك تشبه ما يلي:

$

التنفيذ التالي

wget https://cdn.cs50.net/2026/x/psets/3/runoff.zip

من أجل تنزيل ملف ZIP يسمى runoff.zip في مساحة الشيفرة الخاصة بك.

ثم نفذ

unzip runoff.zip

لإنشاء مجلد يسمى runoff. لم تعد بحاجة إلى ملف ZIP، حتى تتمكن من التنفيذ

rm runoff.zip

ثم قم بالرد بـ "y" متبوعًا بـ Enter عند المطالبة لإزالة ملف ZIP الذي قمت بتنزيله.

الآن اكتب

cd runoff

متبوعًا بـ Enter للانتقال إلى (i.e.، open) هذا الدليل. يجب أن تشبه مطالبتك الآن ما يلي.

runoff/ $

إذا كان كل شيء ناجحًا، فيجب عليك التنفيذ

ls

وشاهد الملف المسمى runoff.c. تنفيذ code runoff.c الملف الذي ستكتب فيه الشيفرة الخاص بك لمجموعة المشكلات هذه. إذا لم يكن الأمر كذلك، قم بإعادة تتبع خطواتك ومعرفة ما إذا كان بإمكانك تحديد الخطأ الذي ارتكبته!

فهم الشيفرة الموجود runoff.c

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

انظر إلى الجزء العلوي runoff.c أولاً. يتم تعريف ثوابتين: MAX_CANDIDATES للحد الأقصى لعدد المرشحين في الانتخابات، و MAX_VOTERS للحد الأقصى لعدد الناخبين في الانتخابات. يُستخدم

// Max voters and candidates
#define MAX_VOTERS 100
#define MAX_CANDIDATES 9

لاحظ ذلك تم الآن إنشاء MAX_CANDIDATES لتحديد حجم المصفوفة، candidates.

// Array of candidates
candidate candidates[MAX_CANDIDATES];

candidates عبارة عن مصفوفة من candidateق. في runoff.c a candidate هو أ struct. كل candidate لديه string الحقل الخاص بهم name، أ int يمثل عدد votes لديهم حاليا، و تم استدعاء قيمة bool eliminated الذي يشير إلى ما إذا كان المرشح قد تم استبعاده من الانتخابات. المصفوفة candidates سوف يتتبع جميع المرشحين في الانتخابات.

// Candidates have name, vote count, eliminated status
typedef struct
{
    string name;
    int votes;
    bool eliminated;
}
candidate;

الآن يمكنك أن تفهم بشكل أفضل preferences، المصفوفة ثنائية الأبعاد. المصفوفة سيمثل preferences[i] كافة التفضيلات الخاصة برقم الناخب i. العدد الصحيح، preferences[i][j]، سيقوم بتخزين فهرس المرشح من candidates مجموعة، من هو jالتفضيل الرابع للناخب i.

// preferences[i][j] is jth preference for voter i
int preferences[MAX_VOTERS][MAX_CANDIDATES];

يحتوي البرنامج أيضًا على متغيرين عالميين: voter_count و candidate_count.

// Numbers of voters and candidates
int voter_count;
int candidate_count;

الآن main. لاحظ أنه بعد تحديد عدد المرشحين وعدد الناخبين، تبدأ حلقة التصويت الرئيسية، مما يمنح كل ناخب فرصة التصويت. عندما يقوم الناخب بإدخال تفضيلاته، فإن يتم استدعاء الدالة vote لتتبع كافة التفضيلات. إذا تم اعتبار الاقتراع غير صالح في أي وقت، فسيتم إنهاء البرنامج.

بمجرد دخول جميع الأصوات، تبدأ حلقة أخرى: ستستمر هذه الحلقة في التكرار خلال عملية جولة الإعادة للتحقق من الفائز وإلغاء مرشح المركز الأخير حتى يكون هناك فائز.

الاستدعاء الأول هنا هو لوظيفة تسمى tabulate، والذي يجب أن ينظر إلى جميع تفضيلات الناخبين ويحسب إجمالي الأصوات الحالية، من خلال النظر إلى المرشح الأفضل لكل ناخب والذي لم يتم استبعاده بعد. التالي، يجب أن تقوم وظيفة print_winner بطباعة الفائز إذا كان هناك واحد؛ إذا كان هناك، فإن البرنامج قد انتهى. ولكن بخلاف ذلك، يحتاج البرنامج إلى تحديد أقل عدد من الأصوات التي حصل عليها أي شخص لا يزال في الانتخابات (من خلال مكالمة إلى find_min). إذا تبين أن جميع المشاركين في الانتخابات متعادلون بنفس عدد الأصوات (على النحو الذي يحدده قانون الانتخابات). is_tie )، تم إعلان التعادل في الانتخابات؛ وبخلاف ذلك، يتم استبعاد المرشح (أو المرشحين) صاحب المركز الأخير من الانتخابات عن طريق الاتصال بـ eliminate .

إذا نظرت إلى الأسفل قليلاً في الملف، فسترى أن بقية الوظائف—vote, tabulate, print_winner, find_min, is_tieو eliminate— كل شيء متروك لك لإكماله! يجب عليك فقط تعديل هذه الوظائف في runoff.c، على الرغم من أنه يجوز لك ذلك #include ملفات رأس إضافية أعلى runoff.c إذا كنت ترغب في ذلك.

تلميحات

انقر على أزرار التبديل أدناه لقراءة بعض النصائح!

أكمل وظيفة vote

أكمل وظيفة vote .

  • تأخذ الدالة ثلاث وسائط: voter, rankو name.
  • إذا name مطابق لاسم مرشح صالح، فيجب عليك تحديث مصفوفة التفضيلات العامة للإشارة إلى أن الناخب voter لديه هذا المرشح باعتباره rank التفضيل. ضع في اعتبارك 0 هو التفضيل الأول، 1 هو التفضيل الثاني، وما إلى ذلك. قد تفترض أنه لن يكون هناك مرشحان يحملان نفس الاسم.
  • إذا تم تسجيل التفضيل بنجاح، فيجب أن تعود الوظيفة true. يجب أن تعود الوظيفة false خلاف ذلك. فكر، على سبيل المثال، متى name ليس اسم أحد المرشحين.

أثناء كتابة الشيفرة الخاصة بك، ضع في اعتبارك هذه التلميحات:

  • تذكر ذلك يمكن candidate_count يخزن عدد المرشحين في الانتخابات.
  • أذكر أنه يمكنك استخدامه strcmp لمقارنة سلسلتين.
  • تذكر ذلك يمكن preferences[i][j] يخزن فهرس المرشح jالترتيب المفضل لـ iالناخب الرابع.
أكمل وظيفة tabulate

أكمل وظيفة tabulate .

  • يجب أن تقوم الوظيفة بتحديث رقم votes لكل مرشح في هذه المرحلة من جولة الإعادة.
  • تذكر أنه في كل مرحلة من جولة الإعادة، يقوم كل ناخب بالتصويت فعليًا لمرشحه المفضل الذي لم يتم استبعاده بالفعل.

أثناء كتابة الشيفرة الخاصة بك، ضع في اعتبارك هذه التلميحات: يقوم

  • تذكر ذلك يمكن voter_count بتخزين عدد الناخبين في الانتخابات، ونريد أن نحسب بطاقة اقتراع واحدة لكل ناخب في انتخاباتنا.
  • تذكر ذلك للناخب i، يتم تمثيل مرشحهم المفضل بواسطة preferences[i][0]، مرشحهم الثاني بواسطة preferences[i][1]، إلخ.
  • أذكر أن candidate struct لديه حقل يسمى eliminatedوالذي سيكون true إذا تم استبعاد المرشح من الانتخابات.
  • أذكر أن candidate struct لديه حقل يسمى votes، والتي من المحتمل أن ترغب في تحديثها للمرشح المفضل لكل ناخب.
  • تذكر أنه بمجرد الإدلاء بصوتك لأول مرشح لم يتم استبعاده من الناخب، ستحتاج إلى التوقف عند هذا الحد، وليس الاستمرار في التصويت. يمكنك الخروج من الحلقة مبكرًا باستخدام break داخل الشرط.
أكمل وظيفة print_winner

أكمل وظيفة print_winner .

  • إذا حصل أي مرشح على أكثر من نصف الأصوات، فيجب طباعة اسمه وإعادة الوظيفة true.
  • إذا لم يفز أحد بالانتخابات بعد، فيجب أن تعود الوظيفة false.

أثناء كتابة الشيفرة الخاصة بك، ضع في اعتبارك هذا التلميح:

  • تذكر ذلك يمكن voter_count يخزن عدد الناخبين في الانتخابات. بالنظر إلى ذلك، كيف يمكنك التعبير عن عدد الأصوات اللازمة للفوز في الانتخابات؟
أكمل وظيفة find_min

أكمل وظيفة find_min .

  • يجب أن تعرض الدالة الحد الأدنى من إجمالي الأصوات لأي مرشح لا يزال في الانتخابات.

أثناء كتابة الشيفرة الخاصة بك، ضع في اعتبارك هذا التلميح:

  • من المرجح أنك ستحتاج إلى التنقل بين المرشحين للعثور على الشخص الذي لا يزال في الانتخابات والذي حصل على أقل عدد من الأصوات. ما هي المعلومات التي يجب عليك تتبعها أثناء التنقل بين المرشحين؟
أكمل وظيفة is_tie

أكمل وظيفة is_tie .

  • تأخذ الدالة وسيطة min، والذي سيكون الحد الأدنى لعدد الأصوات التي حصل عليها أي شخص في الانتخابات حاليًا.
  • يجب أن تعود الدالة true إذا كان كل مرشح متبقي في الانتخابات لديه نفس عدد الأصوات، ويجب عليه العودة false خلاف ذلك.

أثناء كتابة الشيفرة الخاصة بك، ضع في اعتبارك هذا التلميح:

  • تذكر أن التعادل يحدث إذا حصل كل مرشح لا يزال في الانتخابات على نفس عدد الأصوات. لاحظ أيضًا أن تأخذ الدالة is_tie وسيطة min، وهو أقل عدد من الأصوات يحصل عليه أي مرشح حاليًا. كيف يمكن أن تستخدم min لتحديد ما إذا كانت الانتخابات متعادلة (أو، على العكس، ليست متعادلة)؟
أكمل وظيفة eliminate

أكمل وظيفة eliminate .

  • تأخذ الدالة وسيطة min، والذي سيكون الحد الأدنى لعدد الأصوات التي حصل عليها أي شخص في الانتخابات حاليًا.
  • يجب أن تقضي الوظيفة على المرشح (أو المرشحين) الذين لديهم min عدد الأصوات.

الإرشادات التفصيلية

محتوى خارجي من YouTube

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

فتح المصدر

كيفية الاختبار

تأكد من اختبار الشيفرة الخاص بك للتأكد من أنه يتعامل مع...

  • انتخابات بأي عدد من المرشحين (حتى MAX من 9)
  • التصويت للمرشح بالاسم
  • أصوات غير صالحة للمرشحين غير الموجودين في بطاقة الاقتراع
  • طباعة الفائز في الانتخابات إذا كان هناك واحد فقط
  • عدم إقصاء أحد في حالة التعادل بين جميع المرشحين المتبقين

صحة

check50 cs50/problems/2026/x/runoff

النمط

style50 runoff.c

كيفية الإرسال

في جهازك الطرفي، قم بتنفيذ ما يلي لإرسال عملك، والإجابة على المطالبات التي تظهر أيضًا.

submit50 cs50/problems/2026/x/runoff

أنهيت التطبيق؟

راجع عناصر التنفيذ أعلاه، ثم احفظ إنجازك وانتقل إلى التمرين التالي.

حفظ إنجاز التمرين

يمكنك قراءة الدورة كاملة دون حساب. يصبح حفظ التقدم متاحًا بعد تفعيل الحساب، ويبقى محفوظًا بعد انتهاء العضوية.

العودة إلى جميع التمارين