CISC 320 Algorithms and Advanced Programming

Homework set #1, Fall, 2002

Due Tue, Oct 1.

  1. Write a function max_min(Vector& A) which puts the min of the entries of A in the first position and the max of the entries in the last position. The other entries may end up in any position you wish. ...but no entries should be lost. The final values should be some permutation of the initial values. Assume only that entries can be swapped and can be compared using <=. Use at most 3n/2 comparisons of entries, where n is A.size(). Your program can allocate and use any additional memory it wants.

    This is a pencil and paper exercise. You may write your code in "pseudo-C++", which means that it does not have to be syntactically correct in every detail. However, the intended computation should be made clear. Write an explanation why your method uses only 3n/2 comparisions of entries.

  2. Write a function sort5(Vector A) which takes a vector of length 5 and sorts it into increasing order. Assume only that entries can be swapped and can be compared using <=. Use at most 7 comparisons, regardless of the initial order of the 5 entries of A.

    Write sort5 as a C++ template function and test it using the sort5_test program that will be provided on the composers.

  3. Do timing tests of quickSort and randomizedQuickSort on 4 kinds of data set and for various sizes of data set. The four kinds of data set are (1) data already sorted in increasing order, (2) data initially sorted in reverse (decreasing order), (3) data originally in random order, and (4) grid data in column order which is to be sorted in row order.

    Grid data involves entries which are elements of

    class GridNode
    {   
    	double val; 
    	int row; 
    	int col;  
        public: 
    	// constructors
    	GridNode(double v, int r, int c) : val(v), row(r), col(c){}
    	GridNode() {}
    	GridNode(const GridNode& b) : val(b.val), row(b.row), col(b.col){}
    	// comparator for sorting in row order
    	bool operator<=(GridNode& b) 
    	{ return ( row < b.row ) || ( row == b.row && col <= b.col ); }
    };
    
    Here is an example of a data set of grid data in column order. It makes somewhat randomized data. Only about 50% of the n*n possible grid points will have data.
    vector<GridNode> A;
    for (int j = 0; j < n; ++j)
      for (int i = 0; i < n; ++i )
        if ( rand(2) ) 
          A.push_back( GridNode( 1.0/(i+j+1), i, j) );
    
    Choose sensible sizes of data sets so that quickSort and randomizedQuickSort take time which is measurable but excessively long. Sensible sizes will be different for the four different categories of data.

    This is an online exercise in which you write code to generate test cases and time the execution of sort as defined in ~saunders/320/sort/quickSort.h and randomizedQuickSort.h. Submit your test code so that we can see how your test data was constructed. Submit the results of the timings. Analyze/discuss/explain the timings. Do they come out as expected? What do you conclude from these experiments.

  4. MergeSort is easily written recursively and this may be described as a "top down" description. It is essentially, "if there is data, mergeSort each half, then merge the results." MergeSort may also be written "bottom up". The following code does this when the size, n, of the data set is a power of 2.
    template<class Iterator>
    /* 
     We require that class Iterator has pointer arithmetic operations
     and that the unknown class pointed to by dereferencing iterators has 
     operator <= defined.
    */
    void
    mergeSort(Iterator b, Iterator e, Iterator w) // w is for workspace
    {
      // Permute the items [b, (b+1) .. e) into sorted order.
      // Assume e-b is a power of 2.
      for (int k = 1; k < e-b; k = 2*k)
        // merge pairs of sections of length k
        for (Iterator i = b; i < e; i += 2*k)
        {
          merge(i, i+k, i+k, i+2*k, w);
          // copy back
          for (Iterator j = i; j < i+2*k; ++j) *j = *(w + (j - i));
        }
    }
    
    Assume merge is as in ~saunders/320/sort/mergeSort.h on the composers.

    Suppose that the data is a vector of 16 chars in reverse order such as this, for instance:

    main()
    {   vector<char> A(16), w(16);  
        // assume A is initialized to the first 16 letters of the alphabet in 
        // reverse order:  A = {p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, a} 
        mergeSort(A.begin(), A.end(), w.begin());
    }
    
    Write the value of k and the contents of A after each iteration of the outer for-loop in the bottom-up mergeSort function.

  5. Using the bottom-up merge sort of the previous example, explain how many comparisons are made if the data is a vector of 128 elements originally in reverse order. How many comparisons are made if the 128 elements are originally already sorted?

  6. Modify the bottom-up mergeSort so that it works on data vectors of arbitrary length, not just lengths which are powers of 2. Write C++ code. This is a paper and pencil exercise. You do not have to debug and test. Write comments to make clear why you expect it to work correctly.