CS 112
Spring 2019

Old version

This is the CS 112 site as it appeared on May 8, 2019.

Problem Set 5

due by 11:59 p.m. on Wednesday, March 20, 2019

Important

Don’t forget that each of your methods should be preceded by a comment block that explains what your method does and what its inputs are. You should include a comment at the top of each Java file, and you should use goodprogramming style more generally.

In addition, you should continue to follow the other guidelines that we gave you in the prior problem sets. In particular, see here.

Preliminaries

In your work on this assignment, make sure to abide by the collaboration policies of the course.

If you have questions while working on this assignment, please come to office hours, post them on Piazza, or email instructor or TF.

Make sure to put all your work for this problem set in a local folder named ps5 and submit your work using gsubmit, following the instructions found at the end of the assignment.


Part I

55 points total

Problem 1: Comparing two algorithms

9 points; individual-only

Put all of your work for this problem in a plain-text file named ps5pr1.txt.

Suppose that you want to find the largest element in an unsorted array of n elements. Algorithm A searches the entire array sequentially and keeps track of the largest element seen thus far. Algorithm B sorts the array using mergesort, and then reports the last element as the largest.

  1. What is the big-O time efficiency of Algorithm A in the best, average, and worst cases? Explain your answer briefly. (You do not need to implement either algorithm. We just want you to analyze them.)

  2. What is the big-O time efficiency of Algorithm B in the best, average, and worst cases? Explain your answer briefly.

  3. Which algorithm is faster? Explain briefly.

Problem 2: Mergesort

9 points; 3 points for each part; individual-only

Put all of your work for this problem in a plain-text file named ps5pr2.txt.

Given the following array:

{24, 3, 27, 13, 34, 2, 50, 12}
  1. If the array were sorted using the version of mergesort presented in lecture, what would the array look like after the completion of the second call to the merge() method—the method that merges two subarrays? Note: The merge method is the separate helper method; is not the recursive mSort method.

  2. What would the array look like after the completion of the fourth call to the merge() method?

  3. The initial call to the recursive mSort() method is made from within the mergeSort() “wrapper” method. This initial call to mSort() is not a recursive call, because the method is not calling itself. Rather, all recursive calls to mSort() are made from within mSort().

    Assuming that the array has at least two elements, the initial invocation of mSort() makes two recursive calls (which in turn lead to other recursive calls, and so on). Starting with the initial array above, what would the array look like after the completion of the first of these two recursive calls?

Important

There will be no partial credit on the above questions, so please check your answers carefully!

Problem 3: Practice with references

8 points total; individual-only

Put all of your work for this problem in a plain-text file named ps5pr3.txt.

A doubly linked list consists of nodes that include two references: one called next to the next node in the linked list, and one called prev to the previous node in the linked list. The first node in such a list has a prev field whose value is null, and the last node has a next field whose value is null.

The top portion of the diagram below shows a doubly linked list of characters that could be used to represent the string "cat".

Each of the nodes shown is an instance of the following class:

public class DNode {
    private char ch;
    private DNode next;
    private DNode prev;
}

(In the diagram, we have labeled the individual fields of the DNode object that contains the character 'c'.)

In addition to the list representing "cat", the diagram shows an extra node containing the character 'h', and two reference variables: y, which holds a reference to the second node in the list (the 'a' node); and x, which holds a reference to the 'h' node. The diagram also shows memory addresses of the start of the variables and objects. For example, the 'c' node begins at address 0x400.

  1. (3 points) Complete the table below, filling in the address and value of each expression from the left-hand column.

    You should assume the following:

    • the address of the ch field of a DNode is the same as the address of the DNode itself

    • the address of the next field of a DNode is 2 more than the address of the DNode itself

    • the address of the prev field of a DNode is 6 more than the address of the DNode itself, which means that it is also 4 more than the address of the next field.

    Here is the table:

    expression         address       value
    ------------------ ------------- -----------
    x                                
    x.ch                             
    y.prev                           
    y.next.prev                      
    y.prev.next                      
    y.prev.next.next
    
  2. (2 points) Write a Java code fragment that inserts the 'h' node between the 'c' node and the 'a' node, producing a linked list that represents the string "chat".

    Your code fragment should consist of a series of assignment statements. You should not make any method calls, and you should not use any variables other than the ones provided in the diagram. You may assume that your code is part of the main method in the DNode class, and thus it has direct access to the private fields of the DNode objects.

    Make sure that the resulting doubly linked list has correct values for the next and prev fields in all nodes.

  3. (3 points) Suppose you have a doubly linked list of DNode objects in which the prev references have the correct values but the next references have not yet been initialized.

    Write a static method called initNexts() that:

    • takes one parameter, a reference to the last node of the linked list

    • traverses the linked list from back to front, filling in the next references

    • returns a reference to the first node of the linked list.

    You may assume that there is at least one node in the list.

    You do not need to code up this method as part of a class; simply include it in the same file as your other problems for this question. You may assume that the method is part of the DNode class.

