Searching for a Better Way

Assignment 4

Searching through data is a frequent necessity in data processing; finding what you want quickly is typically the goal. Yet, even with a fast machine, the algorithm employed is the major determiner of data retrieval speed. This project will give you practice in using two searching techniques, ProxmapSearch and ChainSearch, and helps give you a feel for the practical meaning of O-notation and “improvement by a constant factor.” You’ll practice code optimization, a commonly used (and abused) programming activity. This lab also demonstrates how programs can be used as test vehicles to answer design questions for larger programs; it also provides practice in preparing reports based upon program-generated data.


Background

Imagine you’ve been hired as a “data jockey” by a national chain of retail stores, due to open shortly. Your boss briefs you on your first assignment:

Marketing has (what it thinks) is a brilliant approach to notifying people about these new stores: In addition to standard print and Web advertising, telemarketers are going to telephone and text homes within a ten-mile radius of each new store to personally invite consumers to “come on in” during the grand openings.

The marketing research branch has prepared a list of the 5-digit ZIP codes which correspond to these invitation areas; it has obtained a file that lists, for every phone group, a corresponding ZIP code. A phone group consists of a three-digit area code followed by a three-digit phone prefix (the first three digits of the phone number). Since one phone group might be found in several ZIP code areas, there may be several entries in the file that have the same phone group, but have different ZIPs. And clearly there could be several different phone groups in the same ZIP code.

Marketing calls this list of ZIP codes with their phone groups the master file. Details of its structure are below.

Marketing has also procured a list of telephone customers' names and phone numbers, in phone number order; this is the phone list.

Marketing wants a look-up program that will print on the screen, in an easy-to-read format, the phone groups that are in a chosen ZIP code. A telemarketing coordinator will use this program to assign a ZIP's phone groups to telemarketers, who will then use the phone list to make calls and texts to potential customers (who are not on the Federal Do Not Call List). Always time-pressured, marketing wants a request for a ZIP codes#146;s phone groups filled as quickly as possible.

This is not a one-time program. As calls and texts to each ZIP code’s list are completed, another set of numbers will be needed; as new stores open, marketing will need additional ZIP codes’ phone groups.

Requirements and constraints known at this time:


Your assignment

Your boss tells you that your task, perhaps surprisingly, is not to write this program; rather, it is to investigate and report on which data structure ought to be used to make the search for a ZIP code, and returning a list of the phone groups associated with it, as fast as feasible. The program requirements team will use your results in determining the requirements for the search algortihm they give to the design and programming teams. The boss also admonishes you that time (as always) is of the essence, so you are to focus your efforts only on comparing ProxmapSearch and ChainSearch; in particular, you are not to go off looking at other search approaches.

You are to report your results in this company-standard format:

  1. Title Page
  2. Table of contents. Page numbers can be any form you like as long as a reader can get to a page quickly.
  3. Problem Statement. A discussion of what you are investigating, and the results that you hope to achieve.
  4. Method. What you tried when working toward a solution to the problem.
  5. Results. What you discovered, completely and clearly presented.
  6. Conclusions and Recommendations. What you conclude from your investigation, and what you recommend to be done.
  7. Appendices. Any supportive material, too detailed or technical to be included in the main body of the text, including references to programs and their output.

Requirements, hints, and suggestions

