 Hi folks, so in this video we're going to talk about a different type of sorting algorithm, which is called quicksort So quicksort as you may guess is fast It's better than n squared in most cases It would and it also works completely differently from everything we've looked at so far before we kind of looked at algorithms that Kind of picked an item in the list and then had to go through the list many many many times To figure out where everything went in this case quicksort Still picks an item and then has to go through the list a couple times But the way that it goes through the list is a little more clever and so you get better performance It was developed way back in 1959 by Sir Tony whore. He's actually still around today So in 1959 we were still dealing with punch cards in great big canisters and computers It is very fast. It is memory efficient And it is commonly implemented as a divide and conquer algorithm and implemented recursively, right? So this is a function or a sorting algorithm that is recursive, right? You can implement it iteratively, but recursively it's actually very very elegant very simple more or less Alright, so How does it work in a nutshell, okay? So if you imagine once again, we're sorting a list of something or other a list of numbers what you do is you pick One element called the pivot. Okay, and the idea with the pivot is that you need to Partition the rest of the data around the pivot so that you know We just pick out of our list and we don't care how big or small it is We pick one element to be the pivot It can be the first element the last element random doesn't really matter and then we're gonna say put into our list We're gonna set move everything around so that everything to the left of the pivot is less than this value And everything to the right of the pivot is greater than this value Okay, this is a process called partitioning and the net effect of this step the net effect of the partition step is that Whatever your pivot is is sorted. It's in its final position wherever that may be Okay Then what do we do we quick sort? This pile that's on the left and we quick sort this pile that's on the right. We do it recursively Okay, and that's it We just keep calling this recursively until we're down to we've sorted everything the list There's only one item in either side or no items and that's it. We're done And so it's a clever little algorithm Again here are the steps, you know, imagine you've got a list here. You're gonna pick a pivot value Say 65 and then you partition the remainder of the list So we've got 65 here and then conceptually we're gonna put everything less than 65 on one side everything to the right of 65 is gonna be bigger than it and then 65 is in the right spot now. We need to quick sort the left side and the right side and whenever we're all done Whenever we've quick sorted whenever because we're doing this recursively we hit our base case Hey, they're sorted and we come back, right? So the key to this is the partition step and we're gonna switch over to the handout and Kind of talk through how that partition step works Everyone so I'm over in the quick sort handout now and I'm actually on the back page Where we're gonna walk through an example of how this partitioning scheme works because it's the partition that does all of the work You partition the list and then you call partition again on the two Sides of the pivot that has already been sorted into its final place. So I've got a new ink Tool here, hopefully it'll work a little bit better than one note. I don't know how it could work any worse So how does this partition work? This is not exactly the pseudocode the code itself is maybe a little bit longer But I think this part is hopefully a little more understandable. Okay, so we have to have a few variables We need to have a pivot point now quick sort algorithm You can select the pivot at random out of this list. You can select it to be the first item last item It's up to you We'll set it to be the first element in the list now if you go online and you search for quick sort You'll probably find that they choose the last element really doesn't matter You just have to tweak the rest of the steps just a tiny bit We'll pick the pivot to be the first element. Okay, so my pivot in this case It's going to be number five Okay, so Now what I do is I set I equal to one And I set J equal to the length of the list minus one Okay, so we're going to set it up to here All right, and basically these are our two what we're going to do is we're going to take these two Indices and kind of walk inward to help us do the partitioning. All right So what we do is we increment I Looking for a value that is greater than the pivot value. Okay So this is going to be like a loop a while loop probably and we're going to keep incrementing I so one is Not greater than five. So we move I here Right, just imagine this. This is a loop doing this three We're looking for a value that is greater than the pivot three is not greater. So we move I here to not greater than the pivot Seven yes, seven is greater than the pivot. Okay, so we're going to stop. We're not going to do anything else We're just going to stop moving I right and now we turn to part two of this algorithm Decrement J looking for something less than the pivot. Okay, so J starts out at eight eight is not less than five So we're going to move J in one Okay six Not less than five. Okay, so we got to move in again nine Not less than five. So we move in again. Okay Four. Yes four is less than five. So we stop here. Okay, and What's going on? We're trying to get everything so that? Everything to the left of our pivot value and everything to the right of our pivot value is going to be greater than everything left It's going to be less than this is helping us do that Okay, so now step three if both I and J find something well, that's the case that we have here Swap their values then continue with step one or we're going to stop But we're not ready to stop yet. Okay, so we're going to swap these two values right here These things okay, so Bear with me. I'm gonna try and redraw this list Real fast three two seven. Oh, no Yeah, one job for right because we have swapped four and seven Zero is still there. So this is the list After we have done the swap. All right So I and J are still in their respective positions. Okay, the pivot is still here at this point I've just redrawn it to show that the swap occurred. I is still here. J is still here. Okay, all right So now we continue According to this if you find I and J find something swap them and then go back to step one. All right, so I'm actually gonna Put J just down a little bit. Okay, so increment I looking for a value greater than the pivot Okay, the pivot is five. So four is not greater than five. So we move up here Zero is not greater than five. So we move up here to seven and Seven is greater than five. Right. So we stop I'll stop here and move on to step two now we decrement J looking for a value Less than the pivot. Okay, so we move J in here one step and Yeah, zero is less than the pivot. Okay, so now what do we do? We stop we stop J All right, so now What do we do we? They have both found something Right, they've both found something. The question is are we going to swap? Okay, we're going to swap. Well the answer is no, right? Because what has actually happened is J is now less than I So since J is less than I word we're done, right? We actually have we do not do the swap So the the stopping takes precedence. All right. So finally, what do we do? We swap the pivot With a sub J, right? So we swap zero and Five Okay, so now It looks like this zero one three two four five seven eight six or excuse me seven nine six eight Okay, so this is what our list looks like now alright now Note what has happened here, right? The pivot value Was five and if you'll notice Everything to the left of the pivot is less than the pivot and everything to the right of the pivot is greater than it That is the property that we were shooting for with quicksort, right? So now Huh, that's interesting, right? So now what do we need to do? We need to make a recursive call Where we're saying hey take this sub list, excuse me Take just this sub list this part and quicksort Okay, so you want a quicksort from what what was this a? sub We want a quicksort a from I to the end right everything from This is I this is J right my quicksort everything to the right and We want a quicksort Everything from the beginning up to But not including the pivot value so the pivot value was at J Cool, right so it even works out nicely in the Python code and because lists are a mutable data structure in Python the changes that we make inside these recursive calls They will be seen right they will kind of they will actually alter the list itself So you can make this recursive call and then you stop with the recursive call whenever you've got a list That's either size one or it's empty and you're done. You know that a list of size one or a list of Size empty is already sorted all right So that's the intuition behind the partition method You need to understand that and if you understand that then you've gone a long way to understanding quicksort So we're going to switch back over to The PC with PowerPoint and talk through the rest of the handout really quick Hey everybody just want to wrap up quicksort relatively quickly so I strongly encourage you to check out these visualizations of quicksort They can hopefully help concretize it a little bit So remember we just walked through one iteration or one call of the partition algorithm But we still need to partition either the list on either side of the pivot So go take a look these and please go seek out other resources to really try and understand quicksort It is such a fundamental algorithm in computing I'm sorry that we don't have time to like play with it in in class. It's worth your while knowing it It's the kind of question that shows up on programming interviews a lot. So take the time to try and Understand it. Please contact me if you have questions and use these resources to your advantage There are a few additional questions about quicksort that I do want to answer with you though Okay, so the first question is how many comparisons against the pivot are made in a single run Through the quicksort function, right? So before when we were doing this We selected this as the pivot and we walked I and J inward Well, it's always going to be the case that we stop when J is less than I right We got these two indices So the only way that's going to be the case if I walks up and J walks up is if they Somehow cover all of the items in the list, right? So in the most kid in every time we're doing a comparison wise we walk these things So in the worst case here or the usual case the number of comparisons is going to be and Comparisons that's how many we have to do so take the time You know go back walk through the algorithm take the time to convince yourself that that is the case In the best case, where does the pivot wind up? Oh excuse me in this Well in the best case the best case is that the pivot winds up in the middle Okay, now the reason that is the best case is it just has to do with probability, right? If the pivot is in the middle then there's a good chance There's some chance that these items over here these n minus two items are kind of sorted and these Tough items that are to the right of the pivot are also maybe a little kind of sort, right? You want the pivot to be in the middle, okay, so in the best case best case the pivot Is in the middle That's the best case the worst case is When the pivot Lines up at the beginning or end okay, so why is that so bad? It effectively means that you get none of the benefits of partitioning things into Less than me and bigger than me right everything is all either bigger than me or less than me And if you're asking that question well that question is the same as insertion sort Insertion sort goes through the list and picks kind of goes up the items and says let's make everyone less than me Right make sure that everybody to the left of me is less than me. That's what it's doing Right, so quick sort kind of turns into insertion sort if the pivot is either at the beginning or the end Whereas if the pivot is somewhere in the middle you've got a probability you've got a Fairly decent chance that you while you know it's not even a probability You know that you have already swapped some things and while they may not be in their final resting place They've gotten a lot closer right So you're kind of you're kind of you're moving the pivot But you're also kind of sort of sorting these things on either side right in the same step So given the answer to the previous question what starting conditions of the list will be worse for our quick Sort algorithm. Well, that's the case where the list is already sorted in one direction or the other So if for example you wanted to quick sort an already sorted list It turns into insertion sort if you want a quick sort of list and that list happens to be in reverse order It's also insertion sort. Okay, so you really need a random distribution of the Values in the list is what you're hoping for And also how you choose the pivot can make a difference here, but you know, that's beyond us So on average though quick sort is big O of n log n. So that's neat. This is a Big O of n log and sorting algorithm and where does that n log n come from the end comes from the end Comparisons you have to do right with each pass through quick sort The log n comes from the fact that this is dividing conquer and in an ideal world your partition Your pivots gonna wind up close to the middle right and so because of that you're again You're dividing you're making the space smaller and smaller and smaller kind of like you did with binary search But you still have to do it at least n times Right, so that is a big O of n log n algorithm It's worse than big O of n. It's much better than big O of n squared Okay, but in the worst case in the worst case, which is the starting list now. I'm not talking about worst case time complexity I mean just in rare weird random events in the worst case quick sort is Big O of n squared Okay So you need to know that and you need to know when in which case it can be So besides the list how much additional space is needed not much if you're doing quick sort iteratively You need so i and j variables. You need some like temporary variables to put things in But if you make this algorithm recursive You will need space for all of the activation records And I think we mentioned these briefly during recursion that when every time a function calls another function an activation record is pushed on to the call stack and these things take up space You will need space for all the recursive calls that you make just so that python remembers Where it needs to return to okay? and these things can Take up a lot of room after a while so if you wind up quicksorting a gigantic list That's already been sorted in one direction or another you can wind up in trouble, but in general, that's rare right then general That's rare in general quicksort is very fast and it's still very popular today So study it know how it works. Please. Let me know if you have any questions