CS220 Project 3 FAQ (last update just after midnight, April 23)

This page contains questions and answers about Project 3. I will update this page as more questions arrive.

  • What should happen if we use the two-argument add method to add an element at a negative index, or at an index higher than the length of the list? Or for get/set with an illegal index?

    Your method should throw an exception.

  • Should the various methods (set, get, getIndex, etc.) be defined in the LongList class, or in its inner class?

    There must be public methods matching those signatures in the LongList class. You might choose to include helping methods in the inner class, but that implementation is up to you.

  • The assignment specification originally referred to the class you should write as both NumberList and LongList. It should be LongList, and the spec has been corrected.
  • Should we implementing merge sort for the merge method? No. You are not implementing the whole of merge sort; your merge method is not intended to sort arbitrary, unsorted linked lists. The scenario here is much more specific: given two arrays that are already sorted, combine them into a sorted list.

    So while this behavior is like one pass through the merging of two sorted sublists, there will not be the series of recursive calls to break the list down over and over.

  • How similar should our implementation for the merge method be to merge sort on arrays? There are similar ideas, but the implementation idea should be different, to take advantage of the different underlying structure of linked lists as opposed to arrays.

    The right way to imagine your merge method, is as if it were some person (let’s call them M) standing at the head of two lines of people, each line running shortest to tallest. M wants to combine the two lines into one single line, again to be sorted shortest to tallest. Does M need to look through the whole line to find the next person to add to the back of the combined line? No — M only needs to look at the first person in each line, take the shorter, and move that person to the back of the combined line.

    Implementing this behavior for M lets you take advantage of the linked nodes. Your method should keep track of the smallest as-yet-unmerged node of each of the given lists, and also of the last-so-far node of the chain of nodes for the combined list which it is building.

  • I want to assemble my LongList wrapper in a way which is different then what the specified constructor allows. That’s fine. The specification says that your class must include that list of public methods and constructor, not that it is limited to that list. If there is another constructor form which you would like to use, then by all means, do add it. Just do not omit the required constructor, or any of the required methods.
  • My tests show that I have a bug, but how do I figure out exactly where it is?

    Debugging is tricky! And there are several points to consider.

    • The first step is to figure out a minimal failing case. In some of our test examples, we used several calls to methods like add before printing the expected+actual results. That’s fine when we are first building up our understanding of the problem. But once we see that we have a bug, we need more from our tests: we need to print expected+actual results more frequently, so that we detect the error as soon as it happens, and not several method calls later.
    • Another kind of refinement to our tests is to reduce the scope of the methods they use. Think about the two versions of add — in the sample implementation in the lectures, our implementation of the one-argument version made use of the two-argument version. In a situation like that, we want to debug the two-argument version first. If we start by debugging the one-argument version, then it can be hard to know whether our problems are in with the body of the two-argument version, or with the way the one-argument version calls the two-argument version.

      Instead, we should focus first on examples with only calls to the two-argument version, then we do not have this ambiguity. Then, when we are confident that the two-argument version is fixed, we can move on to examples using the one-argument version.

      When we first write tests, it can be hard to predict which methods will use other methods. That’s OK. It is normal to expand and evolve your tests to reflect how your implementation turned out, and to focus on your actual debugging needs.

    • Once you have focused in on the problematic method call, and you want to find exactly what line of the code is going wrong, your strategy is to add temporary print statements inside your methods. Use them to make sure that you are inserting links and making other changes where you expect. A good start would be to add print statements at the beginning and end of each of the methods involved in the erroneous call, displaying the argument and result values. Then based on that, you can add more print statements to track down the problem.

      And remember to remove, or to comment out, these print statements after you fix the bug! You can always add them back in, but keep your output tidy, and remove the clutter of all that output until you need it again.

See also: CS220 homepage