Requirements given in this section are stated explicitly (by such phrases as “We require you to...”). The hints and suggestions here are just that; they are not requirements. As long as what you do meets the requirements, you may do and name things differently, even use a completely different approach.

  1. We require you to code up classes for the proxmap and chain list structures. We have provided skeletons for Proxmap and ChainList classes to get you started, in the SearchForABetterWay project zip file; you may change or remove any of the private items, and add in other private items, as you see fit, but be sure to use good style. Don’t change any of the public signatures. In particular, avoid using Java features that aren’t really needed to get the job done cleanly and quickly, and may unnecessarily add to running time or memory usage. (For instance, we did not use the Java LinkedList class for the chains of the chain list; LinkedLists are doubly-linked and we only need singly-linked lists. Using our own singly-linked list saves the space used by the “previous” pointers of a LinkedList, thereby dropping the memory requirements of a chain by about one-third, a significant savings.)

    Also in the project file is a sample master file TestZIP.txt, of about 97,000 lines. We encourage you to use it, portions of it, and larger files based on it, as appropriate, when testing and timing your routines. (Of course, use small files for your first tests; when things look like they are working, move on to larger test files.)

    With the exception of ArrayList, you are not allowed to use the predefined Java “collection” classes, such as java.util.TreeMap, in your solution. (The collection classes are the ones that store a collection of data, and include such classes as LinkedList, HashMap, Vector, Hashtable, and TreeMap.) Among other things, these classes are overblown for our needs, and so unnecesarily increase memory usage or the time to complete the searches.

  2. You need methods to add the data from the master file to the proxmap or chain list and to search those structures. Write four methods to accomplish this task; call them Proxmap.buildList() and Proxmap.lookup() (to build and search the sorted array) and ChainList.buildList() and ChainList.lookup() (to build and search the chain list). Signatures for these methods are provided in the skeleton classes we’ve provided.

  3. To test ProxmapSearch, write a method called testProxmapSearch that takes as parameters the name of the master file and the name of a text file that has a list of ZIP codes for which to search. testProxmapSearch builds the proxmap using the master file data and reports how long that took. Then testProxmapSearch records the time it takes to search for the passed-in ZIP codes (including the time it takes to return its list of phone groups or throw an exception if the ZIP code is not found) divided by the number of searches done; it reports this average search time and exits.

    When testing chain searching, you’ll need to try out several different map key functions. The easiest way to do this is to extend from the provided abstract class AbstractMapKey a concrete class that represents a map key; do this for each map key you want to try. Then, in your test program, you construct the map key(s) you want to use and pass them in turn to the Proxmap constructor. Details on this approach are given in comments in the AbstractMapKey class.

  4. To test ChainSearch, do what you did for proxmap search: write a method called testChainSearch that takes as parameters the name of the master file and the name of a text file that has a list of ZIP codes for which to search. (Make sure this file has the same format as the one used with testProxmapSearch, so the comparison is fair). Then build the chain list using the master file data and report how long that took. Then, as with testProxmapSearch, testChainSearch reports the average time it takes to search for a ZIP code in the list of passed-in ZIPs and exits.

    As with proxmap search, you’ll need to try out several different map key functions to see which produces the best results. Note that the map key which produces the best proxmap search may be different than the one that produces the best chain search.

  5. We require that you write a driver program that causes your testing methods to be called with various sizes of master files, with master files containing various distributions of keys, with several map key methods and with various sizes of, and distributions of, ZIP codes in the file that lists the ZIPs for which to search. By having the driver call your test routines repeatedly with well-chosen combinations of these choices, you can have it produce a file containing all of your results—and if you format the file well, its data can be pasted directly into a spreadsheet for further analysis. This approach will save you significant time over entering choices via the keyboard, one set at a time, and then copying the results from the screen by hand into a spreadsheet or your report.

    By choosing your test cases so they illuminate distinct behaviors, rather than just repeatedly looking at the same sort of behavior, you can save yourself numerous tests and lots of work. For example, the number of items in the proxmap or chain list, which is determined by the number of lines in the master file, could easily affect the performance of the search. One good set of sizes for the master file is {100, 500, 1000, 10,000, 100,000, 250,000} records. These sizes more than cover the sizes your boss said were possible—they allow a safety margin: if the specs change somewhat, our code should still work. We require that you test your code with master files of the aforelisted sizes. Include whatever additional sizes you think are needed to gauge the relative performance of ProxmapSearch and ChainSearch. If your program runs out of memory for lists beyond a certain size, be sure to report that finding! But we must say that a good implementation of these algortihms should not run out of memory for sizes up to at least 250,000.

    As for the searches that will be done during the business day, three scenarios come to mind (you might think of others). The first is that a telemarketer will focus on one store opening, then another and then another, and so one. That would imply that the ZIP codes used in the search would be in groups that are numerically near each other, as ZIP codes are roughly assigned in ascending order as one moves from east to west across the U.S. So run tests where a group of the ZIP codes are numerically close to each other, then followed by a different group are close to each other (but not close to the first group) and then another such group, and so on.

    Another scenario is where an unplanned search for one ZIP code is needed, then nothing happens for a while, then another ZIP code is checked, and so on. This would lead to a test file where there are a number of ZIP codes where each one may or may not be numerically close to the one preceding it. Run a test using such a group of codes.

    The third situation is a mixture of the first two: the coordinator looks up a bunch of ZIPs for a store, then one ZIP for a query that has come up, then perhaps another ZIP code, then perhaps another store’s group, and so on. Run at least one test with a file of ZIP codes that represents this situation.

  6. For the map key, try at least these two approaches: (1) mapkey(key) = key (that is, use the ZIP code) and (2) mapkey(k) = int(key/100) (that is, the first three digits of the zip code). Again, try others you think appropriate to produce as fast an approach as feasible.

  7. Run the test program with good test data; analyze the results; write the required report. The report should be as clear and well written as you can make it. We encourage you to use the features of Microsoft Office or other productivity tools to help you with your presentation. You must include tables of times used by various approaches, along with other appropriate data and discussion, to support your conclusions; we also require that you present your results graphically— it’s much easier to discern patterns in the data when looking at graphs than at tables. In the appendix, include the names of the files in which your programs and results can be found; of course, turn those files in with your report, as part of your project.

  8. Finally and importantly: Don’t get so wrapped up with the experimentation that you leave no time to write your report!


