إتقان تقييم التعبير
والتنقل عبر الشجرة
باستخدام تعدد الأشكال
في مجال البرمجة، فإن فهم تقييم التعبير والقدرة على التلاعب بـ الأشجار الثنائية هي مهارات حيوية يمكنها تعزيز قدراتك في التطوير. إحدى الطرق المثيرة لتطبيق هذه المفاهيم هي من خلال استخدام تعدد الأشكال، خاصة ضمن برمجة الكائنات (OOP).
ستستكشف هذه التدوينة سؤال المقابلة الكلاسيكي المستوحى من ملاحظات ستيف ييجي، حيث يتم تحدي المرشحين لتحويل تعبير حسابي (مثل السلسلة “2 + (2)”) إلى شجرة تعبير. سنقوم باستعراض المشكلة خطوة بخطوة، مع شرح كيفية معالجة هذه الأشجار باستخدام تعدد الأشكال، وتقديم رؤى حول الكود.
المشكلة: من التعبير إلى الشجرة
فهم الأساسيات
في جوهرها، تتمثل المهمة في تمثيل وتقييم التعبيرات الحسابية كأشجار ثنائية:
- العقد الورقية: هذه هي الأرقام.
- العقد الداخلية: هذه هي العمليات (مثل
+
،-
،*
،/
).
يتضمن تقييم مثل هذه التعبيرات “التنقل” عبر هيكل الشجرة. إذا واجهت هذه المشكلة، إليك كيفية البدء:
- تحويل التعبير: تحديد كيفية تحويل تعبير كسري إلى هيكل شجري.
- تقييم التعبير: التجول في الشجرة لحساب القيمة النهائية.
لماذا نستخدم تعدد الأشكال؟
كثيراً ما يجد المرشحون للبرمجة صعوبة في أفضل طريقة لتنفيذ هذه المهام. يمكن أن تصبح الطرق الأكثر بساطة، مثل استخدام عبارة switch أو هياكل if-else المتسلسلة، غير مريحة وصعبة الإدارة.
تعدد الأشكال يتيح لك تعريف واجهة شائعة لمجموعة من الفئات المرتبطة، مما يؤدي إلى تصميم أكثر مرونة وسهولة في الإدارة. عندما تواجه عمليات مختلفة، يمكنك من خلال تعدد الأشكال استدعاء الطريقة الصحيحة دون الحاجة لمعرفة تفاصيل تنفيذ العملية.
الحل: تنفيذ الأشجار متعددة الأشكال في بايثون
دعونا نستكشف الكود لفهم كيفية عمل تعدد الأشكال في هذا السياق بشكل أفضل.
شرح الكود
#!/usr/bin/python
class Node:
"""فئة أساسية، يجب ألا تعالج واحدة من هذه."""
def process(self):
raise('يجب ألا تعالج عقدة') # مجرد تجريد
class BinaryNode(Node):
"""فئة أساسية للعقد الثنائية."""
def __init__(self, _left, _right):
self.left = _left
self.right = _right
def process(self):
raise('يجب ألا تعالج عقدة ثنائية') # مجرد تجريد
class Plus(BinaryNode):
def process(self):
return self.left.process() + self.right.process()
class Minus(BinaryNode):
def process(self):
return self.left.process() - self.right.process()
class Mul(BinaryNode):
def process(self):
return self.left.process() * self.right.process()
class Div(BinaryNode):
def process(self):
return self.left.process() / self.right.process()
class Num(Node):
def __init__(self, _value):
self.value = _value
def process(self):
return self.value
# حالات اختبار للتوضيح
def demo(n):
print(n.process())
demo(Num(2)) # الناتج: 2
demo(Plus(Num(2), Num(5))) # الناتج: 7 (2 + 5)
demo(Plus(Mul(Num(2), Num(3)), Div(Num(10), Num(5)))) # الناتج: 8 ((2 * 3) + (10 / 5))
تحليل الكود
-
الفئة الأساسية المجردة:
Node
- هذه تعتبر فئة أساسية لجميع العقد.
- تم تصميم طريقة
process()
لتكون قابلة للتجاوز ولكن لا يتم تنفيذها مباشرة علىNode
.
-
الفئة الأساسية المجردة:
BinaryNode
- ترث من
Node
و تمثل العمليات الثنائية. - تحتوي على عقد فرعية للتعبيرات الفرعية اليسرى واليمنى.
- ترث من
-
فئات ملموسة للعمليات
- فئات
Plus
وMinus
وMul
وDiv
ترث منBinaryNode
وتقوم بتنفيذ طريقةprocess()
لتقييم التعبيرات.
- فئات
-
فئة العقدة الورقية:
Num
- تمثل القيم الرقمية وتقوم ببساطة بإرجاع القيمة المخزنة عند استدعاء
process()
.
- تمثل القيم الرقمية وتقوم ببساطة بإرجاع القيمة المخزنة عند استدعاء
الأفكار النهائية
يقدم تعدد الأشكال طريقة قوية لتنفيذ تقييم التعبير في البرمجة. من خلال الالتزام بهيكلية مماثلة، يمكن للمطورين إنشاء كود واضح ومنظم ومرن يسمح بإضافات وتعديلات سهلة.
في الختام، يفتح إتقان تحويل سلسلة تعبير حسابي إلى شجرة تعبير باستخدام تعدد الأشكال مجموعة واسعة من الاحتمالات. لا تعمل هذه الأنماط التصميمية على تبسيط عمليات البرمجة فحسب، بل تعزز أيضًا قابلية صيانة الشفرة الخاصة بك.
الآن بعد أن فهمت المفهوم، حاول تنفيذ تنويعات خاصة بك واستكشاف العالم الواسع من البرمجة!