 Hello and welcome to this session in which we look at another data type called Q which also has its value as sequences, but it differs from say a stack in terms of the operations that can be performed on it. So, what is a Q? So, as I said it is another data type whose value is a sequence only, but the operations that you can perform are different. So, Q you are familiar with from ordinary usage, they are used whenever resources have to be shared. So, when you want to enter a bus you have to form a Q because many people want to use the bus. Similarly, when you want to print a file the printer uses a Q to store all the files that need to be printed. So, this is also what is called a first and first out structure or a FIFO structure where an element which enters the Q first will come out of the Q earlier. Whereas, the stack is the last in first out structure the element that entered the stack last will be the first one to come out of the stack. So, in a Q elements are popped in the order they are pushed in the Q. So, let us define Qs formally. So, what are the allowed operations? They are very similar to those for a stack except for the insert operation. So, there is a empty operation again which tests whether a Q is true whether a Q is empty or not. So, it is true only for phi and for a Q obtained by pushing an element in any list it is also false. The insert operation is defined differently in the case of a Q compared to the push operation in a stack. If you insert in an empty Q you get a Q which contains just that element which is obtained by pushing that element X in an empty sequence. If you insert an element X in a Q which already has an element Y pushed into some sequences then you insert X in the sequences and then push Y into that result. So, here essentially X gets inserted at the end of the Q when you are inserting in a Q whereas in a stack a push would have got inserted at the beginning of the stack itself. Pop operation is similar for a stack as well as a Q. Pop for an empty Q is undefined which means it will give an error if you try to execute it and pop of a Q whose value is push X comma S is the Q obtained by removing the element X. The front is again similar to the top operation of a stack front is undefined if the Q is empty and front of push X comma S is the element X which is at the beginning of the sequence. So, here only the insert operation is different from the stack but Q's have different properties because of this. So, let us look at a property of a Q. So, this says that if the Q is not empty then the front of the Q obtained by inserting an element X in the Q Q is equal to the original front of the Q. That is the element at the front of the Q does not change if you insert an element in a non-empty Q. Note that if the Q was empty then front of Q was not defined earlier whereas after you insert an element X in it it will be defined. So, this equation will not be valid if Q was empty because front Q is not defined in that case. So, inserting in a non-empty Q does not change its front element. So, we will try to prove this formally. This is not true for a stack for example, if you push an element in a stack the top of the stack changes. So, this is different from that for a stack whereas in a Q the front remains unchanged even after an insertion. So, we will prove in the base case now we consider is not the empty Q but the Q having one element whose value is obtained by pushing an element Y into the empty sequence. So, let us prove formally that the front of a Q remains unchanged if you insert an element in a non-empty Q. So, essentially we first consider a Q with single element which is push Y comma phi. If I insert X into such a Q by definition its value is obtained by pushing Y in the Q obtained by inserting X in phi and by definition of the front operation this value is equal to Y in both the cases. So, front of push Y comma insert X comma phi is defined by defined to be Y by the definition of front and front of push Y comma phi is also defined to be Y. So, both sides become Y and the equality holds for this. Now, consider a Q with two or more elements we can write such a Q as push Y comma push Z comma S where S is any sequence with zero or more element and now we insert X into such a Q by definition resulting Q can be written as obtained by pushing Y in the Q obtained by inserting X in push Z comma X. The front of this is always Y by definition and this is also equal to the front of the Q obtained by pushing Y in push Z comma S. So, again this equality holds for Q's of size greater than or equal to 2. Assume in this case actually we do not really need the induction hypothesis, but directly we can show that the front remains the same for both Q's, but you need to do it for the base case as well as for Q's of larger length. So, let us define some functions of Q's and we can use Q operations themselves to define these functions. So, one way is to look at possible values of a Q the standard way we have been using to define operations is to define for the empty Q and assuming it is defined for a Q X or Q S you define it for the Q push X comma S, but instead we can also define it using the already defined operations on a Q. So, now look at a function like size of Q. So, if Q is empty or empty Q is true then the size is 0 else we remove one element from the Q. So, look at size of pop Q and return the next element of that as the size of the Q. So, this just says that pop Q reduces the size of the Q by 1. So, here is another operation called shift which takes the element at the front of the Q and puts it at the back. So, if empty Q then it does not do anything to the Q the Q remains as it is its empty else we call insert front of Q into pop Q. So, this operation takes the front element removes it from the Q that gives you the Q pop Q and now it inserts the front element into the result of popping the front element from the Q which will put this element at the end of the Q. So, this you can think of it as a circular shift operation on the Q, but note that it is easy to define using the already defined operations on the Q. So, here is another way of reversing a Q using only these operations again if the Q is empty it is nothing else all that we need to do is remove the front element of the Q, reverse the remaining Q which is pop Q and now insert the front element in that Q and note that insert operation puts it at the end of the Q. So, this will essentially give you the reverse of the original Q. So, these are operations are well defined because pop Q has smaller size than Q and therefore, we are using induction here to be formally precise we should have done it in the earlier way define it when the Q is empty and define it for when the value of the Q is obtained by pushing an element into the Q into some smaller Q. In this case we are assuming it is defined for the Q pop Q and then we are defining it for Q. So, here are some exercises that you can try to do. So, again try to prove that reverse of reverse of Q is equal to Q for any Q. Now, consider this function f Q comma i that takes a Q Q and a number i as a parameter and it is defined as follows f Q comma 0 is Q for all Q Q. So, if i is 0 then it does not do anything to the Q f of Q comma next i is shift f of Q comma i and so prove that. So, what this we have defined the shift operation as removing the first element of the Q and putting it at the end of the Q. So, if we apply this operation size Q times we should get back the same Q as the original Q. So, try to prove the formulae that f of Q comma size Q is always equal to Q for all Q's Q and now what Q's will satisfy the property that if you shift this once you will get back the same Q that f of Q comma next 0 next 0 is essentially 1. So, if you apply this operation once when will you get back the same Q not all Q's will satisfy this property, but you can find out exactly which Q's have these properties. So, try these exercises and we will meet next time. Thank you.