Problem 4: Choosing an appropriate list implementation

12 pts. total; 4 pts. each part; individual-only

Put all of your work for this problem in a plain-text file named ps5pr4.txt.

In lecture (after break), we will look at two different implementations of the list ADT: ArrayList and LLList. For each of the following applications, decide which list implementation would be better for that particular application. Your should consider both time efficiency and space efficiency, and you should assume that both implementations have an associated iterator like the LLListIterator that we discussed in lecture. Explain your answers.

To fully answer this question, you should wait until after break when we cover these two implementations, however, the question is asking to think about the difference between using an array or a linked list as an underlying datastructure.

  1. You need to store information about the gardening tools that you sell in your online store. To do so, you maintain a list of product records, each of which contains information about a single type of product, including how many copies of it you have in stock. You don’t tend to change the types of tools that you sell, and thus items are seldom added or removed from the list. However, you need to update a product’s record whenever your inventory of that product changes (e.g., because someone purchases one!). A product’s position in the list is also its product ID, and therefore updating a record involves using the product ID to get the corresponding record and modifying its contents.

  2. You need to maintain a list of tweets that are made by government officials in the current week. The number of tweets can vary widely from week to week in a way that is hard to predict. You start with an empty list at the start of the week, and as tweets are made you add them to the list. You need to frequently display the tweets in reverse chronological order – from most recent to least recent.

  3. You are responsible for maintaining a monthly list of events for an online arts calendar. The number of events is fairly consistent from month to month. Events are added to the list in chronological order, and you need to display them in that same order.

Problem 5: Computing Big-O

12 pts. total; 4 pts. each part; individual-only

Put all of your work for this problem in a plain-text file named ps5pr5.txt.

  1. Express each of the following functions using Big-O notation. Represent your answer as an equality (e.g., p(n) = O(n^2)). The answer for function a(n) is given.

    • a(n) = 8n + 3 = O(n)
    • b(n) = 12n + n^2 + 64
    • c(n) = 2log(n) + n
    • d(n) = log(n) + 2
    • e(n) = 2n
  2. Using Big-O notation, determine the number of times the function count is called when the following code fragment runs, in terms of the variable n.

    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            for (int k = 0; k < j; k++)
                count();
    
  3. Using Big-O notation, determine the number of times the function count is called when the following code fragment runs, in terms of the variable n.

    for (int i = n; i > 0; i/=2)
        for (int j = 0; j < n; j++)
            for (int k = 0; k < 1000; k++)
                count();
    

Problem 6: More Sorting practice

5 points; individual-only

Put all of your work for this problem in a plain-text file named ps5pr6.txt.

Important: When answering these questions, make sure to apply the versions of these algorithms that were discussed in lecture. The Java code for each algorithm can be found in our Sort class.

Given the following array:

{14, 7, 27, 13, 24, 20, 10, 33}
  1. If the array were sorted using quicksort, what would the array look like after the first call to the partition method?

  2. If the array were sorted using quicksort, what would the array look like after the second call to the partition method?

Important

There will be no partial credit on the above questions, so please check your answers carefully!


Part II

40 points total

Problem 1: A merge-like approach to finding the intersection of two arrays

20 points; individual-only

In a file named MergeIntersect.java, implement a static method named intersect that takes two arrays of integers as parameters and uses an approach based on merging to find and return the intersection of the two arrays – i.e., all values that are found in both arrays.

