Stack

This lesson will introduce you to the stack data structure and its implementation in Python which we'll use in the problems throughout this chapter.

We'll cover the following

In this lesson, we are going to consider the stack data structure and its implementation in Python.

In subsequent lessons, we’ll provide specific problems where a stack is particularly useful. We’ll be using the implementation that we develop in this lesson to solve those problems.

What is a stack? #

First of all, let me describe what a stack is. Based on the name, it should be a relatively familiar concept.

Let’s assume that we have four books with the following riveting titles:

• A
• B
• C
• D

At the moment, these books are strewn out all over the floor and we want to stack them up neatly.

Now we have a nice neat stack of books! If we want to retrieve a book from this stack, we can take the book on top. Taking a book from the bottom is a bit precarious and we don’t want to topple the entire stack. Therefore, we’ll take down the top book on the stack and read it or do whatever we want to do with it.

Let’s say we want to take Book A. Right now, it is at the bottom of the stack, so we need to take Book D, put it down, then do the same for Book C and Book B, and then we can access Book A.

This is the main idea of a stack. The data structure stack is very similar to a physical stack that you’d most likely be familiar with. The stack data structure allows us to place any programming artifact, variable or object on it, just as our example stack allowed us to put books in it.

Stack Operations #

Push#

The operation to insert elements in a stack is called push. When we push the book on a stack, we put the book on the previous top element which means that the new book becomes the top element. This is what we mean when we use the push operation, we push elements onto a stack. We insert elements onto a stack and the last element to be pushed is the new top of the stack.

Pop#

There is another operation that we can perform on the stack, popping. Popping is when we take the top book of the stack and put it down. This implies that when we remove an element from the stack, the stack follows the First-In, Last Out property. This means that the top element, the last to be inserted, is removed when we perform the pop operation.

Push and Pop are two fundamental routines that we’ll need for this data structure.

Peek#

Another thing that we can do is view the top element of the stack so we can ask the data structure: “What’s the top element?” and it can give that to us using the peek operation. Note that the peek operation does not remove the top element, it merely returns it.

We can also check whether or not the stack is empty, and a few other things too, that will come along the way as we implement it.

Now I’m going to create a stack class, and the constructor of the class is going to initialize a Python list. The Python list has a lot of things that we’re after, and it’s going to make it easier for us to tweak Python’s implementation of the list to be adapted to what we would expect to see in a stack, namely, push/pop.

"""Stack Data Structure."""class Stack():    def __init__(self):        self.items = []

I’m defining a class variable that I’m calling items, and I’m assigning it to an empty list. self.items is created when we create a stack object so now let’s create the push method:

"""Stack Data Structure."""class Stack():    def __init__(self):        self.items = []    def push(self, item):        self.items.append(item)

push is going to be a member of this class, and it’s going to take an item as an argument. In our example, that item is the book. We are putting or pushing the name of the book onto the top of the stack.

append is a built-in method for a Python list that adds the item to the end of the list. This is just what we want to do for our stack in the push method.

"""Stack Data Structure."""class Stack():    def __init__(self):        self.items = []    def push(self, item):        self.items.append(item)				    def pop(self):        return self.items.pop()

The other method we need to implement is pop. Since we’re basing this off a list, Python makes this very easy as well. There is an implicit pop method that returns the last element inserted to the list.

Another thing that we’re going to do is add a few more methods, but before that, I’m going to do a test drive.

"""Stack Data Structure."""class Stack():    def __init__(self):        self.items = []    def push(self, item):        self.items.append(item)				    def pop(self):        return self.items.pop()    def get_stack(self):        return self.itemsmyStack = Stack()myStack.push("A")myStack.push("B")print(myStack.get_stack())myStack.push("C")print(myStack.get_stack())myStack.pop()print(myStack.get_stack())

We make a method called get_stack(). This will return the items list, which forms the core of the stack. Then I define a stack object, myStack, on line 17 and push A and B onto the stack, lines 18-19. After these operations, I can print myStack and the output is ['A', 'B']. A is at the bottom of the stack, and B is on the top. Then we push C on line 21 and the output is ['A', 'B', 'C'], which implies C is the top.

We understand the core fundamentals of the stack. A few of the other methods we can include in this are helpful, namely, we could have a method called is_empty. It will return whether or not the stack is empty.

"""Stack Data Structure."""class Stack():    def __init__(self):        self.items = []    def push(self, item):        self.items.append(item)				    def pop(self):        return self.items.pop()        def is_empty(self):        return self.items == []            def get_stack(self):        return self.itemsmyStack = Stack()print(myStack.is_empty())

We get True here because there’s nothing on the stack at this point. If we push something and call is_empty(), we should get False. You can try it out yourself.

"""Stack Data Structure."""class Stack():    def __init__(self):        self.items = []    def push(self, item):        self.items.append(item)				    def pop(self):        return self.items.pop()        def is_empty(self):        return self.items == []        def peek(self):        if not self.is_empty():            return self.items[-1]            def get_stack(self):        return self.itemsmyStack = Stack()myStack.push("A")myStack.push("B")myStack.push("C")myStack.push("D")print(myStack.peek())

Now we have the peek operation on line 17 which tells us the topmost element of the stack.

If peek is called on the stack in the above code, it should return D. peek checks if the stack is not empty on line 18 and if it isn’t, it returns the last element of the list, which in this case, is the top element of the stack. We return self.items[-1] on line 19 which is the last item in the list for Python. Hence, at first, we get D as the element that Python thinks is on the top of the stack.

Note that you can also check whether the stack is empty or not in the methods implemented previously. However, to keep things simple, this step has been omitted from the other methods.

Go ahead and create a stack object. You don’t have to limit yourself to letters or strings or anything like that, you could also push numbers. Just play around with this data structure and get a sense of how it works. I’ll see you in the next lesson.