Return to the Lecture Notes Index

15-111 Lecture 18 (Monday, June 14, 2004)
Quicksort Review

The idea behind a quicksort is that we have a list of numbers, and like any sorting algorithm, we have to pick a value to put in the right place. In a bubble sort and selection sort, you search the whole array for the largest value and then put that at the end, decreasing the size of the unordered array by one each time. In a quicksort, your goal is to pick the middle value and set it at the right spot in there.

2 6 5 9 3 1 8 4 7

Just guess that the middle value in the list is the middle index of the array. This value is 3. Swap the last value and that middle value, and put a pointer starting at the left, and one at the right. Compare each of the values with the 'middle' value. If the value in the left pointer is less than the middle value, then move it to the next value. If not, stop it where it is. For the right pointer, compare its value to the middle value, and if it is greater, then continue. Otherwise stop. If you happen to have both pointers stop, then swap the values of those two pointers and then move both pointers forawrd. Once the left and right meet,you know that's where your middle value needs to be, so put it back in.

Once you've done this, you recursively do the sort again on the two unordered lists to the left and right of the middle value. Both of these are ~1/2 the size of the original list if we get lucky. Keep recursively doing this until you reach your base case of a list of size 1, which is trivially sorted.

2 6 5 9 3 1 8 4 7  

Swap 3 value in middle with end value

   2 6 5 9 1 8 4 7 3
   |             |
 left           right

Here 2 is less than 3, so move its pointer forward.

   2 6 5 9 1 8 4 7 3
     |           |
   left         right

6 is greater than 3, so stop the left, and check the right one. 7 is greater than 3, so move its pointer left one.

   2 6 5 9 1 8 4 7 3
     |         |
   left       right

4 is also greater than 3, so move it again.

   2 6 5 9 1 8 4 7 3
     |       |
   left     right

8 is also greater than 3, so move it again.

   2 6 5 9 1 8 4 7 3
     |     |
   left   right

Now 1 is less than 3, so swap the left and right, and move the pointers forward by 1.

   2 1 5 9 6 8 4 7 3
       |  \
     left  right

5 is greater than 3, so stop the left one. 9 is greater than 3, so move the right one over one.

   2 1 5 9 6 8 4 7 3
       |\
    left right

Now left and right are pointing to the same value. Since 5 is greater than 3, we can just swap it with the end.

   2 1 3 9 6 8 4 7 5
   \_/   \_________/

We've now put 3 in its proper spot, so we've broken the problem down into doing quicksort on two smaller lists.

The algorithm

The main reason why this algorithm works is not just that you're putting the pviot in the right place, but mainly because when you pin the pivot in its right place, you have all the left values less than you, and all the right values greater than you. By doing this you are properly breaking down the problem into two smaller subproblems. If some numbers on the left belong on the right of the pivot, then sorting the two smaller lists would not solve the large problem of creating the

Practice questions

NOw we're going to do a few practice problems, the first being pathLength. This returns the length of the path from the root to a specified value.


/* returns number of edges between root and node with specified data value
 *
 * returns -1 if value isn't found
 */

public int pathLength (Comparable c) {
   return find (root, c);  //need to recursively solve this
}

public int find (BSTNode root, Comparable c) {
   if (root == null)
     return -1;  //not found

   int diff = root.getData().compareTo(c);

   if (diff == 0)
     return 0;  //found it!  return 0 to show it

   if (diff < 0) {  //if < 0 check right
      int edgeCount = find(root.getRight());
      if (edgeCount < 0)  //if edgeCount returns -1 then you failed..
                          //show this by also returning -1.
         return -1;
      else //otherwise you were successful.. add 1 to the previous edgeCount
           //to add yourself into the count. 
         return 1 + edgeCount;
   }


   //same thing for the left subtree
   if (diff > 0) {
      int edgeCount = find(root.getLeft());
      if (edgeCount < 0)
         return -1;
      else
         return 1 + edgeCount;
   }

Now we're going to try another, to see whether a tree has the Heap Order Property. Remember that this means the parents must be less than children at all points in the tree.


   public boolean hasHeapOrder() {
      return hasHeapOrder(root);  //as in most cases with trees.. easiest to do recursively
   }

   public boolean hasHeapOrder (BSTNode root) {

     if (root == null)
       return true;  //empty tree trivially has the property.

     if ((root.getLeft() == null) && (root.getRight() == null))
       return true;  //same for a tree that only has a root.

     //recursively check for heap order on left.. if it returns 
     //false then also return false.. also make sure that the 
     //left node is greater than the parent.
     if (!hasHeapOrder(root.getLeft()) ||
         root.getLeft().getData().compareTo(root.getData()) < 0)
       return false;

      
     //do same for right subtree..
     if (!hasHeapOrder(root.getRight() ||
         root.getRight().getData().compareTo(root.getData()) < 0)
       return false;
 
     //if you never returned false here.. then both subtrees have 
     //heap order property and are less than you, so also return true
     return true;

   }
}