Introduction to Computer Science:
Assignment 24:  Quiz Review and Debugging Fundamentals
 Sewickley Academy, 2000-2001

See Course Home Page.
 
Date Assigned: Fri Dec-1
Date Due: Wed Dec-6

0. Note:  This is an ungraded assignment.  Part A includes code to review for the quiz on Monday Dec-4, and Part B includes a description of the debugging techniques which may appear on a pop quiz sometime later this week.



Part A:  Code to review for the Sorting Algorithms quiz on Monday Dec-4

//////////////////////////////////////////////////
/////  Sort Functions Demonstration Code
/////  by David Kosbie
//////////////////////////////////////////////////

// This program demonstrates the following 6 sorts:
// insertionSort, selectionSort, bubbleSort,
// mergeSort, quickSort, radixSort.

// The IntroCS students are responsible for the first 4
// sorts (all but quickSort and radixSort).

// The AP CS students are responsible for all 6 sorts.

//////////////////////////////////////////////////
/////  Includes, Typedefs, Constants
//////////////////////////////////////////////////

#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <math.h>
#include "apvector.h"

typedef apvector<int> intVector;
typedef intVector& intVectorByReference;
typedef int& intByReference;

const int BASE = 10;
const int MAX_EXPT = 6;

//////////////////////////////////////////////////
/////  loadVector(), printVector(), and swap()
//////////////////////////////////////////////////

// loadVector() loads the vector v with
// random elements in [0,BASE^MAX_EXPT)
// (presently 10^6).
void loadVector(intVectorByReference v)
{
 // load vector with numbers mostly random in [0,BIG_NUM]
 int len = v.length();
    for (int i = 0; i < len; i++)
        v[i] = rand() % int(pow(BASE,MAX_EXPT));
}

// This function is provided here for debugging purposes,
// and is not currently called by any functions below.
void printVector(intVectorByReference v)
{
 // print vector elements separated by two spaces with
 // a carriage return at the end
    for (int i = 0; i < v.length(); i++)
        cout << v[i] << "  ";
    cout << endl;
}

void swap(intByReference x, intByReference y)
{
 int temp;
 temp = x;
 x = y;
 y = temp;
}

//////////////////////////////////////////////////
/////  insertionSort()
//////////////////////////////////////////////////

// This O(n^2) sort repeatedly inserts the element at the
// cursor into the sorted vector to the left of the cursor.

void insertionSort(intVectorByReference v)
{
 int len, cursor, i;
 len = v.length();
    for (cursor=1; cursor<len; cursor++)
        for (i=0;i<cursor;i++)
            if (v[i] > v[cursor])
    swap(v[i],v[cursor]);
}

//////////////////////////////////////////////////
/////  selectionSort()
//////////////////////////////////////////////////

// This O(n^2) sort repeatedly finds the smallest element from
// the cursor to the right end of the vector and swaps
// that element with the cursor.

void selectionSort(intVectorByReference v)
{
 int len, cursor, i;
 len = v.length();
    for (cursor=0; cursor<len-1; cursor++)
        for (i=cursor+1;i<len;i++)
            if (v[i] < v[cursor])
    swap(v[i],v[cursor]);
}

//////////////////////////////////////////////////
/////  bubbleSort()
//////////////////////////////////////////////////

// This O(n^2) sort repeatedly sweeps through the vector and
// swaps each pair of elements which are out of order.
// This is repeated until an entire sweep results in no swaps.

void bubbleSort(intVectorByReference v)
{
 int len, cursor;
 bool unsorted;

 len = v.length();
 unsorted = true;

 while (unsorted == true)
 {
  unsorted = false;
  for (cursor=1; cursor < len; cursor++)
   if (v[cursor] < v[cursor-1])
   {
    swap(v[cursor],v[cursor-1]);
    unsorted = true;
   }
 }
}

//////////////////////////////////////////////////
/////  mergeSort()
//////////////////////////////////////////////////

// This O(n log n) sort is much faster than the O(n^2) sorts
// above.  It is also recursive whereas the above sorts are
// iterative.  It operates by recursively sorting the left
// and right halves of the vector and then merging the sorted
// halves into a sorted whole.

