 Unlike in searching, when it comes to sorting, we have more than a few different options for the general case of an unsorted list. We're going to look at just five, starting with the infamous bubble sort and ending with the accurately named quicksort, which note that yes is intentionally spelled as one word rather than two, unlike all the other sorts. So the general strategy of the bubble sort algorithm is that we work from the start of the list to the end of the list comparing each adjacent pair of items and swapping those which are in the wrong order. So here we have our unsorted list of E, B, C, A, D, which of course properly sorted would be A, B, C, D, E. And in our first pass through the list, we will compare the first element and the second element, E and B, the second element and the third, the third and the fourth and the fourth and the fifth. And as we do so left to right, and we swap them as we compare, we swap them if they are not in the correct order. So first off is E less than B. No, it is not. So we need to swap them. That puts E in the second position, which we compare against C in the third position and those two are out of order. So we swap them. C ends up in the second position and E in the third. And then we compare E in the third position with A in the fourth. And those again are out of order. So we swap them. A gets moved into the third position and E in the fourth. And then finally E compared to D. Again, those are out of order. So we swap them and D ends up in the fourth position and E in the fifth. Now, of course, the list is still not sorted, but this is just our first pass. We now do a second pass, but this time we do one less comparison and swap. So we compare B against C. That's a correct order, so we don't need to swap them. Then we compare C against A. And those are out of order, so we have to swap them. A ends up in second position and C in third. Then we compare third position C against fourth position D. Those are in correct order, so there's no swap there. And after our second pass, we end up with B, A, C, D, E. Again, still not sorted, but again, there's another pass. Again, with one less comparison than the previous pass. So we're just comparing B against A. Those are out of order. We swap them. And then B against C. Those are in order, so no need to swap. And notice now that our list is now properly sorted. However, if the data had been different, if things were mixed differently at the start, it's still possible that the first and second item would be out of order. So we actually have one more pass to do in which we compare one less item from the previous pass. So we just compare the first and second. But of course A and B are still in correct order, so we don't swap them. The point though is that the algorithm doesn't know that in some cases it might finish early. It might not need to do the last few passes. But that all depends on the particular unordering of our list at the start. Now, you may have noticed a pattern with bubble sort that after the first pass, the last item is in its proper position. And then after the second pass, the next to last item is in its proper position. And then after the third pass, the next to next to last item is in its proper position and so forth. So one way to think of bubble sort is that it's effectively like we are finding the item that goes at the end of the list, and then the next to last item, and then the next to next to last item. And this pattern continues until the very last pass where actually we're putting the very last two pieces in their place, the first and second item. Again, note though that in some cases, depending on how the data is unsorted to begin with, some items may find their place early. Like notice that D, the second to last item, finds its place after the first pass, so it actually finds its place one pass early. And actually in this case the same can be said of C, B and A, they all find their place one step early. In any case, looking at how we would implement this in code, we have our function bubble sort which takes one parameter, the list which we are sorting and in the body we have two loops. The outer one for each pass through the algorithm and then the inner one for iterating through the comparisons made in each pass. Recall from our example that we had five items and yet we did four passes because the pattern with bubble sort is that the number of passes is one less than the number of items in the list. And in the inner loop, the number of comparisons we do starts off one less than the length of the list but gets smaller by one by each pass. So from the length of the list we subtract one and also we subtract the index of which passes is. In the first pass the pass index will be zero and in the last pass it will actually be two less than the length of the list because again recall that the range function creates a range from zero up to but not including the number specified in our outer loop we specified a range of length of list minus one. So if the list has a length of five then the argument to range is four producing a range of zero, one, two, three. So in the last pass it will end up that our inner loop will only do just one iteration. Now in the inner loop we do our comparison and if the items are out of order we do our swap. We get our two comparison values a and b, the item at index i and i plus one and if a is greater than b then we swap them. Notice that our comparison is done here using just a greater than operator and that works great assuming that we are ordering a list of numbers. Other data types though don't necessarily have defined behavior with the greater than operator. For those cases you generally have to define your own semantics of what it means for one value to be greater than another and you would do so by implementing your own function and then using that function as the comparison in a sorting algorithm. For simplicity though we're just going to illustrate sorting with the assumption that we're talking about sorting numbers so we're just going to use the greater than and less than operators. The general strategy of the insertion sort algorithm is to take values from the so-called unsorted portion of the list and insert them into a sorted portion of the list. That is a portion of the list where the items are sorted at least relative to each other. This is basically the same strategy people often use in real life like say if you wanted to sort a deck of cards you would take a card off the top or maybe just a random card from the stack and you'd place it in a new stack and as you do this one by one is you take cards from the original stack and place them in the new one. In the new stack you would keep them sorted relative to each other as you add the cards so you draw cards one by one and insert them into place. Insertion sort is that same idea except most commonly it's done such that we are using the same space the same list to keep both the unsorted portion and the sorted portion. So we start off by simply designating the first item as being the sorted portion of the list and given that it has just one item of course it's naturally sorted within itself. Notice that we're designating the unsorted portion with a red outline and the sorted portion with an orange outline. Then in the first pass we take the first item from the unsorted portion of the list in this case B and we insert it into the sorted portion of the list. In the next pass we do the same thing we take the first value of the unsorted portion in this case C and insert it into its proper place in the sorted portion. In each pass we keep doing this the sorted value and inserting it into the sorted portion of the list until the whole list is sorted. One thing to note about the pattern of insertion sort is that it's not until after the very last pass that we know for sure that every item is in its proper position. Until then you have yes the sorted list is growing and some items may end up in their final position in earlier passes but it's not until after the very last pass that we know that any and all items are in their proper position. Now as for the actual insertion process the way it works is that we compare the value to insert with the value to its left and if the insertion value is less than the value to its left then we swap them and do it again we compare the insertion value to the new value to its left and if it is less than that value then we swap them. So basically we walk the insertion value one step to the left until finally it either reaches the front of the list or we find that the value to its left is less than that insertion value. So here in the second pass when we insert C into the sorted list. C is less than E, so we swap those two values and then when we compare C against B, C of course is greater than B, so the insertion value is actually now in its proper place. Looking now at code for insertion sort, we have a function insertion sort that takes one parameter, the list to sort, and again we have two loops. The outer loop, which iterates for each pass of the algorithm for the insertion of each item, and the inner loop which does the actual insertion. Note that in the outer loop we are iterating from index one up to but not including the length of the list, so in a five element list we're going to iterate from one to two to three to four. Again we don't have to insert the first item into the sorted portion of the list because we just designate that first item as itself being the sorted portion of the list, so we actually start by inserting the second item of the list, not the first. Now in our inner loop we are iterating from the index of the item to insert, its original position, down to but not including zero. That's what the third argument to range here means, that we are counting down, not up, and we're counting down in steps of one. So when index has say the value five, then range here represents a sequence of five, four, three, two, one. And then inside our inner loop is where we do our comparison and swap. So first we get the two values to compare the value at insertion index and the value just before insertion index, insertion index minus one. We compare them and if the value to the left is less than or equal to the insertion value, then we are done with this pass of the algorithm. We're done inserting this value. So we break out of the inner loop, otherwise we do a swap and go to the next iteration. If in a particular insertion pass, A never tests less than or equal to B, then we'll never break and the insertion value will end up in the first position of the list. It'll end up at index zero and we'll move on to the next pass to the next insertion. The selection sort is a variant on the basic idea of the insertion sort whereby we have an unsorted portion of the list from which we take values one by one and place them into the sorted portion of the list. In a selection sort, we don't just take any value or the first value from the unsorted portion. We find the smallest value still in the unsorted portion and we tack that on to the end of the sorted portion. What this produces is a sorting pattern that almost looks like the reverse of the bubble sort, whereas bubble sort effectively finds the values which go at the end of the list first and works its ways backwards. In selection sort, the order is front to back. We first find the item that goes at the front, then the next item, then the next and so on until we've sorted the entire list. So here in this example in the first pass, we identify A as the smallest value in the unsorted portion of the list. So we swap it to the front of the list, so A and E swap places. And then in the second pass, we find that B is the lowest value. So we swap it to the next position and it swaps with C. Then in the third pass, C is the smallest value in the unsorted portion of the list. So we swap that into the next position, we swap it with D. And then finally in the last pass, D is the smallest value. So we swap that into place. And of course logically, once every value but one is in their proper place, and of course that last value must also be in its proper place. So note that the last pass, just like in bubble sort, actually puts two values in their place, not just one. In our selection sort function, we again just take one argument, the list to sort, and again we have two loops, one nested within the other. The outer loop represents each pass through the algorithm, and the number of passes like in bubble sort is one less than the length of the list. Target index here refers to the index of the list to which we are going to swap the smallest value in the unsorted portion of the list. So in the first iteration, we swap that smallest value to index zero. In the next pass, we swap it to index one, and index two, then three, four, and so on. Within each pass, our inner loop is where we will scan to find the smallest value in the unsorted portion of the list. And for this purpose, we iterate from target index plus one up to but not including the length of the list. So for example, if we're in the second pass of sorting the list of length five, then target index will have the value one. One plus one is two. That's our first argument to range, and length of ls is five. So range here will return a sequence of two, three, and four. Now it be clear what we're looking for in each pass is not the minimum value per se. We don't really care what that value is. We want to know where it's located. We want its index. So before our inner loop, we start off assigning a local min index, the value of target index, and min value, the value at that location. Then in the inner loop, we get the value at index i. And if it is less than the current min value, then we update min value with this value and min index with this index. Then once our loop completes, min value should contain the smallest value in the unsorted portion, and min index should have its index. With this information, we can then swap the minimum value into place. We can swap it with the value at target index.