More specifically, you should do the following:

  1. Begin by creating a new array for the intersection. What should the length of this array be?

  2. Use one of the more efficient sorting algorithms from Sort.java to sort both of the arrays.

  3. Find the intersection of the two arrays by employing an approach that is similar to the one that we used to merge two sorted subarrays (i.e., the approach taken by the merge method in Sort.java). Your method should not actually merge the two arrays, but it should take a similar approach—using indices to “walk down” the two arrays, and making use of the fact that the arrays are sorted. As the elements of the intersection are found, put them in the array that you created at the start of the method.

    For full credit:

    • The intersection that you create should not have any duplicates.

    • Your algorithm should be as efficient as possible. In particular, you should perform at most one complete pass through each of the arrays.

  4. At the end of the method, return a reference to the array containing the intersection.

  5. Add test code for your method to the main method. Recall that that you can use the Arrays.toString() method to convert an array to a string; import the java.util. package to gain access to the Arrays class.

Here are some expected results:

> int[] a1 = {10, 5, 7, 5, 9, 4};
> int[] a2 = {7, 5, 15, 7, 7, 9, 10};
> int[] result = MergeIntersect.intersect(a1, a2);
contents of result: { 5, 7, 9, 10, 0, 0 }

> int[] a3 = {0, 2, -4, 6, 10, 8};
> int[] a4 = {12, 0, -4, 8};
> int[] result = MergeIntersect.intersect(a3, a4);
contents of result: {-4, 0, 8, 0}

Notes:

Problem 2: Rewriting linked-list methods

25 points; individual-only

In lecture, we’ve been looking at linked lists of characters that are composed of objects from the StringNode.java class. The class includes a variety of methods for manipulating these linked lists, and many of these methods provide functionality that is comparable to the methods found in Java String objects.

Some of the existing StringNode methods use recursion, while others use iteration (i.e., a loop!). In this problem, you will rewrite several of the methods so that they use the alternative approach.

Guidelines

  • The revised methods should have the same method headers as the original ones. Do not rename them or change their headers in any other way.

  • Make sure to read the comments accompanying the methods to see how they should behave.

  • Because our StringNode class includes a toString() method, you can print a StringNode s in order to see the portion of the linked-list string that begins with s. You may find this helpful for testing and debugging. However, you may not use the toString() method as part of any of your solutions.

  • You should not use the existing getNode() or charAt() methods in any of your solutions, because we want you to practice writing your own code for traversing a linked list.

  • Make your methods as efficient as possible. For example, you should avoid performing multiple traversals of the linked list if your task could be performed using a single traversal.

  • Another useful method for testing is the convert() method, which converts a Java String object into the corresponding linked-list string.

  • There is existing test code in the main() method. Leave that code intact, and use it to test your new versions of the methods. You are also welcome to add extra test code to this method, although doing so is not required.

  • You can also test your revised methods from the Interactions Pane in DrJava. For example:

    > StringNode s1 = StringNode.convert("hello");
    > StringNode.length(s1)
    5
    
  • A general hint: Drawing diagrams will be a great help as you design your revised methods.

  1. Before you get started, we recommend that you put a copy of the original StringNode class in a different folder, so that you can compare the behavior of the original methods to the behavior of your revised methods.

  2. Rewrite the length() method. Remove the existing recursive implementation of the method, and replace it with one that uses iteration instead.

  3. Rewrite the toUpperCase() method. Remove the existing iterative implementation of the method, and replace it with one that uses recursion instead. No loops are allowed.

  4. Rewrite the printReverse() method so that it uses iteration. This method is easy to implement using recursion–as we have done in StringNode.java–but it’s more difficult to implement using iteration. Here are two possible iterative approaches, either of which will receive full credit:

    • reverse the linked list before printing it: This approach is the trickier of the two, but we recommend it because it uses less memory, and it will give you more practice with manipulating linked lists. Remember that you may not use the toString() method for this or any other method. In addition, you should not use the print() method. Finally, don’t forget to restore the linked list to its original form!

    • use an array: Create an array of type char that is large enough to hold all of the characters in the string and use it to help you with the problem.

  5. Rewrite the removeFirst() method. Remove the existing iterative implementation of the method, and replace it with one that uses recursion instead. No loops are allowed.

  6. Rewrite the copy() method. Remove the existing recursive implementation of the method, and replace it with one that uses iteration instead.

Remember: Drawing diagrams will be a great help as you design your revised methods!


Submitting Your Work

Submission Checklist:

Follow the instructions and submit the following files:

Warnings

  • Make sure to name the folder ps5.

  • Make sure to use these exact file names as specified or we will not be able to find your files and grade them.

  • Make sure that you do not try to submit a .class file or a file with a ~ character at the end of its name.

  • If you make any last-minute changes to one of your Java files (e.g., adding additional comments), you should compile and run the file after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.