void merge(intVectorByReference v,int lo,int hi)
{
 // 1. Declare variables
 int mid, mergeIndex, mergeSize, leftIndex, rightIndex;
 int leftMaxIndex, rightMaxIndex;
 bool leftHalfDone, rightHalfDone;
 intVector mergeVector;

 // 2. Initialize variables
    mid = (hi + lo) / 2;
    leftIndex = lo;
 leftMaxIndex = mid;
    rightIndex = mid+1;
 rightMaxIndex = hi;
 leftHalfDone = false;
 rightHalfDone = false;
 mergeSize = 1 + hi - lo;
 mergeVector.resize(mergeSize);

 // 3. Merge into the mergeVector
    for (mergeIndex=0; mergeIndex<mergeSize; mergeIndex++)
    {
  // Get the next element from either left half or right half,
  // place into mergeVector and advance the appropriate index.
  // Use the left half if:
  //  a)  The right side is done, or
  //  b)  The left side is not done, and the left side is smaller
        if ((rightHalfDone == true) ||
            ((leftHalfDone == false) && (v[leftIndex] < v[rightIndex])))
  {
   // Use the next element on the left half
            mergeVector[mergeIndex] = v[leftIndex];
   leftIndex++;
   if (leftIndex > leftMaxIndex)
    leftHalfDone = true;
  }
        else
  {
   // Use the next element on the right half
            mergeVector[mergeIndex] = v[rightIndex];
   rightIndex++;
   if (rightIndex > rightMaxIndex)
    rightHalfDone = true;
  }
    }

 // 4. Copy from mergeVector back into v
    for (mergeIndex=0; mergeIndex<mergeSize; mergeIndex++)
  v[lo + mergeIndex] = mergeVector[mergeIndex];
}

// This function sorts the elements from v[lo] to v[hi].
void mergeSort(intVectorByReference v,int lo,int hi)
{
 int mid;

 // 1 Base Case: if there is 1 (or fewer) elements,
 // then the vector is sorted, so just return.
    if (hi <= lo)
  return;

 // 2.  Recursive Case
    mid = (hi + lo) / 2;
    mergeSort(v,lo,mid);   // Sort the left half
    mergeSort(v,mid+1,hi); // Sort the right half
 merge(v,lo,hi);        // And merge the sorted halves
}

void mergeSort(intVectorByReference v)
{
    mergeSort(v,0,v.length()-1);
}

//////////////////////////////////////////////////
/////  quickSort()
//////////////////////////////////////////////////

// This O(n log n) sort is also recursive like mergeSort.
// It is typically about twice as fast as mergeSort.  However,
// while the average performance for quickSort is O(n log n),
// its worst-case performance (if you pick the worst pivot each
// time) is O(n^2).  Conversely, mergeSort's worst-case performance
// is the same as its average-case performance:  both are O(n log n).

// This sort operates by choosing a pivot, then splitting the
// vector so that the elements less than or equal to the pivot
// are to the left of the pivot, and those greater than the
// pivot are to the right of the pivot.  Then the two portions
// to the left and right of the pivot are recursively sorted.

int getPivotIndex(intVectorByReference v,int lo,int hi)
{
 return lo;
}

int pivot(intVectorByReference v, int lo, int hi)
{
 int pivotIndex;
 // 1. get a pivot index and swap it to the first position
 pivotIndex = getPivotIndex(v,lo,hi);
 swap(v[pivotIndex],v[lo]);

 // 2. Swap elements as necessary so those less than or
 //    equal to the pivot are in the left portion, and
 //    those greater than the pivot are in the right portion
 //    of the vector.
 int loPointer = lo + 1; // lo is the pivot, and we don't count it
 int hiPointer = hi;

 while (loPointer < hiPointer)
 {
  if (v[loPointer] <= v[lo])
   loPointer++;
  else if (v[hiPointer] > v[lo])
   hiPointer--;
  else
   // Both left and right elements are on the wrong
   // side, so swap them and continue.
   swap(v[loPointer],v[hiPointer]);
 }

 // 3. Swap the pivot into the new location
 assert(loPointer == hiPointer);
 int newPivotIndex;
 if (v[loPointer] <= v[lo])
  newPivotIndex=loPointer;
 else
  newPivotIndex=loPointer-1;
 swap(v[newPivotIndex],v[lo]);
 return newPivotIndex;
}

void quickSort(intVectorByReference v,int lo, int hi)
{
 if (lo >= hi)
  return;

 int p = pivot(v,lo,hi);

 quickSort(v,lo,p-1);
 quickSort(v,p+1,hi);
}

void quickSort(intVectorByReference v)
{
 quickSort(v,0,v.length()-1);
}

//////////////////////////////////////////////////
/////  radixSort()
//////////////////////////////////////////////////

// This sort is O(n log RANGE), where RANGE is the range of
// the elements in the vector.  For example, here we are using
// elements from 0 to 999,999, so our range is 10^6, and this
// requires 6 iterations, thus this is O(6 * n), which in fact
// is O(n).

