Saint Louis University |
Computer Science 180
|
Dept. of Math & Computer Science |
Please see the general programming webpage for details about the programming environment for this course, guidelines for programming style, and details on electronic submission of assignments.
For this assignment, you must work individually in regard to the design and implementation of your project.
Please make sure you adhere to the policies on academic integrity in this regard.
In this assignment, we wish to add another of the std::list behaviors into our NodeList class. Specifically, the merge method (documented here), has a signature that for our class will appear as
A precondition to this function is that the values on the original list are sorted in non-decreasing order, and that the values on the other list are also sorted in non-decreasing order. After a call to merge, all elements should be in the first list, and the second list should be empty.void merge(NodeList& other);
Note well that the documentation for the official function states
The entire operation does not involve the construction, destruction or copy of any element object. They are moved.
The pointers, references and iterators that referred to moved elements keep referring to those same elements, but iterators now iterate into the container the elements have been transferred to.
We insist that your implementation provide a similar guarantee. What this means for your implementation is that you must internally relink the Node's to accomplish the relocation of nodes from the secondary list to the primary list.
The high-level algorithm for merging two sequences is described in Chapter 11.1.2 of the book (in the context of a recursive sorting algorithm known as mergesort). You may use the same ideas in your program, but note that you are to merge the elements from the secondary list into the primary list, while the book's description assumes that two lists are being merged into a third list.
A final hint comes from the formal documentation of STL's merge, which describes the algorithm in great detail, paraphrased in our context as:
The merging is performed using two iterators: one to iterate through other and another one to keep the insertion point in the list object; During the iteration of other, if the current element in other compares less than the element at the current insertion point in the list object, the element is removed from other and inserted into that location, otherwise the insertion point is advanced. This operation is repeated until either end is reached, in which moment the remaining elements of other (if any) are moved to the end of the list object and the function returns (this last operation is performed in constant time).
All such files can be downloaded here.
NodeList.h
This is our original implementation of the NodeList class,
including a new stub for the merge function,
yet without any code.
NodeListVisualizer.tcc
Some support for generating visualizations of the linked lists
(see discussion of driver below).
MergeTest.cpp
This file provides a main driver to be used in testing your
program. You will not need to modify or examine this code. The
use of the driver is discussed in a later section.
makefile
This makefile should allow you to rebuild your project by
simply typing 'make' rather than in invoking the compiler
directly.
Your revised NodeList.h source code
Test Input
Please submit a single file, inputfile, which we will
use as sample input when testing all of the students'
submissions. The file format for inputfiles is based on use with our driver
Your input file may use at most 100 lines (although you may
certainly specify multiple merges within the 100 line limit).
In order to make sure that your inputfile follows the proper
format, we strongly recommend that you make sure that your
inputfile is accepted by the driver.
Readme File
A brief summary of your program, and any further comments you
wish to make to the grader.
The assignment is worth 10 points. Eight points will be awarded based on our own evaluation of your assignment and the readme file. One additional point will be awarded fractionally based on how well your program performs on other students' test inputs. The final point will be awarded fractionally based on how well your test input fools other students' flawed programs.
The executable MergeTest is a driver which will handle reading the input, creating the initial lists, calling your routine, and then outputting the merged result.
The expected format for input is as follows (please make sure that the inputfile you submit adheres strictly to these standards!):
You will notice that this format allows you to specify a test file which involves many different merges, as demonstrated in the following example of a properly formatted input file.
5 9 12 1000 4 10 11 15 1000 3 4 1000 1000 -10 0 0 8 1000 -5 8 10 1000 -1000
The driver will create the two lists
After that, it will create two lists
Then it will merge
By default, the driver reads input from the keyboard. However, if you would like to have the driver read input from a text file, you may create such a file, and then give the filename as a single argument when starting the program (as was done in an earlier programming assignment).
As an experiment, we are trying a system to produce graphical visualizations of the before and after state of the linked list. There is no stanard graphics package included with C++, but we will be using a third party tool named Graphviz to produce postscript renderings. This software is already installed on turing.
When you type 'make' to compile your project, it builds two executables by default: MergeTest and MergeTestVisual. The latter is identical to the former except that it also produces images of the two lists just before and after the call to merge. When running this program, it will produce a postscript file merge.ps in the current directory just before calling merge. It updates that file just after calling merge. You may view that file in a separate window. For example, here is the rendering of the first test case just before the merge:
If all goes well, just after the merge, you should get the result:
Of course, if things go poorly, you might get an inconsistent state. Assuming that the call to merge returns without crashing, we will do our best to draw a flawed state, such as: