1 6 Merge Sort Pseudocode 13 min

Okay, so let’s move on, and actually
discuss the pseudo-code for the merge sort algorithm. First, let me just
tell you the pseudo-code, leaving aside exactly how the merging subroutine is
implemented. And thus, high levels should be very simple and clear at this point. So
there’s gonna be two recursive calls, and then there’s gonna be a merging step. Now,
I owe you a few comments, ’cause I’m being a little sloppy. Again, as I promised,
this isn’t something you would directly translate into code, although it’s pretty
close. But so what are the couple of the ways that I’m being sloppy? Well, first of
all, there’s, [inaudible], you know, in any recursive algorithm, you gotta have
some base cases. You gotta have this idea that when the input’s sufficient. Really
small you don’t do any recursion, you just return some trivial answer. So in the
sorting problem the base case would be if your handed an array that has either zero
or an elements, well it’s already sorted, there’s nothing to do, so you just return
it without any recursion. Okay, so to be clear, I haven’t written down the base cases.
Although of course you would if you were actually implementing, a merge short. Some
of you, make a note of that. A couple of other things I’m ignoring. I’m ignoring
what the, what to do if the array has odd lengths, so if it has say nine elements,
obviously you have to somehow break that into five and four or four and five, so
you would do that just in either way and that would fine. And then secondly, I’m
ignoring the details or what it really means to sort of recursively sort, so for
example, I’m not discussing exactly how you would pass these subarrays onto the
recursive calls. That’s something that would really depend somewhat on what, on
the programming language, so that’s exactly what I want to avoid. I really
want to talk about the concepts which transcend any particular programming
language implementation. So that’s why I’m going to describe algorithms at this level
okay. Alright, so the hard part relatively speaking, that is. How do you implement
the merge depth? The recursive calls have done their work. We have these two sort of
separated half the numbers. The left half and the right half. How do we combine them
into one? And in English, I already told you on the last slide. The idea is you
just populate the output array in a sorted order, by traversing pointers or just
traversing through the two, sorted sub-arrays in parallel. So let’s look at
that in some more detail. Okay, so here is the pseudo-code for the merge step.
[sound] So let me begin by, introducing some names for the, characters in the,
what we’re about to discuss. So let’s use C. To denote the output array. So this is
what we’re suppose to spit out with the numbers in sorted order. And then, I’m
gonna use a and b to denote the results of the two recursive calls, okay? So, the
first recursive call has given us array a, which contains the left half of the input
array in sorted order. Similarly, b contains the right half of the input
array, again, in sorted order. So, as I said, we’re gonna need to traverse the
two, sorted sub-arrays, a and b, in parallel. So, I’m gonna introduce a
counter, i, to traverse through a, j to traverse through b. I and j will both be
initialized to one, to be at the beginning of their respective arrays. And now we’re
gonna do. We’re going to do a single pass of the output array copying it in an
increasing order. Always taking the smallest from the union of the two sorted
sub arrays. And if you, if there’s one idea in this merge step it’s just the
realization that. The minimum element that you haven’t yet looked at in A and B has
to be at the front of one or the two lists right so for example at the very beginning
of the algorithm where is the minimum element over all. Well, which ever of the
two arrays it lands in — A or B — it has to be the smallest one there okay. So the
smallest element over all is either the smallest element A or it’s the smallest
element B. So you just check both places, the smaller one is the smallest you copy
it over and you repeat. That’s it. So the purpose of K is just to traverse the
output array from left to right. That’s the order we’re gonna populate it.
Currently looking at position I, and the first array of position J and the second
array. So that’s how far we’ve gotten, how deeply we’ve probed in the both of those
two arrays. We look at which one has the current smallest, and we copy the smallest
one over. Okay? So if the, if, the entry in the i position of A is smaller, we
copy that one over. Of course, we have to increment i. We probe one deeper into the
list A, and symmeterically for the case where the current position in B has the
smaller element. Now again, I’m being a little bit sloppy, so that we can focus on
the forest, and not sort of, And not get bogged down with the trees. I’m ignoring
some end cases, so if you really wanted to implement this, you’d have to add a little
bit, to keep track of when you fall off, either, either A or B. Because you have
additional checks for when i or j reaches the end of the array, at which point you
copy over all the remaining elements into C. Alright, so I’m gonna give you a
cleaned up version, of, that pseudo-code so that you don’t have to tolerate my
questionable handwriting any longer than is absolutely necessary. This again, is
just the same thing that we wrote on the last slide, okay? The pseudo-code for the
merge step. Now, so that’s the Merge Sort algorithm. Now let’s get to the meaty part
of this lecture, which is, okay, so merge sort produces a sorted array. What makes
it, if anything, better than much simpler non divide and conquer algorithms, like
say, insertion sort? Other words, what is the running time of the merge sort
algorithm? Now I’m not gonna give you a completely precise definition, definition
of what I mean by running time and there’s good reason for that, as we’ll discuss
shortly. But intuitively, you should think of the running time of an algorithm, you
should imagine that you’re just running the algorithm in a debugger. Then, every
time you press enter, you advance with one line of the program through the debugger.
And then basically, the running time is just a number of operations executed, the
number of lines of code executed. So the question is, how many times you have to
hit enter on the debugger before the, program finally terminates. So we’re
interested in how many such, lines of code get executed for Merge Short when
an input array has n numbers. Okay, so that’s a fairly complicated question. So
let’s start with a more modest school. Rather than thinking about the number of
operations executed by Merge Sort, which is this crazy recursive algorithm, which
is calling itself over and over and over again. Let’s just think about how many
operations are gonna get executed when we do a single merge of two sorted sub
arrays. That seems like it should be an easier place to start. So let me remind
you, the pseudo code of the merge subroutine, here it is. So let’s just go
and count up how many operations that are gonna get used. So there’s
the initialization step. So let’s say that I’m gonna charge us one operation for each
of these two initializations. So let’s call this two operations, just set i equal to one
and j equal to one then we have this four loop executes a total number of end times
so each of these in iterations of this four loop how many instructions get
executed, well we have one here we have a comparison so we compare A(i) to B(j) and
either way the comparison comes up we then do two more operations, we do an
assignment. Here or here. And then we do an increment of the relevent variable
either here or here. So that’s gonna be three operations per iteration. And then
maybe I’ll also say that in order to increment K we’re gonna call it a fourth
iteration. Okay? So for each of these N iterations of the four loop we’re gonna do
four operations. All right? So putting it all together, what do we have is the
running time for merge. So let’s see the upshot. So the upshot is that the running
time of the merge subroutine, given an array of M numbers, is at most four M plus
two. So a couple of comments. First of all, I’ve changed a letter on you so don’t
get confused. In the previous slide we were thinking about an input size of N.
Here I’ve just made it. See I’ve changed the name of the variable to M. That’s
gonna be convenient once we think about merge sort, which is recursing on smaller
sub-problems. But it’s exactly the same thing and, and whatever. So an array of M
entries does as most four M plus two. Lines of code. The second thing is,
there’s some ambiguity in exactly how we counted lines of code on the previous
slide. So maybe you might argue that, you know, really, each loop iteration should
count as two operations, not just one.’Cause you don’t just have to
increment K, but you also have to compare it to the, upper bound of N. Eh, maybe.
Would have been 5M+2 instead of 4M+2. So it turns out these small differences in
how you count up. The number of lines of code executed are not gonna matter, and
we’ll see why shortly. So, amongst friends, let’s just agree, let’s call it
4M plus two operations from merge, to execute on array on exactly M entries. So,
let me abuse our friendship now a little bit further with an, an inequality which is
true, but extremely sloppy. But I promise it’ll make our lives just easier in some
future calculations. So rather than 4m+2, ’cause 2’s sorta getting on my nerves.
Let’s just call this. Utmost six N. Because m is at least one. [sound] Okay,
you have to admit it’s true, 6MO is at least 4M plus two. It’s very sloppy, these
numbers are not anything closer to each other for M large but, let’s just go ahead
and be sloppy in the interest of future simplicity. Okay. Now I don’t expect
anyone to be impressed with this rather crude upper bound, the number of lines of
code that the merge subroutine needs to finish, to execute. The key question you
recall was how many lines of code does merge sort require to correctly sort the
input array, not just this subroutine. And in fact, analyzing Merge Sort seems a lot
more intimidating, because if it keeps spawning off these recursive versions of
itself. So the number of recursive calls, the number of things we have to analyze,
is blowing up exponentially as we think about various levels of the recursion.
Now, if there’s one thing we have going for us, it’s that every time we make a
recursive call. It’s on a quite a bit smaller input then what we started with,
it’s on an array only half the size of the input array. So there’s some kind of
tension between on the one hand explosion of sub problems, a proliferation of sub
problems and the fact that successive subproblems only have to solve smaller and
smaller subproblems. And resolute resolving these two forces is what’s going
to drive our analysis of Merge Short. So, the good news is, is I’ll be able to show
you a complete analysis of exactly how many lines of code Merge Sort takes. And
I’ll be able to give you, and, in fact, a very precise upper bound. And so here’s
gonna be the claim that we’re gonna prove in the remainder of this lecture. So the
claim is that Merge Short never needs than more than six times N. Times the logarithm
of N log base two if you’re keeping track plus an extra six N operations to
correctly sort an input array of N numbers, okay so lets discuss for a second
is this good is this a win, knowing that this is an upper bound of the number of
lines of code the merger takes well yes it is and it shows the benefits of the divide
and conquer paradigm. Recall. In the simpler sorting methods that we briefly
discussed like insertion sort, selection sort, and bubble sort, I claimed that
their performance was governed by the quadratic function of the input size. That
is they need a constant times in the squared number of operations to sort an
input array of length N. Merge sort by contrast needs at most a constant times N
times log N, not N squared but N times log N lines of code to correctly sort an
input array. So to get a feel for what kind of win this is let me just remind you
for those of you who are rusty, or for whatever reason have lived in fear of a
logarithm, just exactly what the logarithm is. Okay? So. The way to think about the
logarithm is as follows. So you have the X axis, where you have N, which is going
from one up to infinity. And for comparison let’s think about just the
identity function, okay? So, the function which is just. F(n)=n. Okay, and
let’s contrast this with a logarithm. So what is the logorithm? Well, for our
purposes, we can just think of a logorithm as follows, okay? So the log of n, log
base 2 of n is, you type the number N into your calculator, okay? Then you hit
divide by two. And then you keep repeating dividing by two and you count how many
times you divide by two until you get a number that drops below one okay. So if
you plug in 32 you got to divide five times by two to get down to one. Log base two of
32 is five. You put in 1024 you have to divide by two, ten times till you get down
to one. So log base two of 1024 is ten and so on, okay. So the point is you already
see this if a log of a 1000 roughly is something like ten then the logarithm is
much, much smaller than the input. So graphically, what the logarithm is going
to look like is it’s going to look like. A curve becomes very flat very quickly, as N
grows large, okay? So F(n) being log base 2 of n. And I encourage you to
do this, perhaps a little bit more precisely on the computer or a graphing
calculator, at home. But log is running much, much, much slower than
the identity function. And as a result, sorting algorithm which runs in time
proportional to n times log n is much, much faster, especially as n grows large, than a sorting algorithm with a running time that’s a constant times n

4 thoughts on “1 6 Merge Sort Pseudocode 13 min

  1. sir what programming languages would be best to implement data structures and algorithms..please suggest me sir,it would be very helpful for me..

  2. This is not the full Merge Sort algorithm, this is just the Merge Sorted part of it. Which is basically just merging two already sorted arrays.
    He could have introduced Big-O notation earlier and avoided all those gibberish with constants in the complexity analysis.

Leave a Reply

Your email address will not be published. Required fields are marked *