// Thus, for large enough n, this sort will be arbitrarily
// faster than either mergeSort or quickSort (and of course
// will completely bury insertionSort, selectionSort, and bubbleSort).

typedef apvector<intVector> intVectorVector;

void radixSort(intVectorByReference v)
{
 intVectorVector buckets(BASE);
 intVector bucketCount(BASE);
 int i, len, bucket, bucketSize;
 len = v.length();

 // Initialize buckets
 int defaultBucketSize = 10 + 2 * len / BASE;
 for (i=0;i<BASE;i++)
 {
  bucketCount[i] = 0;
  buckets[i].resize(defaultBucketSize);
 }

 // Iterate over each expt up to MAX_EXPT
 int divver, modder = 1;
 for (int expt=0; expt < MAX_EXPT; expt++)
 {
  modder *= BASE;
  divver = modder / BASE;
  // 1.  Place each element v[j] into the approprate bucket
  //     based on the expt'th digit in v[j]
  for (int j=0;j<len;j++)
  {
   bucket = (v[j] % modder) / divver;
   bucketSize = buckets[bucket].length();
   // add v[j] to this bucket now
   // first make sure there is room
   if (bucketCount[bucket] >= bucketSize)
    buckets[bucket].resize(2*bucketSize);
   buckets[bucket][bucketCount[bucket]] = v[j];
   (bucketCount[bucket])++;
  }

  // 2.  Copy the buckets, from bucket[0] to bucket[BASE-1],
  //     back into v.
  //     AND clear the buckets for the next iteration by
  //     resetting the bucket count to 0!
  int vIndex = 0;
  for (bucket = 0; bucket < BASE; bucket++)
  {
   for (i=0; i<bucketCount[bucket];i++)
    v[vIndex++] = buckets[bucket][i];
   bucketCount[bucket] = 0;
  }
 }
}

//////////////////////////////////////////////////
/////  verifySorted() and testSort()
//////////////////////////////////////////////////

void verifySorted(intVectorByReference v)
{
 int cursor;
 for (cursor=v.length()-1; cursor>0; cursor--)
  if (v[cursor] < v[cursor-1])
  {
   cout << "Uh oh -- vector not sorted at index "
     << cursor << endl;
   return;
  }
 cout << "Wahoo -- the vector is sorted!" << endl;
}

// Note:  IntroCS students are *not* responsible
// for any part of the following function.
void testSortFunction(char* name,void(*sortFn)(intVector&v),intVector& v)
{
    intVector v2;
 int time1,time2;
    v2 = v;
 cout << endl << "Starting " << name << ": ";
 cout.flush();
 time1 = time(NULL);
    sortFn(v2);
 time2 = time(NULL);
 verifySorted(v2);
 cout << "Sort took: " << (time2 - time1) << " seconds" << endl;
}

//////////////////////////////////////////////////
/////  main()
//////////////////////////////////////////////////

void main()
{
    intVector v;
    int vSize;
 bool useSlowSorts;

 useSlowSorts = true;
    while (true)
    {
        cout << "Enter size of vector (0 to toggle slow sorts, <0 to exit): ";
        cin >> vSize;
        if (vSize < 0)
            return;

  if (vSize == 0)
  {
   useSlowSorts = !useSlowSorts;
   if (!useSlowSorts)
    cout << "not ";
   cout << "using slow sorts." << endl << endl;
  }
  else
  {
   v.resize(vSize);
   loadVector(v);
   cout << endl << "------------------------------";
   if (useSlowSorts)
   {
    testSortFunction("insertionSort",insertionSort,v);
    testSortFunction("selectionSort",selectionSort,v);
    testSortFunction("bubbleSort",bubbleSort,v);
   }
   testSortFunction("mergeSort",mergeSort,v);
   testSortFunction("quickSort",quickSort,v);
   testSortFunction("radixSort",radixSort,v);
   cout << "------------------------------" << endl << endl;
  }
    }
}



Part B:  Debugging Techniques Which May Appear on a Pop Quiz Later This Week

Your assignment:  learn how to use the debugger.  Do this by stepping through code you have already written.  Intro CS students are responsible for the following (and yes, you must know these by their F-keys (meaning, you must simply know what Shift-F11 does, for example), and yes, you may be quizzed on this as soon as tomorrow):

Finally, Intro CS students are responsible for understanding basic debugging techniques, such as: IntroCS students will cover more advanced debugging techniques later in the year, but this is enough to get you started.  Remember: use the debugger early and often.  It can save you *enormous* amounts of time.

Carpe diem.

DK


See Course Home Page.