i'm making expression parsing algorithm using stack by python and when i input equation without whitespaces like this "1+2*3+10" it doesn't work properly,sometimes give error result and sometimes it give an error , it should be entered like "1 + 2 * 3 + 10" to work
def applyOp(a, b, op):
if op == '+': return a + b
if op == '-': return a - b
if op == '*': return a * b
if op == '/': return a // b
def evaluate(tokens):
values = Stack()
ops = Stack()
i = 0
while i < len(tokens):
if tokens[i] == ' ':
i += 1
continue
elif tokens[i] == '(':
ops.push(tokens[i])
elif tokens[i].isdigit():
val = 0
while (i < len(tokens) and
tokens[i].isdigit()):
val = (val * 10) + int(tokens[i])
i += 1
values.push(val)
elif tokens[i] == ')':
while ops.peek() != None and ops.peek() != '(':
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
# print(val2 , val1 , op)
values.push(applyOp(val1, val2, op))
ops.pop()
else:
while (ops.peek() != None and
precedence(ops.peek()) >= precedence(tokens[i])):
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.push(applyOp(val1, val2, op))
ops.push(tokens[i])
i += 1
while ops.peek() != None:
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.push(applyOp(val1, val2, op))
return values.peek()
I'm not sure if this is the only problem, but
elif tokens[i].isdigit():
val = 0
while (i < len(tokens) and
tokens[i].isdigit()):
val = (val * 10) + int(tokens[i])
i += 1
values.push(val)
advances i too far. It stops when i is already pointing to something that's not a digit, and then when you advance i again at the end of the outer while loop you will miss whatever was there, which doesn't matter if it's a space - so that's why spaces fix it.
EDIT: Okay so I tried it out, swapping the mentioned elif statement with this should work:
elif tokens[i].isdigit():
val = int(tokens[i])
while i+1 < len(tokens) and tokens[i+1].isdigit():
i += 1
val = (val * 10) + int(tokens[i])
values.append(val)
Related
I'm using the following code to perform stack implementation in the case of solving arbitrary arithmetic operations:
def precedence(op):
if op == '+' or op == '-':
return 1
if op == '*' or op == '/':
return 2
return 0
def operation(a, b, op):
if op == '+': return a + b
if op == '-': return a - b
if op == '*': return a * b
if op == '/': return a / b
def evaluate(tokens):
# This is a stack to store integer values
values = []
# This stack stores operators
ops = []
i = 0
while i < len(tokens):
if tokens[i] == ' ':
i += 1
continue
elif tokens[i] == '(':
ops.append(tokens[i])
elif tokens[i].isdigit():
val = 0
while (i < len(tokens) and
tokens[i].isdigit()):
val = (val * 10) + int(tokens[i])
i += 1
values.append(val)
i -= 1
elif tokens[i] == ')':
while len(ops) != 0 and ops[-1] != '(':
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.append(operation(val1, val2, op))
ops.pop()
else:
while (len(ops) != 0 and
precedence(ops[-1]) >=
precedence(tokens[i])):
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.append(operation(val1, val2, op))
ops.append(tokens[i])
i += 1
while len(ops) != 0:
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.append(operation(val1, val2, op))
return values[-1]
if __name__ == "__main__":
ask = input('Enter your expression here: ')
print(f"\nThe answer is {evaluate(ask)}")
But I have no clue how to translate this implementation of stack using linked list.
Can anyone help me? Or provide me with links that would be helpful in explaining stack using linked lists ?
Thanks!
class LLstack:
def __init__(self):
self.numNodes = 0
self.tail = None
def __iter__(self):
self.n = self.numNodes
self.index = self.tail
return self
def __next__(self):
if (self.n == self.numNodes):
self.n-=1
return self.index.val
if self.n>0:
self.n-=1
self.index = self.index.next
return self.index.val
else:
raise StopIteration
def push(self,val):
self.numNodes+=1
if (self.tail!=None):
temp = self.Node(val)
temp.next = self.tail
self.tail = temp
else:
self.tail = self.Node(val)
def pop(self):
if (self.numNodes==0):
return None
self.numNodes-=1
val = self.tail.val
self.tail = self.tail.next
return val
def size(self):
return self.numNodes
class Node:
def __init__(self,val):
self.val = val
self.next = None
if __name__== "__main__":
stack = LLstack()
for i in range(100):
stack.push(LLstack())
i = iter(stack)
for x in i:
print(x)
https://algs4.cs.princeton.edu/13stacks/
Not sure if this is what you are looking for.
I want to implement basic calculator only includes numbers, '+' and '-' in Python. But I found that I cannot change index i inside the while loop.
def basicCalculator(expression):
res = 0
sign = 1
i = 0
while i < len(expression): # using while loop here
if expression[i] == '+':
sign = 1
elif expression[i] == '-':
sign = -1
elif '0' <= expression[i] <= '9':
temp = int(expression[i])
while i + 1 < len(expression) and '0' <= expression[i + 1] <= '9':
i += 1 # want to increase i, but failed
temp = temp * 10 + int(expression[i])
res += sign * temp
return res
s = "2+3-999"
print(basicCalculator(s)) # ouput should be -994, but infinite
Then I tried another way: using for loop instead of while loop, get incorrect answer.
def basicCalculator(expression):
res = 0
sign = 1
for i in range(len(expression)): # using for loop
if expression[i] == '+':
sign = 1
elif expression[i] == '-':
sign = -1
elif '0' <= expression[i] <= '9':
temp = int(expression[i])
while i + 1 < len(expression) and '0' <= expression[i + 1] <= '9':
i += 1 # increase i
temp = temp * 10 + int(expression[i])
res += sign * temp
return res
s = "2+3-999"
print(basicCalculator(s)) # ouput should be -994, but got -1102
I don't know why I cannot change the index inside the while loop or for loop. It is not a good idea to change i in for loop. What is the best way to fix the bug?
(I wrote the same code in Java using approach 2, everything is good, any difference?)
Rather than incrementing the index in a loop within the loop, I suggest just accumulating the current number in the main loop so you have less to keep track of:
def basicCalculator(expression):
res = 0
sign = 1
num = ""
for c in expression:
if c.isdecimal():
num += c
continue
res += int(num) * sign
num = ""
if c == "+":
sign = 1
elif c == "-":
sign = -1
else:
raise ValueError(f"Invalid operator {c}")
return res + int(num) * sign
print(basicCalculator("2+3-999")) # -994
I have code to generate a postfix expression from infix and generate an expression tree from the postfix notation. The problem is, if I give it an expression like 45 / 15 * 3, it will give me the result 1 instead of 9, because it is solving the deepest levels of the tree first. Is there another traversal I can do to evaluate the expression properly?
def evaluate(self):
if not self.is_empty():
if not infix_to_postfix.is_operator(self._root):
return float(self._root)
else:
A = self._left.evaluate()
B = self._right.evaluate()
if self._root == "+":
return A + B
elif self._root == "-":
return A - B
elif self._root == "*":
return A * B
elif self._root == "/":
return A / B
def InfixToPostfix(exp: str):
exp = exp.replace(" ", "")
S = Stack()
postfix = ""
j = 0
for i in range(len(exp)):
if is_operand(exp[i]):
if i + 1 <= len(exp) - 1 and is_operand(exp[i+1]):
continue
else:
j = i
while j - 1 >= 0 and is_operand(exp[j - 1]):
if is_operand(exp[j]):
j -= 1
else:
break
postfix += exp[j:i + 1] + " "
elif is_operator(exp[i]):
while not S.is_empty() and S.top() != "(" and \ HasHigherPrecedence(S.top(), exp[i]):
if is_operator(S.top()):
postfix += S.top() + " "
else:
postfix += S.top()
S.pop()
S.push(exp[i])
elif exp[i] == "(":
S.push(exp[i])
elif exp[i] == ")":
while not S.is_empty() and S.top() != "(":
if is_operator(S.top()):
postfix += S.top() + " "
else:
postfix += S.top()
S.pop()
else:
print("There's an invalid character")
return
while not S.is_empty():
if S.top() == '(':
S.pop()
continue
if is_operator(S.top()):
postfix += S.top() + " "
else:
postfix += S.top()
S.pop()
return postfix
def HasHigherPrecedence(op1: str, op2: str):
op1_weight = get_operator_weight(op1)
op2_weight = get_operator_weight(op2)
return op1_weight > op2_weight
The postfix expression of your example 45 / 15 * 3 would be:
45 15 / 3 *
So the tree generated would look like:
*
/ 3
45 15
So your traversal algorithm appears correct, as it would do 45 / 15 = 3, then 3 * 3 = 9.
The issue is actually pretty minor in your postfix generator. Specifically, in the function HasHigherPrecedence, you should return op1_weight >= op2_weight. It should be greater than or equal to because in examples such as this one where the operators have the same precedence, they should be executed in the order they appear. So division would be done first.
I am trying to find a way to create a calculator where the user can input
6+8 for example and get an answer.
I'm trying to find a better way to get it to work for numbers of more than one digit or a function for it to work for anything.
Below is my code so far.
calc = input("Enter the calculation ")
nums = []
for i in calc: # Only works for single-digit numbers eg: 6+6
try:
if i != " ":
float(i)
except ValueError:
op = str(i)
lcalc = len(calc)
if lcalc == 3:
calc2 = calc[0]
calc3 = calc[2]
nums.append(int(calc2))
nums.append(int(calc3))
elif lcalc == 5:
calc2 = calc[0:2]
calc3 = calc[3:5]
nums.append(int(calc2))
nums.append(int(calc3))
elif lcalc == 7:
calc2 = calc[0:3]
calc3 = calc[4:7]
nums.append(int(calc2))
nums.append(int(calc3))
print(nums)
if op == "+":
print("Final answer = " +str(sum(nums)))
elif op == "-":
print("Final answer = " +str(nums[0] - nums[1]))
elif op == "/":
print("Final answer = " +str(nums[0] / nums[1]))
elif op == "*":
print("Final answer = " +str(nums[0] * nums[1]))
Easiest way is:
calc = input("Enter the calculation: ")
print("Final answer:", eval(calc))
Explanation: when you enter 6+8 it's also python expression and eval() returns result of python expression.
But user can type any python expression (like quit() or something with strings).
So better answer would be:
calc = input("Enter the calculation: ")
calc = calc.replace(" ", "")
m_i = calc.find("*")
m_i = len(calc) if m_i == -1 else m_i
d_i = calc.find("/")
d_i = len(calc) if d_i == -1 else d_i
while m_i < len(calc) or d_i < len(calc):
i = min(m_i, d_i)
p_i = calc.rfind("+", 0, i)
s_i = calc.rfind("-", 0, i)
val1_i = max(p_i, s_i)
val1 = int(calc[val1_i + 1:i])
p_i = calc.find("+", i)
p_i = len(calc) if p_i == -1 else p_i
s_i = calc.find("-", i)
s_i = len(calc) if s_i == -1 else s_i
val2_i = min(p_i, s_i)
val2 = int(calc[i + 1:val2_i])
if i == m_i:
ans = str(val1 * val2)
else:
ans = str(val1 // val2)
calc = calc.replace(calc[val1_i + 1:val2_i], ans, 1)
m_i = calc.find("*")
m_i = len(calc) if m_i == -1 else m_i
d_i = calc.find("/")
d_i = len(calc) if d_i == -1 else d_i
val = 0
t = "+"
i = -1
for p, x in enumerate(calc):
if x in "+-":
v = int(calc[i + 1:p])
if t == "+":
val += v
else:
val -= v
i = p
t = x
v = int(calc[i + 1:])
if t == "+":
val += v
else:
val -= v
print("Final answer:", val)
So first line is like in previous way. Line:
calc = calc.replace(" ", "")
Replaces all spaces in string with empty string (so it deletes it).
m_i = calc.find("*")
m_i = len(calc) if m_i == -1 else m_i
d_i = calc.find("/")
d_i = len(calc) if d_i == -1 else d_i
finds earliest / and * if none found set them to end of string,
while m_i < len(calc) or d_i < len(calc):
i = min(m_i, d_i)
loop that executes while multiplication or division signs are found, i is earlier of signs,
p_i = calc.rfind("+", 0, i)
s_i = calc.rfind("-", 0, i)
val1_i = max(p_i, s_i)
val1 = int(calc[val1_i + 1:i])
finds value of left operand (first finds last + and last - sign, higher of these two plus one is starting index of left operand).
Lines:
p_i = calc.find("+", i)
p_i = len(calc) if p_i == -1 else p_i
s_i = calc.find("-", i)
s_i = len(calc) if s_i == -1 else s_i
val2_i = min(p_i, s_i)
val2 = int(calc[i + 1:val2_i])
are very similar to previous ones, except they finds right operand.
if i == m_i:
ans = str(val1 * val2)
else:
ans = str(val1 // val2)
calc = calc.replace(calc[val1_i + 1:val2_i], ans, 1)
Calculates result of multiplication or division (I wrote // because I think you want integer division) and replaces expression with result.
Last lines of loop are same as lines before loop so I won't explain them.
In last loop t is operator and if it's +, val will increase for last value, otherwise it will decrease.
Last line just prints final value.
Note: using regular expression (re) can help a lot, especially if you add brackets, power, and similar.
I want to make a binary calculator and I have a problem with the subtraction part. Here is my code (I have tried to adapt one for sum that I've found on this website).
maxlen = max(len(s1), len(s2))
s1 = s1.zfill(maxlen)
s2 = s2.zfill(maxlen)
result = ''
carry = 0
i = maxlen - 1
while(i >= 0):
s = int(s1[i]) - int(s2[i])
if s <= 0:
if carry == 0 and s != 0:
carry = 1
result = result + "1"
else:
result = result + "0"
else:
if carry == 1:
result = result + "0"
carry = 0
else:
result = result + "1"
i = i - 1
if carry>0:
result = result + "1"
return result[::-1]
The program works fine with some binaries subtraction but it fails with others.
Can someone please help me because I can't find the mistake? Thanks a lot.
Short answer: Your code is wrong for the case when s1[i] == s2[i] and carry == 1.
Longer answer: You should restructure your code to have three separate cases for s==-1, s==0, and s==1, and then branch on the value of carry within each case:
if s == -1: # 0-1
if carry == 0:
...
else:
...
elif s == 0: # 1-1 or 0-0
if carry == 0:
...
else:
...
else: # 1-0
if carry == 0:
...
else:
...
This way you have a separate block for each possibility, so there is no chance of overlooking a case like you did on your first attempt.
I hope the answer below it helps.
def binarySubstration(str1,str2):
if len(str1) == 0:
return
if len(str2) == 0:
return
str1,str2 = normaliseString(str1,str2)
startIdx = 0
endIdx = len(str1) - 1
carry = [0] * len(str1)
result = ''
while endIdx >= startIdx:
x = int(str1[endIdx])
y = int(str2[endIdx])
sub = (carry[endIdx] + x) - y
if sub == -1:
result += '1'
carry[endIdx-1] = -1
elif sub == 1:
result += '1'
elif sub == 0:
result += '0'
else:
raise Exception('Error')
endIdx -= 1
return result[::-1]
normalising the strings
def normaliseString(str1,str2):
diff = abs((len(str1) - len(str2)))
if diff != 0:
if len(str1) < len(str2):
str1 = ('0' * diff) + str1
else:
str2 = ('0' * diff) + str2
return [str1,str2]