Timing the search routine

Java has a few different library classes that can help you time how long it takes to do a particular search. As we suggestedin Assignment 2, using the System.currentTimeMillis( ) provides an easy way. When the task begins, do this:

long startTime = System.currentTimeMillis();

...and when it ends, do this:

long endTime = System.currentTimeMillis();

Subtract the start time from the end time to get the elapsed time.

Remember the following:


Optional work


Deliverables

Turn in your project file, as a ZIP file, to Checkmate. Be sure it includes the following:

  1. A PDF file, or a Microsoft Word ".doc" document, containing the report of your findings and conclusions, in the format and containing the information described above. If you submit the report as a Word file, be sure you submit the report as a ".doc" file, and not ".docx"—the version of Word we can guarantee our graders can access cannot read ".docx" files. (If you are using a newer version of Word, you will need to use the Save As... command to save the docment as a ".doc", rather than ".docx", file.) Put your report in the main project folder, not a subfolder.

  2. The Java programs that you used to create the results presented in your report, and their output, in the src folder inside the project.

  3. If you completed any of the optional work, a README file, in the main project folder, that explains what features you implemented, and the approach(es) you used (e.g., the algorithms you employed) to actualize them.

Grading

Your grade for this assignment is based on your programs’ correctness and style and especially on the report’s quality—its conclusions, how well its recommendations are supported and the quality of its composition and presentation. The higher weight is on the report because the programs are just an investigative tool; what matters most is the report’s conclusions and how well those conclusions are supported. So we allocate 1 point for your ProxmapSearch working and having run the required tests of its performance, 1 point for the ChainSearch working and having run the required tests of its performance, and 2 points for the report itself. (As always, you can earn up to 1 extra point for well-done optional work, and for an amazing job on the assignment, even if optional work is not undertaken.)


Written by Norman Jacobson for ICS23 Spring 2006, March 2006
Minor revisions to clarify passages, by Norman Jacobson, November 2006
  Inspiried by the March 1997 version of the ICS23 lab exercise
    Searching for a Better Way (that used B-trees, hashing and C++)
    written by Norman Jacobson in consultation with George Lueker,
    Spring 1988
  Timing and reporting prose adapted from the September 2004
    version of the 23 exercise When to Be Quick, When to be Simple,
    written by Norman Jacobson and George Lueker, with added inspiration
    from Thomas A. Standish, Spring 1988
  Discussion of skip lists includes prose from the 23 exercise Project #3:
    Always Changing Probably
by Alex Thornton, Summer 2005 version
  SkipList Java class skeleton written by Alex Thornton, July 2005
  ChainList Java class skeleton written by Norman Jacobson, based on
    Thornton’s SkipList class, March 2006
Minor revision to introduce the term “phone group” to distinguish a prefix
  from an area code + prefix group, by Norman Jacobson, November 2006
Minor edits for clarity for ICS23 Winter 2007 by Norman Jacobson, January 2007 and
for ICS23 Winter 2008, December 2008
Added a README file to document optional work, by Norman Jacobson, January 2009
Minor edit to require Word report to be submitted as a ".doc" file, by Norman Jacobson,
February 2009
Minor typos fixed, and scenarios slightly reworded for clarity; made more explicit, via
indicating points awarded, that the report is very important as compared to just getting
the programs working, by Norman Jacobson, March 2009
Revised to include hint of using the same seed in random number generation during
debugging of the skip list, by Norman Jacobson, May 2009
Make clear turned-in results are to be ZIPped into one file; fix some typos, by
Norman Jacobson, June 2009
Replaced skip list search with ProxmapSearch, and thus the class skeleton of SkipList
with one for ProxmapSearch and updated to reflect use of Eclipse and a project file, by
Norman Jacobson, March 2010
Added direct links to the Proxmap and Chain,structure handouts, and fixed a couple
of typos, by Norman Jacobson, May, 2010
Some edits for clarity, by Norman Jacobson, June 2010, March 2011 and April 2011
Updated to allow for a report to be in pdf format, and some related minor edits, by
Norman Jacobson, May 2011