حل عبارت ریاضی با پشته در پایتون
از مسائل مهم ساختمان داده همیشه از پشتهها میتوان نام برد؛ پشتهها یک نوع ساختمان دادهای هستند که برای نگهداری دادهها استفاده میشوند و فرآیند ورود و خروج خاصی دارند. به نحوه ورود و خروج دادهها از پشته Lifo میگوییم. در این نوشته با حل عبارتهای ریاضی معمولی یا infix به کمک پشتهها (دو پشته) با زبان برنامه نویسی پایتون میپردازیم.
حل عبارت ریاضی با پشته در پایتون
با استفاده از کد زیر به کمک پشتهها یک عبارت میان وندی را با زبان برنامه نویسی پایتون برای شما حل میکنیم:
def isOperator(c):
if c != "": return (c in "+-*/")
else: return False
def checkPriority(c):
if c in "+-": return 0
if c in "*/": return 1
def isNumber(c):
if c != "": return (c in "0123456789.")
else: return False
def runOperator(op, number1, number2):
if op == "+": return str(float(number1) + float(number2))
if op == "-": return str(float(number1) - float(number2))
if op == "*": return str(float(number1) * float(number2))
if op == "/": return str(float(number1) / float(number2))
def Calculation(expr):
expr = list(expr)
stack_o = list()
stack_n = list()
num = ""
while len(expr) > 0:
c = expr.pop(0)
if len(expr) > 0: d = expr[0]
else: d = ""
if isNumber(c):
num += c
if not isNumber(d):
stack_n.append(num)
num = ""
elif isOperator(c):
while True:
if len(stack_o) > 0: top = stack_o[-1]
else: top = ""
if isOperator(top):
if not checkPriority(c) > checkPriority(top):
number2 = stack_n.pop()
op = stack_o.pop()
number1 = stack_n.pop()
stack_n.append(runOperator(op, number1, number2))
else:
stack_o.append(c)
break
else:
stack_o.append(c)
break
elif c == "(":
stack_o.append(c)
elif c == ")":
while len(stack_o) > 0:
c = stack_o.pop()
if c == "(":
break
elif isOperator(c):
number2 = stack_n.pop()
number1 = stack_n.pop()
stack_n.append(runOperator(c, number1, number2))
while len(stack_o) > 0:
c = stack_o.pop()
if c == "(":
break
elif isOperator(c):
number2 = stack_n.pop()
number1 = stack_n.pop()
stack_n.append(runOperator(c, number1, number2))
return stack_n.pop()
# For Exam : ((4*2)-(3-1))/(8-3*2) = 3.0
my_input = input("Enter String For Calculation : ")
print(Calculation(my_input))
با توجه به کد بالا به عنوان مثال یک ورودی مثل ورودی زیر میدهیم:
((4*2)-(3-1))/(8-3*2)
و در صورتی که کد بالا را درست اجرا کنید باید خروجی 3 را مشاهده کنید.
توضیحات
- در کد بالا از دو پشته با نامهای stack_o و stack_n استفاده شده است که از پشتهی stack_n به عنوان پشتهای برای نگهداری اعداد و از پشتهی stack_o برای نگهداری عملگرها استفاده کردیم.
- کد بالا با زبان برنامه نویسی پایتون نوشته شده است.
- در کد بالا عبارت ریاضی میاوندی را میتوانید به صورت دستی وارد کنید و هر بار یک عبارت خاص اجرا کنید و در واقع ورودی را از کاربر خواهید گرفت.
- در کد بالا توابع زیر را تعریف کردهایم:
- isOperator
- checkPriority
- isNumber
- runOperator
- Calculation
- این برنامه اعداد اعشاری را نیز محاسبه میکند.
پشته یک ساختار دادهای هست که هر چیزی زودتر داخلش وارد بشه آخرین آیتم میتونه خارج بشه اصطلاحا بهش میگن مدل FIFO داره مثل یه پارکینگ که کلا مستطیلی رو به جلو هست باید ماشینی که آخر قرار گرفته خارج بشه و بعد ماشینهای دیگه الی آخر. پشتههای یه سری عملیات کلی دارن مثل pop که برای خواندن از پشته هست به این معنی که آخر المانی که وارد شده رو میخونه و از پشته خارج میشه push یه آیتم رو وارد پشته میکنه is empty خالی بودن پشته رو بررسی میکنه که معمولا موقعی که تابع pop فراخوانی میشه ازش استفاده میشه is full هم برای اینکه پر بودن پشته رو بررسی کنه استفاده میشه که در کنار push کاربرد داره. دقت کنید is empty و is full در واقع خروجی بولین یا true false دارند. توی این سوال قرار هست یک عبارت ریاضی حل بشه اون هم با کمک پشتهها. اگر دانش حداقلی ریاضی دارید، میدونید که توی ریاضیات عملگرها که همون چهار عمل اصلی هستند و باقی عملگرها الویت دارند و پرانتز هم که اولویت اول رو داره عبارت رو از ابتدا شروع میکنه به خوندن هر جا پرانتز باز دید میاد پرانتز رو داخل پشته میزاره هر وقت یک عملگر دید عملوند بعدی رو (عملوند منظور در اینجا اون اعداد هستن) میگیره و حساب میکنه نتیجه رو میزاره توی پشته. با پرانتزهای بسته هم نتیجه ذخیره میشه و عبارت تا پایان این شکلی حل میشه.
اگر روشهای بهتری برای حل عبارتهای میانوندی با کمک زبان برنامه نویسی پایتون در اختیار دارید در بخش نظرات همین نوشته برای ما ارسال کنید.



















به نظر شما میشه این کد رو طوری تغییر داد که از اعداد منفی هم پشتیبانی کنه؟
بله با کمی تغییر در تابع isNumber و منطق پردازش اعداد، امکان پشتیبانی از اعداد منفی نیز وجود دارد.
برای تقسیم بر صفر چه خروجی میده؟
کد ارائه شده برای تقسیم بر صفر خطایی ایجاد میکند. برای مدیریت این مورد، میتوان قبل از اجرای عملیات تقسیم، صفر بودن مخرج را بررسی کرد.
آیا میشه به جای دو پشته از یک پشته استفاده کرد و همون نتیجه رو گرفت؟
بله، با کمی تغییر در منطق و الگوریتم، میتوان با استفاده از یک پشته نیز عبارتهای ریاضی را حل کرد، اما معمولاً استفاده از دو پشته برای این منظور رایجتر و خواناتر است.
میشه این روشو برای حل معادلات پیچیدهتر هم استفاده کرد یا محدودیت داره؟
بله این روش قابلیت تعمیم برای حل معادلات پیچیدهتر را دارد، اما ممکن است نیاز به تغییراتی در منطق برنامه برای مدیریت عملگرها و ساختارهای پیچیدهتر داشته باشد.
برای ورودیهای طولانی هم درست جواب میده؟
بله این الگوریتم برای ورودیهای طولانی هم به درستی کار میکند و جواب میدهد.