Checking Out the Code

This should update your directory to contain a new directory called mp3.
These files are used for both parts of the MP: MP 3.1 and MP 3.2.

Background Information: Template Classes

Identical to what you saw in lecture, template classes provide the ability to create generic container classes. In this MP, you will be writing a List class.

template <classT>
classList {
// implementation
};

This simply says that our class List has a parametrized type that we will
call T. Similarly, the constructor will look like this:

template <classT>
List<T>::List() {
// implementation
}

We need the template <class T> above all of our functions—it becomes part
of the function signature.

Template classes need access to the implementation for compilation. Every time
a different class is used as the template, the code must be compiled to support
containing it. For example, if you want to make a List<int>, the compiler
must take the generic List<T> implementation code and replace all the Ts
with ints inside it, and compile the result (this process is called
template instantiation). Our solution to this is to #include "list-inl.h"
at the bottom of our list.h file. This ensures that whenever a client
includes our header file, he/she also gets the implementation as well for
compilation purposes (there are other solutions, but this is how we will solve
it in this course).

Background Information: Linked Lists

The interface of this List class is slightly different from what you have
seen in lecture. This List has no sentinel nodes; the first node’s prev
pointer, and the last node’s next pointer, are both NULL. In lieu of these
sentinels, we keep a pointer head to the first node, and a pointer tail to
the last node in the List. (In an empty list, both head and tail are
NULL.) The List class also has an integer member variable, length, which
represents the number of nodes in the List; you will need to maintain this
variable.

MP 3.1: A Linked List Implementation

In your mp3 folder, you will find the following that the List class is split into four .h files:

list.h

list-inl.h

We have provided you with a skeleton for the functions needed for this part of the MP, but you will need to write the implementations. They are designed to force you to write pointer manipulation code. You will write code for these
functions, which are declared in list.h but not defined in list-inl.h. You must add your implementation in list-inl.h.

MP 3.1: Pointer Manipulation

MP 3.1: The reverse Helper Function

In list-inl.h you will see that a public reverse method is already defined
and given to you. You are to write the helper function that the method calls.

This function will reverse a chain of linked memory beginning at startPoint
and ending at endPoint.

The startPoint and endPoint pointers should point at the new start and
end of the chain of linked memory.

The next member of the ListNode before the sequence should point at the
new start, and the prev member of the ListNode after the sequence should
point to the new end.

You may NOT allocate new ListNodes.

Example

For example, if we have a list of integers

< 1 2 3 4 5 6 7 >

(with head pointing at 1 and tail pointing at 7) and call the public
function reverse()

The resulting list should be

< 7 6 5 4 3 2 1 >

(with head pointing at 7 and tail pointing at 1)

Your helper function should be as general as possible! In other words, do
not assume your reverse() helper function is called only to reverse the
entire list—it may be called to reverse only parts of a given list.

Additionally, the pointers startPoint and endPoint that are parameters to
this function should at its completion point to the beginning and end of the
new, reversed sublist.

MP 3.1: The reverseNth Function

This function accepts as a parameter an integer, $$n$$, and reverses blocks
of $$n$$ elements in the list.

The order of the blocks should not be changed.

If the final block (that is, the one containing the tail) is not long
enough to have $$n$$ elements, then just reverse what remains in the list.
In particular, if $$n$$ is larger than the length of the list, this will do
the same thing as reverse.

You may NOT allocate new ListNodes.

Example

For example, if reverseNth is called on the list of integers

< 1 2 3 4 5 6 7 8 9 >

then the call to reverseNth(3) should result in

< 3 2 1 6 5 4 9 8 7 >

For the list of integers

< 1 2 3 4 5 6 >

the call to reverseNth(4) should result in

< 4 3 2 1 6 5 >

Hint

You should try to use your reverse() helper function here.

MP 3.1: Testing Your reverse Functions

Once you have completed reverse and reverseNth, you should compile and test
them.

We are done now because we skip over the 4 and get to the tail of the list.
The 8 stays in place, and we have finished. If you were keeping track of
moves, you would notice that a number (they happen to be in order here for
convenience) gets moved the same amount of times as it is divisible by 2!
Technically this might not be true for the 8, but we could have moved it that
last time, it just would have stayed where it was (remove it from the tail
and put it back to the tail). Kinda neat, huh?

MP 3.1: Testing Your waterfall Function

Once you have completed waterfall, you should compile and test it.

make test
./test "List::waterfall"

MP 3.1: Testing

Compile your code using the following command:

make test

After compiling, you can run all of the MP 3.1 tests at once with the
following command:

./test [part=1]

Notes

These tests are deliberately insufficient. We strongly recommend augmenting
these tests with your own.

Be sure to think carefully about reasonable behavior of each of the functions
when called on an empty list, or when given an empty list as a parameter.

It is highly advised to test with lists of integers before testing
with lists of HSLAPixels.

