# IB Computer Science HL Topic 5 Stacks and Queues In the topic 5 of IB we have already covered [2 dimensional arrays](/W401zMAJToK7PBiLN1QKnw) and Recursion. We have left to cover other abstract data structures like stacks, queues, linked lists and Binary trees. These Abstract Data Structures (ADS) are ways to store data. We have already in SL covered collections and 1 dimensional arrays. **Why does this matter?** This matters because we want to acces the data or modify as fast as possible. In order to understand this we need to review what is [Big O Notation](/ePOy45OFT0yOOnIMyxtaTw) that we have already covered. :::warning Remember collections that we have these methods 1) `AddItem()` that adds an item to the collection 2) `hasNext()` that returns true if we can still loop through the collection checking where is the cursor of the collection. 3) `getNext()` that returns the next element and moves the cursor (doesn't delet anything) 4) `resetNext()` that resets the cursor. ::: ## Recomended summary video https://www.youtube.com/watch?v=wjI1WNcIntg {%youtube wjI1WNcIntg%} ## Stacks Stacks are sets of elements with a particular order that allow access only to the last item inserted. They are a linear data structure (elements go one after the other) flexible data structure (we can shrink or increase its size). :::success A stack is a Last-In First-Out (LIFO) data structure ::: They are a linear data structure (elements go one after the other) flexible data structure (we can shrink or increase its size). In IB (And in general) stacks have 3 main methods (They may have different names in different implementations) 1) `push()` that inserts one element onto a stack 2) `pop()` that removes the last element entered on the stack and returns it 3) `isEmpty()` that tests if a stack is empty. Returns a boolean. True if it's empty and fals if it's not. Is used to loop through an stack. Other methods that are common in stacks - `peek()` will return the last element entered on the stack without removing it. ![imagen](https://hackmd.io/_uploads/HJ0VSOql0.png) _stack of plates_ ### When to use a stack Mainly when we know that the most visited element is going to be the last inserted. For example, if we are in web browser or *any* editting tool, we may have a stack of the last steps that we have done. So when we undo them, we can access to them quickly. Also microprocessors (link to topic 2 and 6) usually have a stack for methods. Remember when we have a recursive method? Something like fibonacci(3) that calls fibonacci (2) that calls both fibonacci(1) and fibonacci(0). ``` fibonacci(n) if (n<2) then return 1 else return fibonacci(n-1)+fibonacci(n-2) end method ``` When this happens in memory we have a stack. In this case let's go step by step First, fibonacci(3) is going to be pushed to the stack when is called fibonacci (2). ![imagen](https://hackmd.io/_uploads/rJ6N3dqg0.png) Then fibonacci(2) is going to be pushed to the stack when is called fibonacci (1) called. ![imagen](https://hackmd.io/_uploads/SJ483_cxC.png) Then fibonacci(1) is called and it will return (1). At the time of returning Fibonacci(2) is going to be poped from the stack to add the 1 returned from fibonacci(1). Then fibonacci(2) is going to be pushed (again) back to the stack when is called fibonacci(0). Then fibonacci(0) is going to be called and it will return (1). Then fibonacci(2) is going to be poped (again) from the stack to add 1 that was returned from fibonacci(0). Then fibonacci(2) is going to finish and return 2. Then fibonacci(3) is going to be poped from the stack to add the 2 value from fibonacci(2). Then fibonacci(3) is going to be pushed (again) back to the stack when is called fibonacci(1). Then fibonacci(1) is called and it will return (1). Then fibonacci(3) is going to be poped (again) from the stack to add 1 that was returned from fibonacci(1). Finally fibonacci(3) will return 2+1. #### Exercise Create the stack process of fibonacci(6) using the array implementation of a stack in this web. https://www.cs.usfca.edu/~galles/visualization/StackArray.html ### Stacks in execution threads ![Captura-de-pantalla-2015-08-19-11.48.19-845x397](https://hackmd.io/_uploads/HkpHG59xR.png) ## Algorithms using stacks To look for an element into a stack we're going to use a while loop and a flag variable. In this case we're going to do it in a way that is **destructive**, the stack is not going to be the same after the search. ``` S //stack FOUND = false loop while (S.isEmpty() == false AND FOUND == false) element = S.pop() if (element == condition) then FOUND = true //do whatever, return, output etc end if end loop ``` What we can do for putting everything back together is to use a **stack** for storing the elements that we are poping. Once the search has ended we push the elements back in their place. ``` S //stack FOUND = false S2 // new empty stack loop while (S.isEmpty() == false AND FOUND == false) element = S.pop() S2.push(element) if (element == condition) then FOUND = true //do whatever, return, output etc end if end loop loop while NOT S2.isEmpty() S.push(S2.pop()) end loop ``` ### Simple exercise with stacks (Outputs) Let's create a stack and say the output of these exercise with vegetables ![imagen](https://hackmd.io/_uploads/BJwCkhX-A.png) _pak choi_ ```! S // stack S.push("potato") S.push("lettuce") S.push("pak choi") S.push("tomato") S.pop() S.push("carrot") output(S.pop()) C= S.pop() output(S.pop()) S.push(C) S.push(C) output(S.pop()) ``` What would be the output of this algorithm? Solution on the spoiler :::spoiler carrot, lettuce, pak choi ::: What would be the contents of the stack by the end of this algorithm? The last element would be another copy of "pak choi" and the first element would be the potato. ### Simple exercise with stacks (find info) Imagine that we have a stack with information about vegetables called VEGGIES. We need to find how many vegetables in that stack are "carrot" (and output them) First way to do it is _destructive_ since we're going to mess with the stack. :::info **What do we mean by _destructive_** In stacks and queues, unlike arrays, looping trough them is going to actually change them and even delete them completely if we're not careful. That's why we may have _destructive_ algorithms that we're going to use when we don't care about how is the stack or queue after the execution and _non destructive_ algorithms that are going to set the elements as they were before their execution of the algorithm. ::: For that we need a **COUNT** ``` VEGGIES // stack COUNT = 0 loop while not VEGGIES.isEmpty() element = VEGGIES.pop() if element == "carrot" then COUNT = COUNT + 1 end if end loop output COUNT ``` We _could_ get more _one liners_ with this implementation: ``` VEGGIES // stack COUNT = 0 loop while not VEGGIES.isEmpty() if VEGGIES.pop()== "carrot" then COUNT = COUNT + 1 end if end loop output COUNT ``` But sometimes in other (more complex) programs we actually need to do more than 1 thing to the elements that we pop so for not messing it up I suggest to use the former version. What would be to do something else with that element? In case of being an object, check a couple of their properties. (Such as ID and age, for example). In other cases maybe we need to store 2 elements because we want to check how we add them together. Other cases are 2 conditions or more (a number bigger than some threshold but lower than other threshold) Now the non-destructive version: ``` VEGGIES // stack S // empty stack COUNT = 0 loop while not VEGGIES.isEmpty() element = VEGGIES.pop() S.push(element) if element == "carrot" then COUNT = COUNT + 1 end if end loop loop while not S.isEmpty() VEGGIES.push(S.pop()) end loop output COUNT ``` ### Simple exercise of searching a stack with 2 conditions. Imagine that we have a stack with the latests grades of IB. We need to count how many of them are between 24 and 30 marks. The stack is called IBGrades. The destructive version: ``` IBGrades // stack COUNT = 0 loop while not IBGrades.isEmpty() GRADE = IBGrades.pop() if GRADE > 23 AND GRADE < 31 then COUNT = COUNT + 1 end if end loop output COUNT ``` :::danger This is wrong! ``` IBGrades // stack COUNT = 0 loop while not IBGrades.isEmpty() if IBGrades.pop() > 23 AND IBGrades.pop() < 31 then COUNT = COUNT + 1 end if end loop output COUNT ``` Because you're comparing 2 different grades since everytime that you call IBGrades.pop() you're changing the element that you're working with! ::: The non-destructive version of the algorithm: ![image](https://hackmd.io/_uploads/Hkg6wR2WC.png) _credit Y.C._ ### Count how many elements (in total) we have in an stack We want to know how many elements we have in a certain stack at a certain moment (without destroing it). ``` S //stack COUNT (counter) S2 //temporary stack loop while (S.isEmpty() == false) S2.push(S.pop()) COUNT = COUNT +1 end loop loop while (S2.isEmpty()== false) S.push(S2.pop()) end loop ouput COUNT ``` ## Queues Queues are sets of elements with a particular order that allow access only to the first item inserted. They are a linear data structure (elements go one after the other) flexible data structure (we can shrink or increase its size). :::success A stack is a First-In First-Out (FIFO) data structure ::: In IB (And in general) stacks have 3 main methods (They may have different names in different implementations) 1) `enqueue()` that inserts one element into the end of the queue 2) `dequeue()` that removes the first element entered on the stack and returns it 3) `isEmpty()` that tests if a queue is empty. Returns a boolean. True if it's empty and fals if it's not. Is used to loop through an queue. ### Applications of queues * Simulation of real queues (duh) * Response queues. When you ask something to a server, it usually will put it into a queue. The first query that it gets is usually the first response that it will create. * Sending data packets (topic 3 link) * Printer queues ## Algorithms using queues To look for an element into a queue we're going to use a while loop and a flag variable. In this case we're going to do it in a way that is **destructive**, the queue is not going to be the same after the search. ``` Q //queue FOUND = false loop while (Q.isEmpty() == false AND FOUND == false) element = Q.dequeue() if (element == condition) then FOUND = true //do whatever, return, output etc end if end loop ``` :::info Can we write directly `if Q.dequeue()== condition`? Yes, but the problem is that in some other context you may have to do more than one thing (or one condition) so if you call Q.dequeue twice you're getting 2 different elements (is the same problem with getNext() in collections) so to avoid it I tend to put the element that I'm going to compare in a variable. ::: ## Implenting a queue or a stack using an array Remember that _implementation_ means that how to find *a* solution. There can be many. To implement a stack we can use several ways. For example in the video from before: {%youtube wjI1WNcIntg%} You can see an implementation of a stack and a queue using OOP in java. Now since you know how arrays work let's see how we can implement (in pseudocode) a stack o a queue. ### Implement a stack using an array Remember that in an array in many algorithms that you see in IB we're keeping track of how filled is a fixed length array using a varible of "counter" or "index" or "POTATO_COUNT". So for doing this trick we are going to use an array and implement the methods that we have using variables for those indexes. In the case of Stacks the relevant is `TOP` ```! ARRAY[N] //array of fixed N elements TOP = 0 //we asume that we start that the top is first 0 in this implementation. We can go also that if the stack is empty, TOP = -1. In this case TOP counts how many elements we have in our stack ``` The methods that we need to implement to make it work are: push(data), pop() and isEmpty() #### isEmpty() ```! method isEmpty() if TOP > 0 then return false else return true end if end method ``` #### push(data) In this case we're supposing that we have enough space in our array ```! method push(data) ARRAY[TOP] = data TOP = TOP + 1 end method ``` #### pop() In this case we're supposing that we have elements in our stack ```! method pop() TOP = TOP -1 return ARRAY[TOP] end method ``` ### Implement a queue using an array ([Resource](https://www.geeksforgeeks.org/array-implementation-of-queue-simple/)) In this case we need 2 variables. `HEAD` (head of the queue, the element that is going to be first out) and `TAIL`, the last element that we have enqueued. In this case there are more nuances, _so fasten your seatbelts_ ```! ARRAY[N] //array of fixed N elements HEAD = 0 // the index where is going to be the first element to take out. TAIL = 0 //the index where we're going to put the next element ``` ### isEmpty() This is the easiest one ```! method isEmpty() if TAIL == HEAD then return true else return false end if end method ``` #### enqueue(data) ``` method enqueue(data) ARRAY[TAIL] = DATA TAIL = TAIL +1 end method ``` #### dequeue ``` method dequeue ANSWER = ARRAY[HEAD] HEAD = HEAD + 1 return ANSWER end method ``` ## Exercises with queues and stacks ### How to reverse a stack with a queue algorithm :::success I have seen this question in one of the exams as "description" ::: For doing this we need to loop through the stack and put everything into a queue. Then dequeue and fill the stack again. For example ``` S //Stack to reverse Q //Auxiliary empty queue loop while S.isEmpty() == false Q.enqueue(S.pop()) end loop loop while Q.isEmpty() == false S.push(Q.dequeue()) end loop ``` :::info Remember that when we write `S.push(Q.dequeue())` we are pushing to the stack S what we retrieve from dequeueing in the queue Q ::: ### How to reverse a queue with a stack [ Exercise for the students, do the description AND the pseudocode ] Description: >In order to reverse the queue, we first create an empty stack S. Then, we start a loop while the queue Q is not empty, where the elements will be pushed into the stack S while they are dequeued from the queue Q. Finally, we create another loop while the stack S is not empty, and we enqueue the elements from queue Q, meaning that they are popped from stack S. Since they are popped from a stack, their order will change as the last one will become the first one. As a result, the queue will be reversed. _credit Y.C._ Pseudocode ![image](https://hackmd.io/_uploads/HJ0cd1T-C.png) _credit Y.C_ :::info Remember that when we write `Q.enqueue(S.pop())` we are enqueuing in the queue Q what we retrieve from popping the Stack S ::: ### References Implementation of stacks in Java https://www.geeksforgeeks.org/stack-class-in-java/ Array implementation of a stack https://www.cs.usfca.edu/~galles/visualization/StackArray.html