Java Lecture 11: Sorting

Sorting
  1. Binary search depended on the array of values being sorted
  2. So, now we need to sort our array of values
  3. How should we do this? And can we do this efficiently, too?
  4. Insertion Sort
    1. Idea: pick an item, find where it goes, and insert it at that point
    2. do this incrementally until all items have been inserted into their place
    3. Example: Values start out in order 3,1,5,2,4
  5. Bubble Sort
    1. Idea: compare adjacent items, and swap if they are out of order
    2. continue this on up the array, making as many passes as needed
    3. Example: Same as insertion sort
  6. How efficient are these?
  7. They take about N^2 operations to sort N values
    1. Not quite, but there is no other (simple) formula that they stay below
  8. This isn't very good, can we do better?
First, a little more about arrays
  1. When you declare an array, we said it is not created until you do a "new".
    1. I.e., "int A[];" doesn't create the array A (well, you didn't give it any size anyways)
    2. What is it you are declaring? It is a reference to an array. Then, when you do the new command, the reference is assigned to refer to (or "point to") the newly created array, with all its storage space.
    3. I.e., "A = new int[10];" creates a new array (with no name!), and assigns the array reference A to refer to that 10-element integer array
    4. In fact, if I had another array reference "int B[];", I could do "B = A;", and then A and B would refer to the same array! In other words, B[0] and A[0] would be the same variable, the same value.
  2. The whole array, then, is not a local variable. Just the reference is. The array itself can exist after the method that it was created in is done. In fact, the array could be returned from the method.
  3. But, the reference that refers to it is a local variable, so some other array reference variable needs to be assigned to it, or else it is lost forever.
  4. Even more, when an array is passed as a parameter to a method, only the reference is passed.
  5. So, changes to an array inside a method actually change the array outside of the method!
    1. Good! We can write a Sort method that takes the array as a parameter, and after it is done the array that we called it with is sorted, and stays that way (unless we change it somehow)
  6. The array itself (the references are local variables, so they are on the call stack) is created and stored in an area of program memory called the heap. It lasts between method calls, and actually until no more references refer to it. Once all references are gone to an array, it is removed. This is called garbage collection.
New Algorithm : Mergesort
  1. Idea: Split the problem in half, sort the halves, then merge them
    1. Then, you can split the sub-halves into halves as well, sort them, etc. etc.
    2. Stop splitting when you have a half that is only one value (it is sorted already!)
  2. It is much easier to describe this algorithm using recursion than it is to describe it with a loop
  3. static void Mergesort(int A[], int low, int high)
    {
       int mid;
       if (low>=high) // then only one value, so we're done
          return;
       mid = (low+high)/2;
       Mergesort(A,low,mid);
       Mergesort(A,mid+1,high);
       Merge(A,low,mid,high);
    }
  4. In this method, low and high are the endpoint indices that the current call of Mergesort is considering (so, in the first call, low==0 and high==A.length-1)
  5. This is all that the Mergesort method needs to be, but what about the method Merge that it uses? Well, that's a little more complex, but not much.
  6. Merge needs to take two sorted sequences of values, and combine them into one sorted sequence:
    1. Idea: work along the sequences, taking the lowest value from either sequence at each step and copy it into a holding array
      1. Note: you need to declare this holding array and create it using new. It should be just big enough to hold the portion being dealt with -- i.e., its size should be (high-low+1)
      2. Note: they most likely do not alternate: one sequence might be all lower than the other. So you need to handle these types of cases (as explained in the next three steps)
    2. Start at the beginning of each sequence. Keep current indices into each sequence
      1. one sequence starts at low and goes to mid; the other starts at mid+1 and goes to high
    3. While you're not at the end of either sequence, take the lowest value from one of the sequences, copy it into the holding array, update its current index, and continue
    4. After that while loop, only one sequence has been fully consumed. Take the other one and finish copying its values into the holding array
    5. Now, copy the holding array back into the original array, from indices low to high. This leaves that portion of the array sorted