Задачи по Python: рекурсия, структуры данных, SDLC
المهمة الثالثة
السؤال: اذكر وظائف ثلاث وحدات برمجية بايثون لعمل محاكاة لإدارة سجل التصفح (Browser History) بحيث:
1. تعمل الوحدة المستدعية على:
أ. تعريف السجل من خلال قائمة فارغة.
ب. استدعاء وحدات الإضافة والحذف ومعرفة الصفحة الحالية والحجم والتحقق فيما إذا كان السجل فارغاً أم لا.
- إنشاء:
أ. وحدة باسمpushتستخدم عند زيارة صفحة جديدة.
ب. وحدة تسمىpopلعرض الصفحة السابقة.
ج. وحدة تسمىpeekلعرض الصفحة الحالية.
د. معرفة عدد الصفحات من وحدة تسمىsize.
هـ. التحقق هل السجل فارغ أم لا باستخدام وحدة تسمىis_empty.
الحل:
هذه المهمة تتطلب وصف وظائف وحدات برمجية في بايثون لمحاكاة سجل المتصفح. سنقوم بتعريف الوحدات المطلوبة وشرح وظيفة كل منها.
1. تعريف الوحدات ووظائفها:
-
الوحدة المستدعية (Main Module/Class):
__init__(self): تقوم بتهيئة السجل كقائمة فارغة عند إنشاء كائن من هذه الوحدة.
python self.history = []add_page(self, page): تضيف صفحة جديدة إلى نهاية السجل (تعمل كـpush).remove_page(self): تزيل الصفحة الأخيرة من السجل وتعيدها (تعمل كـpop).get_current_page(self): تعرض الصفحة الحالية (الأخيرة في السجل) دون إزالتها (تعمل كـpeek).get_size(self): تعيد عدد الصفحات الموجودة في السجل.is_empty(self): تتحقق مما إذا كان السجل فارغاً وتعيدTrueأوFalse.
-
الوحدة
push:- الوظيفة: تستخدم لإضافة صفحة جديدة إلى سجل التصفح. عند زيارة صفحة جديدة، يتم استدعاء هذه الوحدة لإضافتها إلى نهاية قائمة السجل.
-
الوحدة
pop:- الوظيفة: تستخدم للانتقال إلى الصفحة السابقة. عند استدعائها، تزيل الصفحة الحالية من السجل وتعيدها، مما يجعل الصفحة التي قبلها هي الصفحة الحالية.
-
الوحدة
peek:- الوظيفة: تستخدم لعرض الصفحة الحالية دون تغيير السجل. عند استدعائها، تعرض الصفحة الأخيرة في قائمة السجل.
-
الوحدة
size:- الوظيفة: تستخدم لمعرفة عدد الصفحات الموجودة حالياً في سجل التصفح. تعيد طول القائمة التي تمثل السجل.
-
الوحدة
is_empty:- الوظيفة: تستخدم للتحقق مما إذا كان سجل التصفح فارغاً. تعيد
Trueإذا كانت القائمة فارغة، وFalseإذا كانت تحتوي على صفحات.
- الوظيفة: تستخدم للتحقق مما إذا كان سجل التصفح فارغاً. تعيد
مثال توضيحي لكيفية عمل الوحدات (باستخدام كلاس بسيط):
class BrowserHistory:
def __init__(self):
self.history = []
# تعمل كـ push
def push(self, page):
self.history.append(page)
print(f"Added: {page}")
# تعمل كـ pop
def pop(self):
if not self.is_empty():
return self.history.pop()
return None
# تعمل كـ peek
def peek(self):
if not self.is_empty():
return self.history[-1]
return None
# تعمل كـ size
def size(self):
return len(self.history)
# تعمل كـ is_empty
def is_empty(self):
return len(self.history) == 0
# --- الاستخدام ---
history_manager = BrowserHistory()
print(f"Is empty? {history_manager.is_empty()}") # True
history_manager.push("google.com")
history_manager.push("facebook.com")
print(f"Current page: {history_manager.peek()}") # facebook.com
print(f"History size: {history_manager.size()}") # 2
previous_page = history_manager.pop()
print(f"Went back to: {previous_page}") # facebook.com
print(f"Current page: {history_manager.peek()}") # google.com
print(f"History size: {history_manager.size()}") # 1
print(f"Is empty? {history_manager.is_empty()}") # False
المهمة الرابعة
السؤال: في إطار دورة حياة تطوير البرمجيات (SDLC)، ما هو النموذج المناسب، وما هو أثر ذلك على تحقيق الشركة لتنفيذها؟
الحل:
السؤال يتحدث عن اختيار نموذج مناسب لدورة حياة تطوير البرمجيات (SDLC) وتأثير هذا الاختيار على تحقيق أهداف الشركة.
النموذج المناسب:
يعتمد اختيار النموذج المناسب لدورة حياة تطوير البرمجيات (SDLC) على عدة عوامل، منها:
- طبيعة المشروع: هل هو مشروع كبير أم صغير؟ هل المتطلبات واضحة وثابتة أم متغيرة؟
- حجم الفريق: هل الفريق كبير أم صغير؟
- الجدول الزمني والميزانية: ما هي القيود المفروضة على الوقت والتكلفة؟
- مستوى المخاطرة: ما هي درجة المخاطرة المتوقعة في المشروع؟
بشكل عام، هناك نماذج متعددة مثل:
- النموذج الشلالي (Waterfall Model): مناسب للمشاريع ذات المتطلبات الواضحة والثابتة، حيث يتم الانتقال من مرحلة إلى أخرى بشكل تسلسلي.
- النماذج التكرارية والمتزايدة (Iterative and Incremental Models): مثل نموذج "التطوير السريع للتطبيقات" (RAD) أو "التطوير الرشيق" (Agile). هذه النماذج مناسبة للمشاريع التي تتغير فيها المتطلبات أو عندما يكون من المهم تقديم منتج قابل للاستخدام بسرعة.
- النموذج الحلزوني (Spiral Model): يجمع بين عناصر النماذج التكرارية والتحكم في المخاطر، وهو مناسب للمشاريع الكبيرة والمعقدة وعالية المخاطر.
أثر اختيار النموذج على تحقيق الشركة لتنفيذها:
اختيار النموذج المناسب له تأثير كبير على نجاح الشركة في تنفيذ مشاريعها:
- زيادة الكفاءة: النموذج المناسب يساعد على تنظيم العمل وتحديد المهام بوضوح، مما يزيد من كفاءة الفريق ويقلل من إهدار الوقت والموارد.
- تحسين الجودة: بعض النماذج (مثل Agile) تشجع على الاختبار المستمر والتغذية الراجعة، مما يؤدي إلى منتج نهائي عالي الجودة يلبي احتياجات العملاء.
- تقليل المخاطر: النماذج التي تركز على إدارة المخاطر (مثل الحلزوني) تساعد الشركة على تحديد ومعالجة المشاكل المحتملة مبكراً، مما يقلل من احتمالية فشل المشروع.
- المرونة والاستجابة للتغيير: النماذج الرشيقة تتيح للشركة الاستجابة بسرعة للتغيرات في متطلبات السوق أو العملاء، مما يضمن بقاء منتجاتها تنافسية.
- رضا العملاء: عندما يتم اختيار النموذج الذي يتناسب مع طبيعة المشروع ويسمح بإشراك العميل بشكل فعال، فإن ذلك يؤدي إلى منتج يلبي توقعاته ويزيد من رضاه.
الخلاصة:
لا يوجد نموذج واحد يناسب جميع الشركات والمشاريع. يجب على الشركة تحليل احتياجاتها وقدراتها واختيار النموذج الذي يوفر أفضل توازن بين الكفاءة والجودة والمرونة وإدارة المخاطر لتحقيق أهدافها التنفيذية بفعالية.
المهمة الخامسة
السؤال: ارسم مخططاً مُبسطاً لعمليات الحساب للآلية الآتية: حساب الراتب الإجمالي لمندوب مبيعات، راتبه الأساسي (300) دينار، والعمولة الإضافية التي يأخذها على النحو الآتي:
1. إذا كانت مبيعاته أقل من أو تساوي (1000) دينار، فإن نسبة عمولته تبلغ 6%.
2. إذا كانت مبيعاته أكثر من (1000) دينار، وأقل من أو تساوي (3000) دينار، فإن نسبة عمولته تبلغ 7.5%.
3. إذا كانت مبيعاته أكثر من (3000) دينار، وأقل من أو تساوي (5000) دينار، فإن نسبة عمولته تبلغ 9%.
4. إذا كانت مبيعاته أكثر من (5000) دينار، فإن نسبة عمولته تبلغ 10%.
الحل:
سنقوم برسم مخطط تدفق (Flowchart) يوضح خطوات حساب الراتب الإجمالي للمندوب بناءً على قيمة مبيعاته.
المكونات الأساسية للمخطط:
- البداية/النهاية (Terminal): شكل بيضاوي.
- العمليات (Process): شكل مستطيل (مثل حساب العمولة أو الراتب).
- المدخلات/المخرجات (Input/Output): شكل متوازي الأضلاع (مثل إدخال المبيعات أو عرض الراتب الإجمالي).
- القرارات (Decision): شكل معين (للتحقق من شروط المبيعات).
- الأسهم (Flowlines): لربط المكونات وتوضيح اتجاه التدفق.
مخطط التدفق:
graph TD
A[البداية] --> B{إدخال قيمة المبيعات};
B --> C{هل المبيعات <= 1000؟};
C -- نعم --> D[العمولة = المبيعات * 0.06];
C -- لا --> E{هل المبيعات <= 3000؟};
E -- نعم --> F[العمولة = المبيعات * 0.075];
E -- لا --> G{هل المبيعات <= 5000؟};
G -- نعم --> H[العمولة = المبيعات * 0.09];
G -- لا --> I[العمولة = المبيعات * 0.10];
D --> J[الراتب الإجمالي = 300 + العمولة];
F --> J;
H --> J;
I --> J;
J --> K[عرض الراتب الإجمالي];
K --> L[النهاية];
شرح المخطط:
- البداية: تبدأ العملية.
- إدخال قيمة المبيعات: يتم إدخال قيمة المبيعات التي حققها المندوب.
- هل المبيعات <= 1000؟: يتم التحقق من الشرط الأول.
- نعم: إذا كانت المبيعات أقل من أو تساوي 1000، يتم حساب العمولة بنسبة 6%.
- لا: إذا لم يتحقق الشرط الأول، ننتقل للتحقق من الشرط التالي.
- هل المبيعات <= 3000؟: يتم التحقق من الشرط الثاني.
- نعم: إذا كانت المبيعات أكبر من 1000 وأقل من أو تساوي 3000، يتم حساب العمولة بنسبة 7.5%.
- لا: ننتقل للشرط التالي.
- هل المبيعات <= 5000؟: يتم التحقق من الشرط الثالث.
- نعم: إذا كانت المبيعات أكبر من 3000 وأقل من أو تساوي 5000، يتم حساب العمولة بنسبة 9%.
- لا: ننتقل للشرط الأخير.
- العمولة = المبيعات * 0.10: إذا لم يتحقق أي من الشروط السابقة، فهذا يعني أن المبيعات أكبر من 5000، ويتم حساب العمولة بنسبة 10%.
- الراتب الإجمالي = 300 + العمولة: بعد حساب قيمة العمولة، يتم إضافتها إلى الراتب الأساسي (300 دينار) للحصول على الراتب الإجمالي.
- عرض الراتب الإجمالي: يتم عرض قيمة الراتب الإجمالي المحسوبة.
- النهاية: تنتهي العملية.
المهمة السادسة
السؤال: ما هو ناتج تنفيذ كل مقطع برمجي مما يأتي:
أ- المقطع الأول:
def repeat_string(s, n):
if n == 0:
return ""
else:
return s + repeat_string(s, n - 1)
print(repeat_string("Hello", 3))
الحل:
هذا المقطع البرمجي يستخدم الاستدعاء الذاتي (Recursion) لتكرار سلسلة نصية.
- الدالة
repeat_string(s, n):- تأخذ سلسلتين نصيتين
s(النص المراد تكراره) وn(عدد مرات التكرار). - الحالة الأساسية (Base Case): إذا كانت
nتساوي 0، تعيد سلسلة نصية فارغة"". هذا يوقف الاستدعاء الذاتي. - الحالة العودية (Recursive Case): إذا كانت
nأكبر من 0، تعيد السلسلةsمضافاً إليها نتيجة استدعاء الدالة نفسها معn-1.
- تأخذ سلسلتين نصيتين
تتبع التنفيذ:
repeat_string("Hello", 3)nليست 0، لذا تعيد"Hello" + repeat_string("Hello", 2)
repeat_string("Hello", 2)nليست 0، لذا تعيد"Hello" + repeat_string("Hello", 1)
repeat_string("Hello", 1)nليست 0، لذا تعيد"Hello" + repeat_string("Hello", 0)
repeat_string("Hello", 0)nتساوي 0، لذا تعيد""
النتيجة النهائية:
سيتم تجميع النتائج من الأسفل إلى الأعلى:
"Hello" + ("Hello" + ("Hello" + ""))
= "Hello" + ("Hello" + "Hello")
= "Hello" + "HelloHello"
= "HelloHelloHello"
الناتج:
HelloHelloHello
ب- المقطع الثاني:
def draw_triangle(n):
if n == 0:
return
else:
draw_triangle(n - 1)
print("*" * n)
draw_triangle(5)
الحل:
هذا المقطع البرمجي يستخدم أيضاً الاستدعاء الذاتي (Recursion) لرسم مثلث من النجوم.
- الدالة
draw_triangle(n):- تأخذ عدداً صحيحاً
nيمثل عدد الصفوف أو حجم المثلث. - الحالة الأساسية (Base Case): إذا كانت
nتساوي 0، فإن الدالة لا تفعل شيئاً وتعود (توقف الاستدعاء). - الحالة العودية (Recursive Case): إذا كانت
nأكبر من 0:- تستدعي الدالة نفسها مع
n-1(هذا يعني أنها ستبني المثلث من الأعلى إلى الأسفل). - بعد انتهاء الاستدعاء السابق (أي بعد طباعة الصفوف العليا)، تقوم بطباعة
nمن النجوم*.
- تستدعي الدالة نفسها مع
- تأخذ عدداً صحيحاً
تتبع التنفيذ:
draw_triangle(5):- تستدعي
draw_triangle(4)
- تستدعي
draw_triangle(4):- تستدعي
draw_triangle(3)
- تستدعي
draw_triangle(3):- تستدعي
draw_triangle(2)
- تستدعي
draw_triangle(2):- تستدعي
draw_triangle(1)
- تستدعي
draw_triangle(1):- تستدعي
draw_triangle(0)
- تستدعي
draw_triangle(0):- تتوقف (الحالة الأساسية).
- العودة إلى
draw_triangle(1):- تطبع
** 1 (أي*)
- تطبع
- العودة إلى
draw_triangle(2):- تطبع
** 2 (أي**)
- تطبع
- العودة إلى
draw_triangle(3):- تطبع
** 3 (أي***)
- تطبع
- العودة إلى
draw_triangle(4):- تطبع
** 4 (أي****)
- تطبع
- العودة إلى
draw_triangle(5):- تطبع
** 5 (أي*****)
- تطبع
الناتج:
*
**
***
****
*****
بالتأكيد! سأقوم بتقديم حل مختصر للسؤال الثالث، وحل مفصل للسؤال السادس مع الخطوات.
المهمة الثالثة
السؤال: اذكر وظائف ثلاث وحدات برمجية بايثون لعمل محاكاة لإدارة سجل التصفح (Browser History) بحيث:
1. تعمل الوحدة المستدعية على:
أ. تعريف السجل من خلال قائمة فارغة.
ب. استدعاء وحدات الإضافة والحذف ومعرفة الصفحة الحالية والحجم والتحقق فيما إذا كان السجل فارغاً أم لا.
- إنشاء:
أ. وحدة باسمpushتستخدم عند زيارة صفحة جديدة.
ب. وحدة تسمىpopلعرض الصفحة السابقة.
ج. وحدة تسمىpeekلعرض الصفحة الحالية.
د. معرفة عدد الصفحات من وحدة تسمىsize.
هـ. التحقق هل السجل فارغ أم لا باستخدام وحدة تسمىis_empty.
الحل المختصر:
push(page): تضيف صفحة جديدة إلى نهاية السجل.pop(): تزيل وتعيد الصفحة الأخيرة من السجل (الصفحة السابقة).peek(): تعرض الصفحة الأخيرة في السجل دون إزالتها (الصفحة الحالية).size(): تعيد عدد الصفحات في السجل.is_empty(): تعيدTrueإذا كان السجل فارغاً، وFalseإذا كان يحتوي على صفحات.
المهمة السادسة
السؤال: ما هو ناتج تنفيذ كل مقطع برمجي مما يأتي:
أ- المقطع الأول:
def repeat_string(s, n):
if n == 0:
return ""
else:
return s + repeat_string(s, n - 1)
print(repeat_string("Hello", 3))
الحل:
هذا المقطع يستخدم الاستدعاء الذاتي (Recursion) لتكرار سلسلة نصية.
- الوظيفة:
repeat_string(s, n)تأخذ سلسلة نصيةsوعدد مرات التكرارn. - آلية العمل:
- إذا كانت
nتساوي 0، تعيد سلسلة فارغة (هذه هي الحالة الأساسية التي توقف الاستدعاء). - إذا كانت
nأكبر من 0، تعيد السلسلةsمضافاً إليها نتيجة استدعاء الدالة نفسها معn-1. هذه هي الحالة العودية.
- إذا كانت
خطوات التنفيذ (تتبع الاستدعاء):
repeat_string("Hello", 3)تستدعيrepeat_string("Hello", 2)وتعيد"Hello" + نتيجة الاستدعاء.repeat_string("Hello", 2)تستدعيrepeat_string("Hello", 1)وتعيد"Hello" + نتيجة الاستدعاء.repeat_string("Hello", 1)تستدعيrepeat_string("Hello", 0)وتعيد"Hello" + نتيجة الاستدعاء.repeat_string("Hello", 0)تعيد""(الحالة الأساسية).
تجميع النتائج (من الداخل للخارج):
- الاستدعاء الرابع يعيد
"". - الاستدعاء الثالث يعيد
"Hello" + "" = "Hello". - الاستدعاء الثاني يعيد
"Hello" + "Hello" = "HelloHello". - الاستدعاء الأول يعيد
"Hello" + "HelloHello" = "HelloHelloHello".
الناتج النهائي:
HelloHelloHello
ب- المقطع الثاني:
def draw_triangle(n):
if n == 0:
return
else:
draw_triangle(n - 1)
print("*" * n)
draw_triangle(5)
الحل:
هذا المقطع يستخدم أيضاً الاستدعاء الذاتي (Recursion) لطباعة مثلث من النجوم.
- الوظيفة:
draw_triangle(n)تأخذ عدداً صحيحاًnيمثل حجم المثلث (أو عدد الصفوف). - آلية العمل:
- إذا كانت
nتساوي 0، تتوقف الدالة (الحالة الأساسية). - إذا كانت
nأكبر من 0:- أولاً، تستدعي الدالة نفسها مع
n-1. هذا يعني أنها ستكمل بناء الأجزاء العلوية من المثلث أولاً. - بعد اكتمال الاستدعاء الداخلي (أي بعد طباعة الصفوف العلوية)، تقوم بطباعة
nمن النجوم*.
- أولاً، تستدعي الدالة نفسها مع
- إذا كانت
خطوات التنفيذ (تتبع الاستدعاء والطباعة):
draw_triangle(5)تستدعيdraw_triangle(4).draw_triangle(4)تستدعيdraw_triangle(3).draw_triangle(3)تستدعيdraw_triangle(2).draw_triangle(2)تستدعيdraw_triangle(1).draw_triangle(1)تستدعيdraw_triangle(0).draw_triangle(0)تتوقف.- تعود
draw_triangle(1)لتنفذprint("*" * 1)فتطبع*. - تعود
draw_triangle(2)لتنفذprint("*" * 2)فتطبع**. - تعود
draw_triangle(3)لتنفذprint("*" * 3)فتطبع***. - تعود
draw_triangle(4)لتنفذprint("*" * 4)فتطبع****. - تعود
draw_triangle(5)لتنفذprint("*" * 5)فتطبع*****.
الناتج النهائي (تسلسل ما تم طباعته):
*
**
***
****
*****