المحاضرة 4: شرائح التكرار على السلاسل والتخمين والبحث وشروح الثنائية كاملة
المحاضرة 4: التكرار على السلاسل النصية والتخمين والاختبار والبحث الثنائي (Loops Over Strings, Guess-and-Check, Binary)
المصادر والنسبة والترخيص
المادة الأصلية: آنا بيل (Ana Bell)، MIT OpenCourseWare (MIT OCW)، معهد ماساتشوستس للتكنولوجيا، مقرر 6.100L: مقدمة في علوم الحاسوب والبرمجة باستخدام Python، خريف 2022 (Fall 2022).
هذه ترجمة وتكييف عربي غير رسمي وفق رخصة CC BY-NC-SA 4.0: النسبة–غير التجاري–المشاركة بالمثل، ولا تعني اعتمادًا أو تأييدًا من MIT أو MIT OCW. شروط الاستخدام والاستشهاد.
منهج الترجمة: لكل صفحة في ملف الشرائح عنوان مستقل ورقم مطابق. نُقلت الأشكال المتكرّرة إلى جداول تحافظ على تسلسلها. الشيفرة محفوظة بالإنجليزية. لم تُضمَّن صور أو صفحات PDF. الصورة في الشريحة 8 مستثناة صراحةً من رخصة المصدر (مصدرها غير معروف) فحُذفت مع الإشارة إلى موضعها.
الشريحة 1: التكرار على السلاسل النصية، والتخمين والاختبار، والثنائية
(LOOPS OVER STRINGS, GUESS-and-CHECK, BINARY)
(نزّل الشرائح وملفات .py لمتابعة الشرح).
6.100L، المحاضرة 4 — آنا بيل (Ana Bell).
الشريحة 2: في المرة الماضية
- آليات التكرار (Looping Mechanisms):
- حلقات
whileوحلقاتfor.
- حلقات
- حلقات
while:- تكرّر ما دام الشرط صحيحًا.
- يجب التأكد من عدم الدخول في حلقة لانهائية (Infinite Loop).
- حلقات
for:- يأخذ متغيّر الحلقة (Loop Variable) القيم في تسلسل واحدًا تلو الآخر.
- يمكنها المرور على نطاقات من الأعداد (Ranges of Numbers).
- ولسوف نرى قريبًا أشياء أخرى كثيرة يسهل المرور عليها بالتكرار.
الشريحة 3: الأمر break
- يخرج فورًا من أي حلقة هو فيها.
- يتخطّى بقية التعابير في كتلة الشيفرة.
- يخرج من الحلقة الداخلية فقط (Innermost Loop)!
while <condition_1>:
while <condition_2>:
<expression_a>
break
<expression_b>
<expression_c>
الشريحة 4: الأمر break
mysum = 0
for i in range(5, 11, 2):
mysum += i
if mysum == 5:
break
mysum += 1
print(mysum)
- ماذا يحدث في هذا البرنامج؟
- رابط Python Tutor.
الشريحة 5: جرّب بنفسك!
- اكتب شيفرة تمرّر حلقة
forعلى نطاق ما وتطبع كم عددًا زوجيًّا يوجد في ذلك النطاق. جرّب مع:range(5)range(10)range(2,9,3)range(-4,6,2)range(5,6)
الشريحة 6: السلاسل النصية والتكرار
- شيفرة للتحقق من وجود الحرف
iأوuفي سلسلة نصية. - الطرق الثلاث تفعل الشيء نفسه:
s = "demo loops - fruit loops"
for index in range(len(s)):
if s[index] == 'i' or s[index] == 'u':
print("There is an i or u")
for char in s:
if char == 'i' or char == 'u':
print("There is an i or u")
for char in s:
if char in 'iu':
print("There is an i or u")
الشريحة 7: الفكرة الكبرى
تسلسل القيم في حلقة for ليس محدودًا بالأعداد.
الشريحة 8: cheerleaders الروبوتات
(ROBOT CHEERLEADERS)
ملاحظة المترجم: محتوى هذه الشريحة صورة مصدرها غير معروف وجميع الحقوق محفوظة، وهي مستثناة من رخصة CC الخاصة بالمصدر؛ لذلك حُذفت الصورة ولم تُستعَض عنها.
الشريحة 9: جرّب بنفسك!
- افترض أنك أُعطيت سلسلة نصية من حروف صغيرة في المتغيّر
s. عدّ كم حرفًا فريدًا (Unique) يوجد في السلسلة. مثال: إذا كانتs = "abca"فتطبع شيفرتك 3. - تلميح:
- مرّ على كل محرف في
s. - تتبَّع المحارف التي رأيتها في متغيّر سلسلة نصية.
- أضف محارف من
sإلى متغيّرseenإذا لم تكن موجودة بالفعل في ذلك المتغيّر.
- مرّ على كل محرف في
الشريحة 10: ملخص ما مرّ حتى الآن
- الكائنات لها أنواع.
- التعابير تُقيَّم إلى قيمة واحدة، وتُربط باسم متغيّر.
- التفريع (Branching):
ifوelseوelif.- ينفّذ البرنامج مجموعة شيفرة أو مجموعة أخرى.
- آليات التكرار (Looping Mechanisms): حلقات
whileوحلقاتfor.- تُنفَّذ الشيفرة تكرارًا ما دام شرط ما صحيحًا.
- تُنفَّذ الشيفرة تكرارًا لكل القيم في تسلسل.
الشريحة 11: هذا كل ما تحتاجه لتنفيذ الخوارزميات
(THAT IS ALL YOU NEED TO IMPLEMENT ALGORITHMS)
الشريحة 12: التخمين والاختبار (GUESS-and-CHECK)
(GUESS-and-CHECK)
الشريحة 13: التخمين والاختبار
- تُسمَّى العملية بالتعداد الشامل (Exhaustive Enumeration).
- ينطبق على مسألة يكون فيها:
- بإمكانك تخمين قيمة للحل.
- بإمكانك التحقق مما إذا كان الحل صحيحًا.
- ويمكنك المواصلة في التخمين حتى:
- تجد الحل، أو
- تكون قد جرّبت كل القيم.
مخطّط الانسياب (Flowchart):
Initial guess
↓
Is your guess correct?
yes → done
no ↓
Choose the next guess (Be systematic)
↓
(back to guess)
الشريحة 14: التخمين والاختبار — الجذر التربيعي (Square Root)
- الفكرة الأساسية:
- معطى عدد صحيح، لنسمّه ، نريد أن نعرف إن كان هناك عدد صحيح آخر هو جذره التربيعي.
- ابدأ بتخمين وتحقق إن كان الجواب الصحيح.
- القيم المفحوصة في المخطط: 0، 1، 2، 3، 4، 5، 6، 7، 8، 9، 10.
الشريحة 15: التخمين والاختبار — الجذر التربيعي
- الفكرة الأساسية نفسها:
- ابدأ بتخمين وتحقق إن كان الجواب الصحيح.
- لكي تكون منهجيًّا (Be systematic)، ابدأ بـ
guess = 0، ثم 1، ثم 2، وهكذا.
الشريحة 16: التخمين والاختبار — الجذر التربيعي
-
الفكرة الأساسية نفسها.
-
إذا كان مربعًا كاملًا (Perfect Square)، فسنجد جذره في النهاية ويمكننا التوقف (انظر مربع التخمين).
-
مثال في المخطط: ، والتخمينات من 0 إلى 10.
الشريحة 17: التخمين والاختبار — الجذر التربيعي
-
الفكرة الأساسية نفسها.
-
ولكن ماذا لو لم يكن مربعًا كاملًا؟
- نحتاج إلى معرفة متى نتوقف.
- استخدم الجبر (Algebra): إذا كان مربع التخمين أكبر من ، فيمكننا التوقف.
-
مثال في المخطط: ، والتخمينات من 0 إلى 10.
الشريحة 18: التخمين والاختبار — الجذر التربيعي بحلقة while
guess = 0
x = int(input("Enter an integer: "))
while guess**2 < x:
guess = guess + 1
if guess**2 == x:
print("Square root of", x, "is", guess)
else:
print(x, "is not a perfect square")
الشريحة 19: التخمين والاختبار — الجذر التربيعي
-
هل يعمل هذا مع أي قيمة عددية صحيحة لـ ؟
-
ماذا لو كان سالبًا؟
- تنتهي حلقة
whileفورًا. - يمكن التحقق من وجود مدخل سالب ومعالجته بطريقة مختلفة.
- تنتهي حلقة
-
مثال في المخطط: ، والتخمينات من -1 إلى 8.
الشريحة 20: التخمين والاختبار — الجذر التربيعي بحلقة while
guess = 0
neg_flag = False
x = int(input("Enter a positive integer: "))
if x < 0:
neg_flag = True
while guess**2 < x:
guess = guess + 1
if guess**2 == x:
print("Square root of", x, "is", guess)
else:
print(x, "is not a perfect square")
if neg_flag:
print("Just checking... did you mean", -x, "?")
الشريحة 21: الفكرة الكبرى
التخمين والاختبار لا يستطيع اختبار عدد لا نهائي من القيم. عليك التوقف عند نقطة ما!
الشريحة 22: مقارنة التخمين والاختبار
| الخطوة | while loop |
for loop |
|---|---|---|
| التخمين الأوّلي | Initial guess | — لا شيء هنا |
| هل تخمينك صحيح؟ | Is your guess correct? | Check if the guess is correct |
| اختر التخمين التالي (كن منهجيًّا) | Choose next guess (Be systematic) | Sequentially go through all possible guesses |
| — | لا | نعم |
| — | كسر الحلقة، انتهيت (Break the loop, you’re done) | مررت على كل القيم في التسلسل (Went through all vals in sequence) |
| — | — | لا يوجد حل (Did not find a solution) |
| — | — | ما زالت هناك قيم (Still more vals in sequence) |
الشريحة 23: جرّب بنفسك!
- ضع عددًا كعدد سريّ (Secret Number).
- اكتب برنامجًا يمرّ على كل الأعداد من 1 إلى 10 ويطبع القيمة السريّة إذا كانت في هذا النطاق. إن لم يُعثر عليها فلا يطبع شيئًا.
- كيف يبدو البرنامج إن غيّرت الشرط إلى: إن لم يُعثر عليها، اطبع أنه لم يعثر عليها.
الشريحة 24: جرّب بنفسك!
- قارن بين الشيفرتين اللتين:
- تضعان عددًا كعدد سريّ.
- تمرّان على كل الأعداد من 1 إلى 10 وتطبعان القيمة السريّة إذا كانت في هذا النطاق.
- الأولى: إن لم يُعثر عليها لا يطبع شيئًا.
- الثانية: إن لم يُعثر عليها، يطبع أنه لم يعثر عليها.
- الجواب:
secret = 7
found = False
for i in range(1,11):
if i == secret:
print("yes, it's", i)
found = True
if not found:
print("not found")
secret = 7
for i in range(1,11):
if i == secret:
print("yes, it's", i)
الشريحة 25: الفكرة الكبرى
يمكن استخدام القيم البوليانية كإشارات (Signals) إلى أن شيئًا قد حدث. ونسمّيها أعلامًا بوليانية (Boolean Flags).
الشريحة 26: while loop أم for loop؟
- رأينا أن الشيفرة تبدو أنظف عند المرور على تسلسلات من القيم (أي باستخدام حلقة
for).- لا تضبط العنصر المُكرَّر (Iterant) بنفسك كما في حلقة
while. - احتمال إدخال أخطاء أقل.
- لا تضبط العنصر المُكرَّر (Iterant) بنفسك كما في حلقة
- خذ مثالًا يستخدم حلقة
forمع نطاق صريح من القيم.
الشريحة 27: التخمين والاختبار — الجذر التكعيبي: مكعّبات موجبة
cube = int(input("Enter an integer: "))
for guess in range(cube+1):
if guess**3 == cube:
print("Cube root of", cube, "is", guess)
الشريحة 28: التخمين والاختبار — الجذر التكعيبي: مكعّبات موجبة وسالبة
cube = int(input("Enter an integer: "))
for guess in range(abs(cube)+1):
if guess**3 == abs(cube):
if cube < 0:
guess = -guess
print("Cube root of "+str(cube)+" is "+str(guess))
الشريحة 29: التخمين والاختبار — الجذر التكعيبي: أسرع قليلًا
cube = int(input("Enter an integer: "))
for guess in range(abs(cube)+1):
if guess**3 >= abs(cube):
break
if guess**3 != abs(cube):
print(cube, "is not a perfect cube")
else:
if cube < 0:
guess = -guess
print("Cube root of "+str(cube)+" is "+str(guess))
الشريحة 30: مثال آخر
- تذكّر مسائل الكلمات (Word Problems) من طفولتك؟
- مثال:
- أليزا وبن وسيندي يبيعون تذاكر لجمع تبرّعات.
- بن يبيع عددًا أقل بـ 2 من أليزا.
- سيندي تبيع ضعف ما تبيعه أليزا.
- بيع الثلاثة 10 تذاكر في المجموع.
- كم باعت أليزا؟
- يمكن حلّها جبريًّا، لكن يمكننا أيضًا استخدام التخمين والاختبار.
الشريحة 31: التخمين والاختبار مع مسائل الكلمات
for alyssa in range(11):
for ben in range(11):
for cindy in range(11):
total = (alyssa + ben + cindy == 10)
two_less = (ben == alyssa-2)
twice = (cindy == 2*alyssa)
if total and two_less and twice:
print(f"Alyssa sold {alyssa} tickets")
print(f"Ben sold {ben} tickets")
print(f"Cindy sold {cindy} tickets")
الشريحة 32: مثال بأعداد أكبر
- مع أعداد أكبر، يصبح تداخل الحلقات بطيئًا!
- مثال:
- أليزا وبن وسيندي يبيعون تذاكر لجمع تبرّعات.
- بن يبيع عددًا أقل بـ 20 من أليزا.
- سيندي تبيع ضعف ما تبيعه أليزا.
- بيع الثلاثة 1000 تذكرة في المجموع.
- كم باعت أليزا؟
- الشيفرة السابقة لن تنتهي في وقت معقول.
- بدلًا من ذلك، مرّ على متغيّر واحد وكتّب المعادلات مباشرة.
الشريحة 33: حل أكثر كفاءة
for alyssa in range(1001):
ben = max(alyssa - 20, 0)
cindy = alyssa * 2
if ben + cindy + alyssa == 1000:
print("Alyssa sold " + str(alyssa) + " tickets")
print("Ben sold " + str(ben) + " tickets")
print("Cindy sold " + str(cindy) + " tickets")
الشريحة 34: الفكرة الكبرى
يمكنك تطبيق الحوسبة (Computation) على مسائل كثيرة!
الشريحة 35: الأعداد الثنائية (Binary Numbers)
(BINARY NUMBERS)
الشريحة 36: الأعداد في بايثون
int: أعداد صحيحة، مثل التي تعلّمتها في المدرسة الابتدائية.float: أعداد حقيقية، مثل التي تعلّمتها في المرحلة الإعدادية.
الشريحة 37: دافعنا — احتفظ بهذا في ذهنك للشرائح القليلة التالية
x = 0
for i in range(10):
x += 0.1
print(x == 1)
print(x, '==', 10*0.1)
الشريحة 38: الفكرة الكبرى
العمليات على بعض الأعداد العشرية (floats) تُدخل خطأً صغيرًا جدًّا. والخطأ الصغير قد يكون له أثر كبير إذا أُجريت العمليات مرات عديدة!
الشريحة 39: نظرة أقرب على الأعداد العشرية
- بايثون (وكل لغة برمجة أخرى) تستخدم «الفاصلة العائمة» (Floating Point) لتقريب الأعداد الحقيقية.
- مصطلح «الفاصلة العائمة» يشير إلى الطريقة التي تُخزَّن بها هذه الأعداد في الحاسوب.
- التقريب (Approximation) لا يهم عادةً…
- لكنه يهمّنا نحن!
- لنرَ لماذا…
الشريحة 40: تمثيل الفاصلة العائمة
- يعتمد على عتاد الحاسوب، لا على تنفيذ لغة البرمجة.
- أشياء أساسية يجب فهمها:
- الأعداد (وكل شيء آخر) تُمثَّل كتسلسل من البتات (Bits) — أي 0 أو 1.
- حين نكتب الأعداد، تستخدم الرموز أساس 10.
- و
0.1يمثّل العدد الكسري .
- هذا يسبّب تنافرًا معرفيًّا (Cognitive Dissonance) — وسيؤثّر في كيفية كتابة شيفرتنا.
الشريحة 41: لماذا الثنائية؟ — التنفيذ العتادي
- سهلة التنفيذ في العتاد: ابنِ مكوّنات يمكن أن تكون في حالة واحدة من حالتين.
- عتاد الحاسوب مبنيّ حول طرق تستطيع تخزين المعلومات بكفاءة كـ 0 أو 1 وإجراء عمليات حسابية بهذا التمثيل.
- الجهد (Voltage) «عالٍ» أو «منخفض».
- الدوران المغناطيسي (Magnetic Spin) «لأعلى» أو «لأسفل».
- مناسبة للعمليات الحسابية على الأعداد الصحيحة، لكن ماذا عن الأعداد ذات الأجزاء الكسرية (floats)؟
الشريحة 42: الأعداد الثنائية
- التمثيل في الأساس 10 لعدد صحيح:
- مجموع لقوى 10، مضروبة في أعداد صحيحة من 0 إلى 9.
- التمثيل الثنائي هو الفكرة نفسها في الأساس 2:
- مجموع لقوى 2، مضروبة في أعداد صحيحة من 0 إلى 1.
الشريحة 43: تحويل عدد صحيح عشري إلى ثنائي
- ندخل الأعداد بالنظام العشري، والحاسوب يحتاج إلى تحويلها إلى النظام الثنائي.
- خذ مثال .
- إذا أخذنا باقي قسمة على 2، أي
x%2، حصلت على آخر بت ثنائي. - وإذا قسمنا قسمة صحيحة على 2، أي
x//2، تحوّلت كل البتات إلى اليمين (Shifted Right) واحدًا.x//2 = 1001_2.
- واصل القسومات المتتالية؛ الآن يعطي الباقي البت التالي، وهكذا.
- لنحوّل إلى الصورة الثنائية.
الشريحة 44: تنفيذ ذلك في بايثون للأعداد الموجبة
result = ''
if num == 0:
result = '0'
while num > 0:
result = str(num%2) + result
num = num//2
- رابط Python Tutor.
الشريحة 45: تنفيذ ذلك في بايثون مع معالجة الأعداد السالبة
if num < 0:
is_neg = True
num = abs(num)
else:
is_neg = False
result = ''
if num == 0:
result = '0'
while num > 0:
result = str(num%2) + result
num = num//2
if is_neg:
result = '-' + result
الشريحة 46: ملخص
- الحلقات يمكنها المرور على أي تسلسل من القيم:
rangeللأعداد.- سلسلة نصية (String).
- التخمين والاختبار يوفّر خوارزمية بسيطة لحل المسائل:
- عندما تكون مجموعة الحلول المحتملة قابلة للتعداد، فإن التعداد الشامل مضمون أن ينجح (في النهاية).
- الأعداد الثنائية تساعدنا على فهم كيف تعمل الآلة:
- التحويل إلى الثنائي سيساعدنا على فهم كيف تُخزَّن الأعداد العشرية.
- وهذا مهم للخوارزمية التالية التي سنراها.
الشريحة 47: بيانات MIT OpenCourseWare
MIT OpenCourseWare — https://ocw.mit.edu
6.100L: مقدمة في علوم الحاسوب والبرمجة باستخدام Python.
خريف 2022.
للحصول على معلومات عن الاستشهاد بهذه المواد أو شروط استخدامها، تفضّل بزيارة https://ocw.mit.edu/terms.