Printing out a list both forward and backwards is one way to check whether
you have the double-linking correct, not just forward linking. Printing the
size may also help debug other logical errors.

DOUBLE CHECK that you can confidently answer “no” to the following
questions:

Did I allocate new memory in functions that disallow it?

Did I modify the data entry of any ListNode?

Do I leak memory?

MP 3.1: Extra Credit Submission

For extra credit, you can submit the code you have implemented and tested for
part one of MP 3. Follow the instructions in the MP 3 Submission section for handing in your code.

MP 3.2: Sorting

You will be implementing the helper functions for one more member function of
the List template class: sort. This is designed to help you practice
pointer manipulation and solve an interesting algorithm problem. In the process
of solving this problem, you will implement several helper functions along the
way—we have provided public interfaces for these helper functions to help you
test your code.

MP 3.2: The split Helper Function

This function takes in a pointer start and an integer splitPoint and
splits the chain of ListNodes into two completely distinct chains of
ListNodes after splitPoint many nodes.

The split happens after splitPoint number of nodes, making that the head
of the new sublist, which should be returned. In effect, there will be
splitPoint number of nodes remaining in the current list.

You may NOT allocate new ListNodes

Example

For example, if split is called on the list of integers

list1 = < 1 2 3 4 5 >

then after calling list2 = list1.split(2) the lists will look like

list1 == < 1 2 >
list2 == < 3 4 5 >

MP 3.2: Testing Your split Function

Once you have completed split, you should compile and test it.

make test
./test "List::split"

You should see images actual-split_*.png created in the working directory (these are
generated by repeatedly splitting split.png). Compare them against
expected-split_*.png.

MP 3.2: The merge Helper Function

This function takes in two pointers to heads of sublists and merges the two
lists into one in sorted order (increasing).

You can assume both lists are sorted, and the final list should remain
sorted.

You should use operator< on the data fields of ListNode objects. This
allows you to perform the comparisons necessary for maintaining the sorted
order.

You may NOT allocate new ListNodes!

Example

For example, if we have the following lists

list1 = < 1 3 4 6 >
list2 = < 2 5 7 >

then after calling list1.mergeWith(list2) the lists will look like

list1 == < 1 2 3 4 5 6 7 >
list2 == < >

MP 3.2: Testing Your merge Function

Once you have completed merge, you should compile and test it.

make test
./test "List::merge"

You should see the image actual-merge.png created in the working directory if your
program terminates properly. This is generated by merging the images
tests/merge1.png and tests/merge2.png. Compare this against expected-merge.png.

MP 3.2: The mergesort Helper Function

This function sorts the list using the merge
sort algorithm, explained below.

You should use operator< on the data fields of ListNode objects. This
allows you to perform the comparisons necessary for sorting.

You should use the private helper functions you wrote above to help you solve
this problem.

You may NOT allocate new ListNodes

This function’s runtime will be graded for efficiency (correct Big-Oh
runtime)

Example

For example, if sort is called on the list of integers

< 6 1 5 8 4 3 7 2 9 >

the resulting list should be

< 1 2 3 4 5 6 7 8 9 >

Merge Sort — Algorithm Details

Merge Sort is a recursive sorting algorithm that behaves as follows:

Base Case: A list of size 1 is sorted. Return.

Recursive Case:

Split the current list into two smaller, more manageable parts

Sort the two halves (this should be a recursive call)

Merge the two sorted halves back together into a single list

In other words, Merge Sort operates on the principle of breaking the problem
into smaller and smaller pieces, and merging the sorted, smaller lists together
to finally end up at a completely sorted list.

MP 3.2: Testing

Compile your code using the following command:

make test

After compiling, you can run the MP 3.2 tests at once with the following
command:

./test [part=2]

Notes

These tests are deliberately insufficient. We strongly recommend augmenting
these tests with your own.

Be sure to think carefully about reasonable behavior of each of the functions
when called on an empty list, or when given an empty list as a parameter.

It is highly advised to test with lists of integers before testing
with lists of HSLAPixels.

Printing out a list both forward and backwards is one way to check whether
you have the double-linking correct, not just forward linking. Printing the
size may also help debug other logical errors.

DOUBLE CHECK that you can confidently answer “no” to the following
questions:

Did I allocate new memory in functions that disallow it?

Did I modify the data entry of any ListNode?

Do I leak memory?

MP 3: Submission

Our grading system will checkout your most recent (pre-deadline) commit for
grading. Therefore, to hand in your code, all you have to do is commit it to
your Subversion repository.

Be sure your working directory is the mp3 folder that was created when you
checked out the code. To hand in your code, you first need to add the new files
you created to the working copy of your repository by typing:

To commit your changes to the repository type:

svn commit -m "mp3 submission"

Grading Information

The following files are used to grade MP 3:

list.h

list-inl.h

All other files including any testing files you have added will not be used for
grading.