(Latest Revision: 11/19/99)

11/10/99: Took out a piece of purposeless information about how to create a deck of index cards.

11/19/99: Moved back the due date from 11/22 to 11/24

BOOK-COLLECTION PROGRAM


DUE DATES:

Please read the class documents entitled:

programAssignmentRules, sampleProgramSubmission-level01, sampleProgramSubmission-level02, sampleProgramSubmission-level03, howToMakeTestScript-level01, sampleTestScript-level01, sampleTestScript-level02, and sampleTestScript-level03

before beginning to do this programming assignment. You will find the documents under "CourseDocuments" in the class web space. Also, be sure to ask questions in class!

Write a simple program to maintain a list of books for a personal library.

Basically, the program must accept commands to make insertions and deletions in the list, and simultaneously maintain the list in alphabetical order for THREE keys: title, author, and subject.

DATA STRUCTURES:

You can simulate an "index card" containing information about a book as a C struct. Here is a C declaration that illustrates:
#include <string>

typedef struct
  {
    string title ;
    string author ;
    string subject ;
  } 
   indexCardType ;

The list structure of the implementation must be that of a binary search tree. Since there are three keys, the structure will actually be a "multi-tree." You must use three sets of pointers: left and right title; left and right author; and left and right subject.

When the program adds another book to the collection it allocates a node that contains room for the book information and the three sets of pointers. It then copies the book information (title, author, and subject) into the node and links the node into the multi-tree -- really three trees in one.

INPUT:

This program will begin with an empty list, and will accept commands from the standard input to insert, delete, list the cards in order by one of the keys, or quit.

In order to make the program easy for me to test, it must be able to work correctly when operated using indirection. For example, I want to be able to test your program by typing

a.out < mytestinputfile > mytestoutputfile

where mytestinputfile is a file containing a series of the commands described in the next section. I don't have time to do much testing in "interactive mode".

COMMANDS:

Input to the program will consist of a series of commands in the following forms.

Note: arguments like <subject> stand for VARIABLES which are strings terminated by end-of-line. Strings will have arbitrary amounts of leading, embedded, and trailing white space. The internal representation of the strings however are required *not* to have leading or trailing whitespace, and to have only single blanks between "words." (Here, a "word" is a contiguous string of characters that are not white space -- so something like the L. in L. Frank Baum would be called a word.)

Command names given below, like Insert, are literals and will appear in the input file exactly as they appear below.
COMMAND FORM:
Insert <author>
<title>
<subject>
SPECIFIC EXAMPLE:
Insert L. Frank Baum
    The   Wizard of  Oz
Children's Fantasy
As stated earlier, this command adds another book to the collection. It allocates a node, copies the data into it, and links the node into the three trees ordered by author, subject, and title. Note that you are required to put the *same* node simultaneously into three tree structures. There will be class discussion about what is involved in doing this.

Note that in the real world two books can have the same author, or the same title, or the same subject. Your program must do something reasonable when there is a "tie" between two keys. To avoid some of the potential technical details, however, we will assume that titles are unique.

If and when the insertion is sucessfully completed, the program must print a message saying so to standard output. Include some information about WHERE in the list the new indexCard got inserted, for each key -- this will be good to know for debugging purposes. For example, if the Baum book gets inserted in the author list as the right child of a book by Baker, it would be nice if the message said that. It would give us immediate confirmation that the insertion was done properly.
COMMAND FORM:
Delete  <title>
SPECIFIC EXAMPLE:
Delete  The    Wizard of Oz
This command must cause a search for the named book. If the book is found, the pointers must be updated so that the book is now deleted from all three trees.

Note: You have to remove the node from three trees, one after the other. This constraint introduces a subtle difficulty: You can't use the "copy trick" described in our textbook to simplify the case of deleting a node that has two children. Do you see why?

We will discuss this issue in class.

An appropriate message must be printed when a successful deletion is done.

If the book is not found, the procedure must leave the list and pointers unchanged, and simply print an appropriate message to the user.
COMMAND FORM:
List by <key>
SPECIFIC EXAMPLE:
List by author
This command must print out the contents of each indexCard in the list, in order according to the indicated key. The key can be either author, title, or subject. Use an attractive format.

If the list is empty, an appropriate message must be printed.
COMMAND FORM:
Quit
SPECIFIC EXAMPLE:
Quit
This command must cause the program to Halt. Print a brief acknowledgement message before quitting -- like "Quit command received ... exiting."

NOTE ON DESIGN:

The "right" way to do this program is to implement the list as an abstract data type that gives you all the basic operations you need for implementing the commands you must support. We will discuss this in class.

Consider implementing the basic node data in this manner:
#include <string>
#include <iostream.h>

#define MAX_CARDS 50
#define NUM_PTRS 6

typedef struct
  {
    string title ;
    string author ;
    string subject ;
  }
   indexCardType ;

struct TreeNodeType ;
typedef TreeNodeType *ptrType ;

enum ptrNameType {leftAuthor, rightAuthor, leftTitle,
                   rightTitle, leftSubject, rightSubject} ;

typedef ptrType ptrArrayType[NUM_PTRS] ;

struct TreeNodeType
{
  indexCardType Item ;
  ptrArrayType pointerTo ;
} ;

int main()
{
  TreeNodeType node ;

  node.Item.title = "Hello World!" ;
  node.pointerTo[leftSubject] = NULL ;
  cout << node.Item.title << endl ;
  if (node.pointerTo[leftSubject] == NULL)
  cout << "The pointer is NULL." << endl ;
  else cout << "The pointer is not NULL." << endl ;
  return 0;
}
This is a pretty "nifty" way to do things. You can pass a variable of type ptrNameType as a parameter to a function. This can facilitate writing a single procedure to do all binary search tree insertions, a single procedure to do all binary search tree deletions, and so on.

The alternative of having three separate sets of functions for the three trees is "definitely not the best" design choice.

The values of ptrNameType can be passed to a function to specify which pair of pointers to use when searching and re-linking. Furthermore the values of ptrNameType are array indices that will give your function direct access to the pointers that the function needs to use and change. See how the pointer is accessed in the main program above? Your program can do all retrievals, insertions and deletions with similar code. If you use this idea, I think it will make the program much easier to design and build.

TESTING:

You will need to do some careful testing.

Test all the functions of the program.

Tests must demonstrate that your program works correctly when it deletes in the no-child, one-child, and two-children cases. In particular, you have to devise a test that shows your program is not susceptible to the problem involving the "copy trick" that I mentioned above.

In your test script, you need to print out all the books in all three orders after each insertion and each deletion.

The test script will count heavily on this assignment, so do a good job. Also make sure that the script is very easy for me to read and understand (in my 79-column display).