 So today we will spend about half the time discussing midterms and what happened in January and then we will go on to the future part of the course. So we are discussing the course review last time and I went and listened to some of my lectures on the video and definitely my voice sounds quite bad when recorded or on the microphone. The only local fix I can think about is that I will really slow down and the second is you know if you help maintain more quietness in the room then even my bad voice will hopefully get across a little better. And I will monitor this for the next month we will have another survey especially on acoustics and speaking at the end of February if there is still some trouble I will probably go and see a speech therapist. So quiz questions there were three questions in the quiz if you do not get the first one at all that is my fault if you do not get the second one that is your fault and if you do not get the third one it is undecided we do not know whose fault it is. If you get at least half the paper right you are doing ok it is in the sense that you do not worry about grades if you solved at least one and half questions reasonably well. If you solved all three then you are sort of done if you decide to not come to class well not that extreme but well there is still a lot of fun stuff to learn. So the first question tested a whole bunch of different things the first issue was how are these characters and integers and long long ints interacting together. So what we did from role of position is a character ok these characters like quote 0 through quote 9 they do not represent the integers 0 through 9 they actually represent some ASCII code which is an integer between 0 and 255 inclusive. When you do operations on them which look like arithmetic and that includes relational comparisons like if quote 0 is less than equal to role pause that is an arithmetic comparison implicitly the system will think about both sides of the comparison as integers and therefore quote 0 will be transformed to the ASCII code for the character 0 and role pause similarly will be transformed from a character inside the string role to another integer value and then those two integers will be compared fine. Remember that the main operation done inside the body of the loop is CH which is a long long int 64 bits equal to role pause minus 0 ok. So in case the character at position pause was quote 0 this will result in the integer 0 going to character. If the character was the quote 5 then this quantity will be quote 5 minus quote 0 which is the integer 5 ok. So in all cases if the input character is a digit between 0 and 9 inclusive that will be transformed to the corresponding integer between 0 and 9 inclusive and that will be stored in CH ok. Similarly in the second if clause we will be testing whether role pause is between A and Z and A is and then we will subtract A from it which means that the resulting raw value will be between 0 and 25. After taking this value between 0 and 25 we will divide by 16 and take the remainder which means that the resulting value will be between 0 and 15 ok which is 1 x digit. In both cases CH gets a value between 0 and 15 inclusive which is worth 1 x digit ok. Now I do not know how many people have role numbers with characters in them anyone with role numbers with characters in them. So you have a D if you are dual degree student and there are some other cases ok. So D will result in 3 ok A is 0 B is 1 C is 2 D is 3. Now the second issue we are testing is how is pause behaving. We are not picking characters from the role string one by one left to right ok. Somewhat reminiscent of the Josephus problem we are running over the role buffer using a pause which is step differently from Rx itself Rx clocks from 0 to role dot size Rx is only job is to count that it has taken all characters once. In fact that is itself not entirely trivial I took the stepper of 13 because for everyone's role number whether it has 10 digits or 11 digits 13 is co-prime to that length and therefore as you step through with a step size of 13 and you take modulus mod of role dot size you will actually exhaust each character exactly once but in some arbitrary order. So if your role number is 11 characters long then although Rx steps from 0 to 10 inclusive pause steps through 0 to 4 6 8 10 followed by 1 3 5 7 9 you can easily verify that ok. So the second issue being tested in the question is do you understand how pause is visiting elements of the role array in some arbitrary order. Now the third issue is how was num being updated in every iteration it was initialized to 0 and then as you read role pause step by step num was shifted left by 4 bits thus making space for 1x digit and because of the shift left those 4 positions were filled with 0 bits and then this num was exored with CH. Now CH as we have already seen is a small number between 0 and 15. So it is higher order bits apart from the low 4 bits everything was 0 to start with ok and this was exored with the other element. So exoding with 0 gives you the original value back right. So in either way this is equivalent to replacing the 4 least significant 0 bits with the 4 bits of CH ok. So if the current role pause is D then CH becomes 3. So the bits 0 0 1 1 will be shifted in into the right most position. So if your picture helps this is my big 64 bit number ok and this is a hex digit that is a hex that is 1 byte ok and remember I have 8 bytes in a 64 bit number. So here is the first byte here is the second byte here is the third byte 4 5 6 7 8 ok. So that is the num ok. So in case you have 4 then this is just 4 and then those are all 0s. So this 4 means 0 1 0 0 and if that is 0 then this is all 0s 4 0s. So what happens is when you supply the new so this is num and here is CH. CH is also a long long integer but its worthwhile content is only in the last hex digit and everything else is 0s. This is all 0s. You read one character you transform it to an integer and you take modulus of 16. So the last hex digit is between 0 and 15 and that is the only content everything else will be 0s. So I mentioned that in a class and it was also in the slide in C++ if you say int or long that is 32 bits. If you say long long int speak of unimaginative names that is 64 bits. Now I realize that I did not emphasize this very carefully in class. There is a discrepancy with Java. In Java when you say int that means 32. You say long that means 64. It is possible that some people got confused because of that and even I was confused initially. So if we see a systematic problem because you misinterpreted it to be 32 bits instead of 64 bits we will take that into account. But in C++ you have to say this long long declaration a long declaration to make it long. So when you get this last digits what the program says is that you shift by 4 position which means this hex digit comes here and this hex digit is moved out and then that input hex digit enters the least significant position. That is what the XOR does really. Shift and XOR that is what it amounts to. So in fact the question was designed that you do not have to do too much bit arithmetic in your head or on paper. You see a number between 0 and 15 that same number goes into the last X position everything else gets shifted left. So printing it out in X should in fact be quite simple if you understood what the code was doing. Yes. In C also in turn long are supposed to be the same but there are differences in compilers. Historically C and C++ become a mess around the middle of the 90s. Different companies are building different compilers with different standards and conventions and that is really why Java took off because Java promise to exact same semantics on a particular virtual machine, Java virtual machine on all architectures. This is why it came about. And that is why I was confused because I have coded on machines where long end is 64. You do not have to say long long end. Any questions so far? So the summary is that there are three parts we are testing in this question roughly corresponding to the three columns in the table and accordingly we will look at grading. So here is the table and in the solution key that we are going to publish soon and explain what we are doing along with the sample. But of course the exact answer depends on your specific role number and you will be graded accordingly. The code I will also post to give you an example of the code running. So this is the same exact code as specified. So I am printing in decimal rx and pos and ch and then in hex the number. That is how you change the radix while you are printing using cout. So I will give an example of this. So I will not give a standard role number. We will just play with different things to see what happens. So suppose I entered the role number which is just say a, b, c, d, f, g, h, i, j. So j is 10. So I entered just j. j is the 10th letter. So it is 9. So you just get a 9. So the 0th position is red. So rx is 0, pos is also 0. It is 0 percent third whatever length is. And then I get a j from there which turns into 9 and then num is also 9 after the shift. Now suppose I entered j, j. So the nice part about this problem is every character you enter becomes one hex digit in the output. So you can just think of it character by character. You will just get 99 because it just shifted and then another 9 goes in there. If I enter jk that will be any guesses? 9a right the next one 10. It is just the next hex thing. So similarly if I say jl it will be 9b. If I keep repeating and otherwise if I say for example say j2l what will happen? It will just be 9 to b. Depend on the order though and the length is increasing now and at some point this stepping by 13 might kick in. But so far not. So j2, 9 to b. Now of course if you enter something long then the stepping by 13 and division will kick in. So if I say 1, 2, 3, 4, 5, 6, 7, 8, 9 what do I get? I get it in some strange order depending on how 13 modulo is stepping through the roll number. That is the actual position being accessed. That is the character being accessed turned into a hex digit. You do not see that here because everything was entered between 0 and 9. If I enter instead a, b, c, d, e, f, g, h, i, j, k I will get this complicated thing. You are still accessing all the even places first and then all the odd places and if you work through it you will see that this is what you get. 2, 4, 6, 8, 10, 1, 3, 5, 7, 9. So 3 things to understand in the code. Stepping through the array, converting characters to integers and masking and shifting and xORing. So the next question was probably simpler than the first one. That is less tedious. So maintain a decimal number as you see more and more digits starting from the most significant digit. So you first see 3. So you think the number is 3. How do you do that? We already saw from question 1 the input digit is a character. It is not an integer. Therefore the integer you want is digit minus code 0. That is one element we will test. Then suppose you see a 1 then the number changes to 31 and that is easy to do. We just take the old number multiplied by 10 and then add digit minus 0 to it. So it is easier to read a number more significant digit onward. If I presented to you the number from the unit place onward it will be a little messier. This is much cleaner. One line code maintaining the number as we see digit after digit. Now for printing a number however it is the opposite. It is easier to print the unit digit first because it is simply num percent 10. And you can directly see out num percent 10 because that integer will be converted into a character inside the IOS stream library as 0 plus whatever you gave it. That is how you turn things into characters. Now to discard the units digit and brings the 10th digit into the unit place we all know how to do that. We simply divide by 10. So an integer division by 10 will discard the unit digit and bring the 10th digit in. So that is how you print a number from the right most digit to the left most digit. Now given these two parts one of the things we will of course test for is that you put them together for the third part. That was the sole point of the exercise. So if we have to reverse the number in digits part c just puts together parts a and b we extract a least significant digit first and pack into b as most significant digit first. So the code is really simple while the number a is greater than 0. I keep shifting b left by one digit and then put in the currently significant digit of a in that least significant position and then I divide a by 10. So question 3 you need a little bit of geometry knowledge but I assume that all of you have it. So to find a point internal to a convex polygon that is not empty that is it has zero area. If it has zero area there is no interior point. Otherwise you can just take the centroid of all the vertices and that is very simple code to write. What you do is you add up the x's you add up the y's maintain a count of what you have to divide it through that is already given to you as n then you divide it. That is the centroid of the polygon. Other solutions are possible. You can find some non-empty triangle or other subset of the polygon and take the centroid of that. Many other solutions are possible. Now the question as to is 0 0 inside or outside. For each edge you have to test whether 0 0 and x in y are on the same side or different sides of the edge. And we know how to do that which is you express the equation of a line as a x plus b y plus c equal to 0. Now you can find a sign distance to the line from any point and then you check if the signs are same or opposite. So that is requires a little thinking. Now we could have given away the exact solution about how to do that and tested you only on writing the code. But it seems like in real life you have to model such things starting from the physical description and then map it to the numbers. So this is a small test of that. And the area problem is probably even slightly easier because everyone understand that the area of a polygon can be decomposed. You can either decompose it based on x in y in and have like pieces of a pie star like or you can use any corner vertex like that. And then you can triangulate it by connecting it to the other vertices. In either case you should get about the same result. So this and many other schemes will get full credit if they are correct. And then there is one assumption which was expressed during the exam which is that assume that there is no vertical or horizontal edge that was partly for part 2 where you have to find the equation of the line. It may or may not have mattered. Assuming that makes life a little easier but it is not necessary in this particular case. So that was the midterm review and as I said we will not test exact syntax if the main idea is correct you will get most of the credit or all the credit. If there is a systematic problem like long, long end versus long end we will of course take care of that. One other comment people asked where you can practice solving problems like this and if you look at the main course page then on the right side panel there is a link to all earlier offerings and in many cases old exams are linked through. So there is enough problems to practice on if you are looking for them. So we get back to arrays and loops. And last time I discussed merging two sorted arrays but since a lot of the class was not present let me go through it again somewhat faster because we have the animation to help us. So suppose I have two arrays and by the way some people are still not comfortable with how arrays are declared or accessed. So the syntax looks deceptively sort of confusing. Both the declaration and access uses the box bracket notation you declare by defining the type of the array followed by the name of the array and then inside box bracket the capacity of the array. Whereas you access using the same name and some index where the index has to be between 0 and capacity minus 1. So coming back suppose you are given two arrays which are say double precision A with m elements B with n elements. Elements may repeat but these two arrays are individually sorted. The output is an array whose size is the sum of the input arrays m plus n and the goal is that C will contain all the elements of A and B including repetitions and C has to be also sorted. C should be in increasing order just like A and B are in order. So that is a merge of the two arrays. For example if A is 0, 2, 7, 8 and B is 2, 3, 5, 8, 9 then C has to be their merger. If that results in duplicates so be it it has to be sorted. So 0, 2, 2, 3, 5, 7, 8, 8, 9 that should be the sorted array. Now the merge approach is fairly simple. We have all done that like card shuffling and so on or even the TAs will have to take all your ansa scripts and check the roll numbers and merge them from arbitrarily collected piles. So it is the same as that. You maintain two indices AX on A and BX on B which are also called cursors and at any point AX points to 1 place BX points to 1 place look at those two values. Pick the smaller one send it to the output and then whatever value you have consumed you have to advance the cursor for that. So if comparing 0 and 2 I send out 0, I consume that 0 from the input A and therefore AX has to switch to the next position. Now I compare 2 and 2 and let us arbitrarily again the upper one wins then 2 is sent out and AX again advances to 7. Now I compare 2 and 7 and this time BX's contents win. So 2 is passed out and B advances to the next place. So this keeps on going and every step you compare the head of the 2 cues so to speak and then take the smaller guy and advance that. So 3 is copied out BX advances to 5, BX wins again, advances to 8. Now AX wins, advances to 8 and so on. Now this ends in a couple of ways. Suppose the 2 arrays are exactly the same length and they have strictly interleaving values. You might have them end up at about the same time but in any case what happens is one array gets over first and then the other array is left with something and no matter what that remainder is it is always larger numbers than anything you have passed out to the output so far. So now you have to just clean up the remaining non-empty stream to the output. So the code looks like this A and B are suitably initialized by some other code which we would not show. Initialize the 3 cursors A and B are AX and BX are what are called read cursors because we will use them to read A and B not write them whereas CX is called a write cursor because we will use it to poke values into C and advance CX. Now we put up this loop which is best written as a while loop in this case. While AX is less than M and BX is less than M which means while there are elements left to consider in A and B both. We look at the head elements A of AX and B of BX we compare them. If A wins namely it is smaller then we set C of CX to be equal to A of AX and we advance both the write cursor and the read cursor which we used which is AX. So we write C of CX plus plus is A of AX plus plus otherwise B wins even if there equals a B wins then we set C of CX equal to B of BX and advance those two cursors. At the end of this loop because of the loop condition here at least one of the arrays will be finished over. So we just put up two loops saying while there are remaining elements in AX just append those to C while there are remaining elements in BX append those to B. In reality exactly one of these loops may execute or none may execute. So that is the merge code. Now this suggests another way to do sorting. Suppose someone gave you an array whose length was a power of 2 just for convenience. So suppose I was given an unsorted array of length 8 elements. Instead of looking at that array as 8 unsorted elements I could conceptually break it up into 8 arrays each with one element. Now an array with one element is by definition sorted. So we start with 8 arrays having a length of 1 we call them segments of length 1 which are already sorted and then we take 2 of them at a time and then we merge them. This gives us merge sorted array segments of length 2 each. So you end up with 4 segments of 2 elements each which are individually sorted. Then we merge pairs of those. So we merge 2 element arrays with 2 element arrays to form 4 element sorted arrays. So we get 2 of those in positions 0 through 3 and positions 4 through 7. And then we do one final merge to have one big sorted array. So this is called merge sort for obvious reasons and the picture explains it perhaps a little better. So initially we start off with one array which we mentally break up into 8 pieces. So they are slightly gapped out and each yellow block is a one element sorted array. Now we take 2 and 2 of those and then we merge them into those segments. So now we have joined them together to represent the fact that each block is an increasing order within itself but across blocks it could be arbitrary. So we do that and then in the next step we put 2 of those together and we get 4 element arrays which are in sorted order. And finally we have a single block of 8 elements which we will ensure is sorted because you already know how to do merges of sorted runs. Now recall that earlier we said that RAM can be read at approximately the same speed no matter which location you are reading. But hard disk takes a lot longer to access because the head has to be moved to a particular cylinder or track and then the disk has to turn to transfer the bytes in or out. The nice part about merge sort is when your runs get long enough near the bottom of the run then your blocks that you access from memory or disk become very large. You access them strictly sequentially. Remember the code here right? So the code strictly advances AX and BX and CX. You never go back you don't jump around at random like pause. It's a very regulated access just forward in the three arrays. So this is very friendly to disk access because the head needs to be positioned only once and then you just scan forward from the head position in each case. So it's all very sequentially accessed and it's very efficient to run on hard disk. So mod sort is the sorting method of choice if you are sorting arrays which are too big to store in RAM and that actually stored on hard disk. We will see examples of that when we do IO input output later in the course. So let's analyze the time taken by mod sort. In one merge, if I am merging together AM with BN, clearly the time taken is about proportional to M plus N. For every item of output I send to C, I am doing a constant amount of work. I am comparing two numbers, I am copying one of them out and I am stepping forward to cursors. It's a constant amount of work. So the time taken to merge AM and BN is some constant times M plus N, some small constant times M plus N. And you can test this easily by timing the merge code that I will put out on the website. Now suppose the array to be sorted is S which has size 2 to the power P. We started out saying in merge sort let's assume that the input size is the power of 2. Now in the first step, we imagine that these are actually 2 to the power P, one element arrays. We paired them up and we merged them. So the number of merges is actually 2 to the power P minus 1 and the total time taken in each merge is about 2. So the total time is again 2 to the power P. So if you look at this picture in the very first step, merging these two takes two units of time, that takes two end of time and the total number of merges is 4. So I still take total of 8 time for the first step going down from here to there. In the second step to merge these two arrays, I take time proportional to 4, but there are only two of those. So I again take time 8. So every step the time doesn't change, it's just productive differently. In the second step 2 to the power P minus 2 merges of segments of size 2 to, that takes time 2 to the power P again. Now how many phases of merges will be there? Log of 2 to the power P which is P phases. So in summary we have P merge phases, each phase taking 2 to the power P time. So the total time taken is therefore P times 2 to the power P. Now if we write n as 2 to the power P which is the size of the input array to be sorted in the first place, then P times 2 to the power P can be written as n times log n which is optimal because you already argued that any sorting algorithm which is based on comparing 2 things cannot really sort all possible n factorial inputs with less than n log n comparisons. So to within a constant factor this algorithm is optimal. So we have seen now 2 sorting algorithms. One is selection sort which picks the smallest element and pulls it up to the left that takes order n squared time which is not optimal and we have seen merge sort which is n log n time and is optimal. Not only that, merge sort is very friendly to disk access. It makes sequential accesses over 3 arrays at a time or 3 array segments at a time. Now the index arithmetic involved and bookkeeping in doing merge sort is a little complicated. It's not too bad but we'll look at it at the end of today's lecture if we have time. Comparing 2 elements takes a constant time. If you are comparing 2 integers that takes constant time. If you are comparing 2 doubles that takes constant time. But if you are comparing 2 strings remember the code for comparing strings it has to run through every character. So primitive objects of constant size those can be compared in constant time. But if you are comparing 2 strings that will take time roughly proportional to the length of the string or at least where the first disagreeing character appears if you run through that. So we'll come back to index arithmetic for merge sort in a bit. Any questions about how merge sort works? So the base case is an array of one element which is by default sorted and then you keep merging upward from that. This basic technique of doubling or squaring is very fundamental to computer science all over the place. So we saw about fast exponentiation using the squaring method. Now we have seen this doubling method where every step the sorted runs double in size until they reach the whole length of the input array. Now suppose I have a sorted array how do I search it? Given an array like 49, 13, 16, 17, 22 suppose the query is find the position of this number called q or query which is 16 and in this case the answer is 3. 16 appears at position 3 0, 1, 2, 3. Now maybe by convention when you do a search like this you declare that if q is not found in the array your reply should be say minus 1 to designate that it was not found anywhere in the array. Return some illegal value which cannot be a legal index into the array. Why do we care about searching? Suppose we have an income tax department database where there are multiple arrays each array holding one aspect of your income tax record. The first array could be the PAN the personal account number and there are as many elements in this array as the number of people at least with PAN numbers and this is sorted so that we can access people fast by PAN number. There is a second array which is income again as long as the number of people. This is said to be gang to the first array if every index is for one person. Of course the second array will not be sorted unless PAN numbers are issued in increasing income order which is unlikely. So to find out the income of a person you read their PAN number. You access the index at which that person occupies the PAN number and the income in both arrays. So to draw a picture of ganged arrays here is the PAN array here is the income array and one person occupies the corresponding index of both arrays. So the PAN number is here and the income is there. If I have to access this by PAN number it makes sense to sort this in increasing order so that I can search it efficiently. So I find the index of a specific PAN and then I access the person's income at the same index. How do I do that? Linear search which is what you would have to do if the array was not sorted just check through all the elements of the array until it finds the element A of AX equal to Q. That is the test condition here. A of AX is equal to Q and in this case it outputs the index AX and breaks. If throughout the for loop this condition was never met then by definition at the end you will end up having AX is equal to AM. This is an useful test of normal termination of a loop. So see what is happening inside the for loop. All I am doing is checking if the element matches the query. If that was never satisfied then you end up the loop with AX equal to AM. This is a standard test to see if the break was ever taken or not. If the break was taken you will have AX strictly less than AM. If the break was never taken you will have AX equal to AM. Then you can output minus 1 or that the record was not found or something like that. Now of course many of you will realize that it is inefficient to search through the array if the array is already sorted and we can instead do binary search. The basic idea in binary search is that we will maintain a bracket a range of indices which may still possibly contain my query Q and outside that bracket I am convinced that Q could never appear. I will do that by initializing two indices low and high initially to 0 and to N minus 1 and then I will keep bisecting it. I will keep bisecting the segment with mid equal to low plus high divided by 2 and then I will compare the query with the middle element. If the query is equal to the middle element then I have already found what I wanted. If the query was less than the middle element then surely my answer if at all there has to be in the first half of that. If the query was greater than the middle element then my answer if there has to be in the second half of that. So I can change high and low suitably in the first case I should change my high from the original value of high to mid minus 1. In the second case I should change low to mid plus 1. So here is the picture I start with Q equal to 16 and the box shows the indices at the bottom and the values inside the boxes. Now I start with low and high set to 0 and 5. So the value of low is 0, the value of high is 5, low points to the array element value 4, high points to the array element value 22. So in the first step because low was 0 and high was 5, mid will be equal to 0 plus 5 divided by 2 which is 2 in integer arithmetic. So mid points there at 13. At this point if I compared a mid with Q I will find that Q is larger than 13 and therefore I can eliminate the lower half of that approximately and low now points to 2 plus 1 actually. And then I will find the mid position to be equal to 3 and then 16 will match that and then I will exit the loop. Now do we terminate when low is equal to high or otherwise so index arithmetic takes a little bit of care. In any case before the first halving of the array the bracket has all the n candidates in the array. After the first halving it approximately reduces to n over 2. After the second halving it reduces to n over 4. So again we have this doubling trick and the number of halvings required to either locate your query or to make sure that the query element is not there will be at most about log n. So if the array is sorted you can search it in log n time. If the array is not sorted then in the worst case you have to run through the whole array. That is why we want to keep array sorted. That is the rational of sorting things. You can search for things much faster. Now to implement we need a little care with index arithmetic because as we have already seen if low is equal to 2 and high is equal to 3 then low plus high divided by 2 is again low. So to make sure you do not miss some elements or fall into infinite loops you have to code a little bit carefully at the edges of your iteration. So this will work in all cases. Low equal to 0, high equal to n minus 1 initialize answer 2 equal to 1 minus 1. Answer is the index at which the element has to be found. Int mid and while low is less than equal to high. Int mid is their average with round off discarded. If q is less than m in then high is mid minus 1 if q is greater than m in low is mid plus 1. If it is equal then answer is equal to mid and break. Now what do you do if answer is minus 1 at the end of the loop? You could either report minus 1 saying that a element query was not found. It is also conventional to return the negative form of the index where the query should have been inserted. So in sometimes c c and c plus plus or java libraries not returning a minus 1 but returning minus of a number which when negated would give you the right place to insert the new element. And that is often useful if you now want to insert a new pan number into the array. So that is binary search. Any questions on this? On binary search? So the summary is I do not want to search the whole expands because I know it sorted. I would rather use a bracketing technique. I will initially have the bracket covered the whole array. In every step I will find the midpoint. I will see if my query should go to the right or left half. Accordingly I should shrink either the left or right part of the bracket. So let us spend some time coding this up to see how it works. So as you have seen you can also declare a static array which is not changed. So you can say int a not give a size because the size will be clear. Let us give that sorted array that we had in the example. That is also acceptable. The length is implicit. We know what the length is. But just for do something about it. So let us say a n is equal to 1, 2, 3, 4, 5, 6 elements. Now there is a way to avoid this magic. So I have to count by hand and say 6. If tomorrow a different programmer adds an element here and forgets to update the 6 there could be a problem. So we will see how that can be bypassed a little later. And suppose I say int query is equal to say 16. Now I will paste in that other code. But I will print a few things on the way so you can see what is going on. So I initialize it to a n minus 1. So at every stage I will first print out low and high. And then maybe I should also print out mid. So let us compute mid and then print out mid as well. And then I do the comparison and if I find it I break. And then finally I will print out ans. So the code is the same. Just doing a few print outs. Query is 16. So low is 0, high is 5. Remember the a n was 6. So I initialize to 5. Mid was 2. So some comparison happened. Next bracket became mid plus 1, 3 to 5. And in the next it was 3 and 5. So mid was 4. Mid 4 meaning 4 is here 0, 1, 2, 3, 4. That was too high. So now high became 4 minus 1, 3. So low and high were both 3. Mid became 3. The comparison worked out and I exited the loop. Now if I ask for something that is not there like 15 I end up with minus 1. But the last place I have checked was 3. It was bracketed between 3 and 3. There is no one else to go. Q was not equal to a of 3. So I exited with minus 1. But observe that 0, 1, 2, 3. 3 is here and if 15 had to be inserted it had to be inserted at 3. So you can instead report something like that. Would you report minus 3? That is not such a good design to report minus 3. Why is that? Because 0 would be an ambiguous situation. If you did not find the element, but it was supposed to be inserted in the beginning. Like suppose I said 2. 2 is not there. I run this and I get minus 1. But look, mid was 0. So it is not a good idea to report minus mid in that case. So in fact what Java does is to return mid minus mid minus 1. So in case of a legal match, you will always get 0 or positive values. In case of an illegal match, you will always get negative values. But you can from that negative value you can easily derive the correct point of insertion. So you understand the reason for this policy. You should not report minus mid because it might be 0 and then you will not know. So it is good to have a convention that not found is strictly negative, found is 0 or positive. But the negative value can be encoded to return the position where you have to insert. In case you have to insert a new person's fan number. One more comment about the mod sort. Suppose my specification was not to retain duplicates, but to squeeze out duplicates. You realize that as I am scanning those two cursors and sending output, I can always remember the previous value and if the next incoming value seems to be a duplicate I can always throw it away. So mod sort is also an excellent way to do what is called merge purge which is to remove duplicates from the incoming stream. So that is a binary search for you. The code will of course go on the site. The next problem we look at is very related which is median. Now suppose I am given a sorted array A with n elements. By definition depending on whether n is even or odd, the median is either at A of n over 2 or it is at A over n over 2 and A of n over 2 plus 1. If the array is of even size, there are two medians. If the array is of odd size, there is only one median. So finding a median is trivial if you can sort the array. Similarly you can find quantiles, percentiles, no big deal. You find sort the array. Suppose the array had a 100 elements, the 10th element, the 20th element, this would be the deciles of the array. What if the array is not sorted? The trivial approach is to behave like a mathematician, reduce it to a known problem by first sorting it. This will take n squared or n log n time. So for a long time in the early days of computer science, there was this open question whether I can find the median of an unsorted array without sorting it. It is a very, very intriguing problem. After sorting it is obvious. It will take you at least n log n time. Now it is not too difficult to see that finding a median element will take you at least n time because you have to inspect every element. If I did inspect the last element, I can always nically change the last element so that it becomes your median. So there is no avoiding reading every input. So n time is required. The big question was whether you can find median of an unsorted array in n time or do you need n log n time to sort it or is it something in between? So it turns out that a constant times n steps are enough to find a median. The constant is a little large, maybe 11 n or something like that. And the algorithm is not at all trivial. It is quite complicated. And the analysis is also fairly complicated to start with. But so I will not discuss it in class but I just wanted to tickle your curiosity saying okay, I do not really need to sort an array to find the median. How is that possible? Or any quantile in fact? I can find it without sorting in linear time but the algorithm is quite non-trivial. We will not discuss that. I will discuss a simpler problem which is suppose we are given two sorted arrays again a, m and b, n. Suppose their merge is c of m plus n and we have seen how to merge it. The goal is to find the median of c without allocating or calculating c at all. Can we do that? And we want to do this in far less time than m plus n. If I had m plus n time, I could merge it and then find the median trivially. Suppose I would not allow that time and I would not even allow allocating or calculating c. Can we find the median of the merger of a and b faster than merging it? Now suppose here is the array a with m elements and that is the median position of a. Similarly, here is b with n elements and that is the median position of b. Suppose we look at those two medians and compare them. Suppose the median of a was 20 and the median of b was 27. Because 27 is larger than 20, what do we know about the setup? We know that all these elements here is larger than all the elements there. That is the definition of the median of b. But you also know through transitivity that these large elements are bigger than 20 which is bigger than those smaller half of a. Therefore, by this one comparison, I have ruled out any of these large elements as being a possible median because there are already m plus 2 over plus n over 2 smaller elements than those. By a similar logic, you can rule out the smaller half of a as well. So, I pick two elements, I compare ones and I have immediately ruled out half and half of the two arrays. So, again how long do I have to do this? Something like log of m plus n ish time right. So, therefore, no large item can be a median, I can throw them out. And this eliminates about m plus n over 2 elements in one shot. Therefore, in log of m plus n time, I will again find the median, I will not have disturbed the arrays or tried to merge it at all. Any questions about this? So, I will not code this up, it is pretty easy to code it up. We will have it in a lab, practice lab. So, let us get back to this merge shot problem and the index arithmetic that is required in there. I need some board work, I will do it pretty much on the board. So, remember we started out with one array with eight elements and we imagine those are actually eight arrays with one elements each. To implement that illusion, we have to do some index arithmetic. So, assume that the array size was a power of 2. To keep things concrete, we will pick power equal to 3. So, eight elements to start with. Now, there will be three merge rounds. As we have seen in that picture, we will mark the rounds as Px. Px will be 0, 1, 2. So, power minus 1. Now, in the Pxth round or merge phase, what happens? So, remember initially Px is equal to 0. In the 0th phase, there are 2 to the power power minus Px sorted rounds. In the 0th phase, there will be 8 sorted rounds. So, in the specific current iteration, this will be 2 to the power 3 minus 0 or 8 sorted rounds each with 2 to the power Px elements. So, in the first iteration, that will be just 2 to the power 0 or 1 element each. Now, how do we count them off as indices? So, these things will be called runs. Initially, in the first step, each run has one element. In the second step, each run has two elements. In the third step, each run has four elements. In the last, finally, one run has eight elements. So, how do we index those? Rounds will be indexed by Rx is a run index. Now, in the Pxth merge phase, the number of runs is this. So, Rx in this phase will take values between 0 and 2 to the power power minus Px minus 1. Rx will take values in that range. In particular, when Px is equal to 0, Rx will take values between 0 to 7. There are 8 runs labeled run 0 through run 7. Rx will take values from 0 through 7. Now, in the original array, the Rxth run will start at original array index Rx into 2 to the power Px. So, let me write that down. So, each run, the Rxth run starts at Rx into 2 to the power Px ends at Rx plus 1 times 2 to the power Px. What do I mean by that? Let us plug in the values for the very first one. Suppose Rx is equal to 0, Px equal to 0, then run 0 in phase 0 starts at 0, 0 times 2 to the power 0. Run 0 in phase 0 ends at 1 times 2 to the power 0. Actually, I should write it there. 0 times 2 to the power 0 through 1 times 2 to the power 0. So, what do I mean by ends at 1? What I mean is including 0 and excluding 1. In C and C++ and Java, it is very convenient to index from the first element of 0 to a last element which is n minus 1. So, when I say this run ends at position 1, I exclude 1 and it is up to the previous one. How about the second run which is run number 1? Run number 1 starts at 1 times 2 to the power 0, ends at 2 times 2 to the power 0. So, the second run goes from 1 to excluding 2. The third run goes from 2 to excluding 3. So, every run has exactly one element and it is indexed like this. So, how many people are comfortable with the indexing so far? Original 8 elements logically broken up into 8 runs, each run having one element. Can you have a show of hands? How many people are ok with the indexing so far in the first phase when Px is equal to 1 to 0? Px is 0, Pao is 3. The number of runs is 8. The runs themselves are numbered 0 through 7 and the Rxth run goes from this to that. Now, let us wipe out the yellow stuff and then let us look at what happens when we go to the second phase. So, let us say Px is equal to 1. When Px is equal to 1, we actually have one run like this, we have another run like that. So, we have 4 runs. Why 4 runs? Because we are now in this stage Px is equal to 1, Pao minus Px is 2 and we have 4 runs each with 2 to the power 1 which is 2 elements, each with 2 elements. Now, runs are now counted between 0 to 3. There are now 4 runs, now the run count has decreased in the range 0 to 3 and now where do the runs begin and end? So, in Px equal to 1, if Rx is equal to 0, so this is Rx, I have 0 times 2 to the power 1 through 1 times 2 to the power 1 that is the first run. The first run goes from 0 to excluding 2. So, the first run is now 0 and 1, 2 is excluded. The second run when Rx is equal to 1 is 1 times 2 to the power 1 to 2 times 2 to the power 1. So, that goes from 2 to excluding 4. So, 2 and 3 is the next run. So, now by a leap of faith you see that because Px is increasing, the number of runs is reducing exponentially, each run size is increasing exponentially and overall the index arithmetic will work out. Now, what is the action? What does the loop structure look like? So, now with this design, we will say at the outermost loop we will say for Px equal to 0 through power minus 1 that is the upper loop, that is the very outer loop which controls the merge phase. Now, we will say that we need to merge a couple of runs. So, which runs do we need to merge? We will say for Rx equal to 0 through 2 to the power power minus Px minus 1, but this will count Rx's through each step. We do not want that, we want to take 2 at a time, we want to take 2 runs at a time. So, let me get back to the initial stage where I have 8 runs. I want to take runs 0 and 1 and merge them, I want to take runs 2 and 3 and merge them. So, instead I will write that. So, let us say for Rx equal to 0 Rx less than 2 to the power power minus Px minus 1 and the stepper for Rx will jump in 2's. So, I will say Rx plus equal to 2 instead of plus plus. So, what will happen is in the very first stage Rx will point here in the next iteration Rx will point there and inside the pseudocode will be merge runs numbered Rx and numbered Rx plus 1. It is logically the same as saying find the sum of every adjacent element pairs in a matrix, it is like that. So, suppose I told you to calculate an output matrix which has half the elements of an input array, where each element in the output was the sum of 2 things in the input, 2 adjacent things in the input. Then you would again step 2 at a time and add up a i with a i plus 1 and then you say i plus equal to 2. It is the same thing here, the run is going up in steps of 2 and I am looking at runs numbered Rx and Rx plus 1. So, this is the outer loop and then here I have to write the merge code. So, let us start coding this up, we will see if we can finish and see what happens. So, I will copy that over, I cannot have 3 elements, 6 elements. So, I will actually have say 29, we still have some time left guys 35 say, we cannot have it sorted otherwise what is the point. So, we will have 35 and we will have 4. I will just shuffle some items around randomly. So, it is not sorted anymore and I have n elements. So, now I will say for int px equal to 0, px less than what was px going up to 2 to the power to power. So, power was 3, power was 3. Now, I say px less than 3 or power plus plus px that is the merge phase, merge phase number. Now, I say for int Rx equal to 0, Rx less than what I want is 2 to the power power minus p, right px. So, what is 2 to the power 1 less than less than power minus px minus 1. I wanted to write for Rx equal to 0 to 2 to the power power minus px minus 1 minus 2 actually inclusive. So, I write that as this in steps of 2 Rx plus equal to 2 and here the code is merge runs Rx and Rx plus 1. Instead of actually trying the sort let me print out what is happening. So, I will print out Rx here px here. So, I will say merge phase px and here I will say see out merge runs Rx and Rx plus 1. Now, let us see what the translate to in terms of indices in the array. We already said that the indices look like this. So, say const int l run the left run l run begin and l run end. Similarly, we will have const int right run begin and right run end. Now, what is l run begin? We already saw that left run begin is Rx times 2 to the power px. So, this is Rx times 2 to the power px is the same as 1 shifted left px and this is equal to Rx plus 1 times 2 to the power px whereas, the right guys remember that is just Rx plus 1 the next run into that is the same as l run end because one is excluded the other is included and R run end is just Rx plus 2 times 2 to the power px. Now, I will print out see out merge elements starting at l run begin comma l run end excluded with elements merge elements with elements again R run begin to R run end. So, see what I am doing I am basically printing out the element ranges to be merged. So, I merge l run begin to l run end with elements R run begin to R run end. I am just printing out the indices I am not doing anything on the array itself. I had 8 positions power 3 phases go from 0 to 2 inclusive inside each phase I mark the runs and then I try to print it out. Let us see if it compiles and runs or this there above. So, I do not do anything to the array at all. So, it is a merge phase 0 merge runs 0 and 1 2 and 3 4 and 5 6 and 7 those are the 4 pairs of runs. So, merge element 0 1 with 1 2 1 is excluded. So, it is just 0 with 1 runs 2 and 3 is 2 3 with 3 4 4 5 with 5 6 6 7 with 7 8 in the merge phase 1 hang on guys if I change my voice everyone will just suffer. So, in phase 1 I have how many runs runs 0 and 1 2 and 3 runs 0 goes from elements 0 and 1 to 2 and 3 merging runs 2 and 3 means merging elements 4 6 with 6 8 which means actually 4 5 with 6 7 and in the final merge run merge phase 2 there are only 2 runs to merge 0 and 1 run 0 goes from elements 0 through 4 run 1 goes from elements 4 through 8. So, you see how the doubling takes place there are 4 runs being merged here 4 plus 4 there are 2 runs of 2 elements being merged here there is 1 run or 2 runs of length 4 being merged here to result in the sorted sequence. Now, let us actually run the sort and see. So, we will not just say we are doing it we will actually want to do it and how are you doing this we have to allocate a second array say which is the sorted array. So, same size now that is uninitialized to garbage we do not care how does the merge work we have we initialize int the 2 runs right. So, we have A x equal to L run begin B x equal to R run begin C x equal to L run begin again see when we merge this and that say we have these 2 runs with 2 elements each in the C array we want these 4 to come to the same place. So, C x will initialize there A x will initialize here B x will initialize there. So, C x will go to the same as L run begin. So, this is again L run begin we set up the beginning of the merge sort. Now, we say while A x less than what is the run size the run size is 2 to the power p x right. Now, while A x less than L run well we have L run end already. So, we will say while end and B x less than R run end. So, that is how the merge is going on what do we do we say if see there are not actually 2 arrays there is just a 1 array really and that array is called A. So, we say if A of A x is less than A of B x I do C of C x plus plus is equal to A of A x plus plus else if A of A x is greater than B of sorry A of B x then C of C x plus plus is equal to B of sorry A of B x plus plus actually this is fine sorry else we do that no no time you know time breaking can be arbitrary. The smaller or less than equal to element goes to the output and finally, you have to clean it out. So, while A x less than L run end we have that while B x less than R run end we have this you need to focus on the indices a fair bit to make sure there are no mistakes, but if you code like this you will not usually make a bad mistake. So, this is how we do the merge. So, let us see if there is a bug or is this ok right now at the end of each stage let me initialize C to some actual value. So, that we know that it is garbage a specific garbage value. So, I will say for int C x equal to 0 C x less than a n plus plus C x because there is no minus 1 in the input I will just say C of C x equal to minus 1 say ok. And at the end of every stage I will print out C ok this is the merge phase loop end of merge phase loop this is the end of the run loop. So, between that I am going to print out the C add to see where C is going. So, instead of reading writing C and of course, print out C of C x with a comma and then finally, I will print out a line ok. So, let me go through the circus in slow motion again first I put up the merge phase loop then inside I put in the run loop that is already explained on the board. Then all I did is inside the two inner loops I put in the merge code. The merge code puts up two cursors it just output the smaller one to the output ok. Now of course, given the condition under which I have done this coding there is very high chance of there being a bug, but let us check it out ok. I gave it an unsorted array let us see what happens. So, clearly nothing is this is not really working merge phase 0 well 935, 16, 22, 13, 17, 4, 29 that was correctly done ok. Look the original array was 35, 9, 22, 16, 17, 13, 29, 4. So, there all the all the two element sections were unsorted right, but at the end of the first phase at least it did the right thing 935 was correct 16, 22, 13, 17, 4, 29 was correct. Then it made some mistakes merge element 0, 2 with elements 2, 4 that was supposed to give me 9, 16, 22, 35. So, somehow that did not happen ok. So, the mistake was clearly in the second step how did that happen ok. So, I can post this code and you can investigate it to see where the bug is. Bug fixing is a important part of coding. So, try it out. So, I will stop there because the sound is getting a little getting impatient fine.