Search code examples
pythonstackcorruptionpostfix-notation

my python code corrupts '*' into '(' when pushed to a Stack class


If I push a character to the Stack and peek at it, it gives me different characters even when no interaction was made after the push.

The relevant class and functions look like this:

class Stack:
    def __init__(self):
        self.data = []
        self.top = -1
        self.max = 10

    def isFull(self):
        if self.top == (self.max-1):
            return True
        else:
            return False

    def isEmpty(self):
        if self.top == -1:
            return True
        else:
            return False

    def push(self, input):
        if self.isFull():
            print(f"Push({input}) : Stack is full")
        else:
            self.top += 1
            self.data.append(input)

    def pop(self):
        if self.isEmpty():
            print("Pop : Stack is empty")
        else:
            temp = self.data[self.top]
            self.top -= 1
            return temp

    def peek(self):
        if self.isEmpty():
            print("Peek : Stack is empty")
        else:
            return self.data[self.top]
        
    def printStack(self):
        if self.isEmpty():
            print("Print : Stack is empty")
        else:
            print("Stack : ", end="")
            for i in range(0,self.top+1):
                print(self.data[i], end=" ")
            print()

def stringToList(input):
    input = input.replace(' ', '')
    result = []
    temp = ''
    i = 0
    while i < len(input):
        char = input[i]
        if char.isdigit() or char == '.':
            temp += str(char)
        else:
            if temp != "":
                result.append(float(temp))
                temp = ''
            if char == '*' and i + 1 < len(input) and input[i + 1] == '*' :
                result.append('**')
                i += 1
            else:
                result.append(char)
        i += 1
    if temp != "":
        result.append(float(temp))
    return result

def infixToPostfix(input):
    stack = Stack()
    result = []
    for i in input:
        print(f"i = '{i}'")
        if type(i) == float:
            result.append(i)
        elif i == '(':
            stack.push(i)
        elif i == ')':
            while stack.isEmpty() == False and stack.peek() != '(':
                result.append(stack.pop())
            stack.pop()
        else:
            while stack.isEmpty() == False and stack.peek() != '(' and priority(i) <= priority(stack.peek()):   
                result.append(stack.pop())
            stack.push(i)

            print(f"stack.peek() = '{stack.peek()}'")

        print(f"result = {result}")
        stack.printStack()
        print()


    while stack.isEmpty() == False:
        result.append(stack.pop())
    return result

def priority(char):
    if char == '+' or char == '-':
        return 1
    elif char == '*' or char == '/':
        return 2
    elif char == '**':
        return 3
    else:
        return -1

the input itself is given through the following code:

input = input("expression : ")
postfix = infixToPostfix(stringToList(input))
print(f"postfix : {postfix}")

I triple-checked that the other code( including stringToList() ) works correctly.

when given (10+2*1.5)*3 as input, the code outputs the following:

i = '('
result = []
Stack : (

i = '10.0'
result = [10.0]
Stack : (

i = '+'
stack.peek() = '+'
result = [10.0]
Stack : ( +

i = '2.0'
result = [10.0, 2.0]
Stack : ( +

i = '*'
stack.peek() = '*'
result = [10.0, 2.0]
Stack : ( + *

i = '1.5'
result = [10.0, 2.0, 1.5]
Stack : ( + *

i = ')'
result = [10.0, 2.0, 1.5, '*', '+']       
Print : Stack is empty

i = '*'
stack.peek() = '('
result = [10.0, 2.0, 1.5, '*', '+']       
Stack : (

i = '3.0'
result = [10.0, 2.0, 1.5, '*', '+', 3.0]  
Stack : (

postfix : [10.0, 2.0, 1.5, '*', '+', 3.0, '(']

As you can see from the 8th iteration, the '*' became a '(' for no specific reason. Expected output was :

i = '3.0'
result = [10.0, 2.0, 1.5, '*', '+', 3.0]  
Stack : *

thus making the postfix : [10.0, 2.0, 1.5, '*', '+', 3.0, '*'] I have moving the print(i) right above the printStack() method, but I am getting the same outputs. I have tried all the python interpreters that I could get my hand to, but always got the same result, so i don't think it is a local env problem.


Solution

  • The problem is that pop() decrements self.top, but it doesn't remove the popped element from the end of self.data.

    So self.data still has elements at indices greater than self.top.

    The specific problem comes when a push follows a pop. The push() method calls self.data.append(input), and this adds the data at the end of self.data, not at the position pointed to by self.top.

    The fix is to remove the popped item from self.data, which you could do using the .pop() method of a list:

        def pop(self):
            if self.isEmpty():
                print("Pop : Stack is empty")
            else:
                self.top -= 1
                return self.data.pop()
    

    With that change, your test input (10+2*1.5)*3 gives the result you expect:

    i = '3.0'
    result = [10.0, 2.0, 1.5, '*', '+', 3.0]
    Stack : * 
    
    postfix : [10.0, 2.0, 1.5, '*', '+', 3.0, '*']
    

    You could further improve the code by removing the use of self.top. With the fix here, you no longer need it, because len(self.data) now tells you how many items are on the stack, and the top element (assuming the stack isn't empty) is self.data[-1].