The University of British Columbia

CICS 216
Assignment #2

The Busy Russel

Objectives:

Implementation of Vectors Using Different Data Structures.

Concepts:

Fixed-Lenght Arrays.
Dynamic Arrays.
Structures.
(Dynamic) Arrays of Structures.
Linked Lists.

Fortunately, Russel could find a job in a company as a software developer. He is happy with his job, which involves writing efficient algorithms for a list of problems which he receives every Monday from his boss. There are some easy problems, and some which require more effort, and may be left over for the next week. Russel feels that if he can keep track of his job list, he can have a better performance.

Tasks:

The purpose of this assignment is to make you familiar with the concepts of dynamic data of the C++ language. The data type (linked list) you will develop in this assignment is used as the base data structure for further assignments. Therefore it is important that you don't fall behind in this assignment, otherwise you may need to work more in the later assignments to catch up.

Suppose that the each problem given to Russel has a unique ID (of type int), a description (of type string), and a deadline (of type Date: see Assignment#1). Russel wants to store these information for later access. He needs to be able to add/remove jobs from his job list. We will use 4 different data structures for this purpose, and will explore their advantages and limitations.
Fixed-Length Arrays
Arrays of Structures
Dynamic Arrays
linked lists

Fixed-Length Arrays:

The simplest way to store the job list is to define 3 sufficiently large arrays,
int jobID[MAX_JOB_NUM];
string jobDescription[MAX_JOB_NUM];
Date jobDeadline[MAX_JOB_NUM];
where MAX_JOB_NUM is the capacity of arrays defined as, e.g.
#define MAX_JOB_NUM 100
at the beginning of the source code. Adding/Removing a job to/from the end of arrays is easy and efficient, e.g.
jobID[++totalJobs] = newJobId; for adding, and --totalJobs; for removing, where totalJobs indicates the number of jobs already in the array.
Howevever, there are three major drawbacks here:
  1. We have defined 3 different arrays, despite the fact that the values stored in them are dependent. It is easy to confuse a particular jobId with another job's description, if add and remove are not performed correctly.
  2. The capacity is fixed. Nothing can be done if suddenly, Russel goes to a short vacation, and needs to store MAX_JOB_NUM+1 jobs!
  3. The amount of effort (complexity) needed to remove a job from the middle of the array is high.
    (Optional: Try to implement a void remove(int fromWhere) function. You can easily see that its average complexity is 1/2*MAX_JOB_NUM for a full array).

Arrays of Structures:

To tackle problem 1, we use a C struct Job with three elements: ID, Description, and Deadline. Note that we don't use a class here, because our purpose is just to link these three elements, and not to define any functions for manipulating them. Then we can have a single array:
Job jobList[MAX_JOB_NUM];
Please implement the add and remove fuctions to/from the end of jobList .

Dynamic Arrays:

To remove the second limitation of fixed-length arrays, we need to use a dynamic array to store the items. Such an array is declared as a pointer, and its space is allocated later by the class member functions. Usually, the class keeps two constant values: the initial size of the array and the increment factor. The constructor initializes the array with space equal to the initial size. The add operation checks the available space before it adds any element in the vector. If the array is full, it expands it by the increment factor. In your case, you should set the initial size to 5 and the increment factor to 0.2 (i.e. 20%). In addition, the class needs to keep track of the capacity of the array and the actual size of the vector, in order to determine when expansion is required. Please implement a class DynamicJobList for this purpose, and define appropriate add/remove functions (to/from the top). Also overload the [] operator, as discussed in the appendix at the end of this page. You can see that we still have a high complexity if we want to remove from the middle of the array (optional: implement it!).

linked lists:

The linked list keeps a cursor (pointer) that points to the beginning of the vector. We then can begin from this cursor, and advance to the next item and access its value. This way, the user can access all the vector values in the order in which they are stored in the vector. The linked list data structure significantly reduces the complexity of adding/removing to/from arbitrary locations, Because the pointers can be assigned to the new values in the vector (see Unit#3 course notes (Page 17) for more details). It also has dynamic capacity (why?).

To implement the LinkedJobList class, first modify the struct Job to contain appropriate next pointers.
It is extremely important to always set these next pointers to point to appropriate Job (or NULL) during the implementation of all functions in the LinkedJobList class. Then define in the class
i) the cursor which points to the beginning of the linked list (i.e., Job *cursor ), and
ii) int length to indicate the number of elements in the vector.
Recall that you can iterate on a linked list by using somthing like:
for (Job* j=cursor; j!=NULL; j=j->next) { ... }
Our LinkedJobList class should provide the following operations:

Appendix: Overloading the [] operator

To allow the user to use the the indexing operator []  to access the i-th value of a dynamic array, you need to overload  the [] operator in the DynamicJobList, LinkedJobList classes. Define the operator  in such a way that a call  to v[i] will return the i-th value stored in the vector v. The acceptable indices are the integers from 0 to length-1. If the index is outside these bounds the program should print an  error  message and terminate the execution. Note that the operator call v[i] does not allow the user to change the  i-th location in the vector; it just returns the value.

In summary, you should do the following:

Further Readings:

Learn to use VC++ Debugger and Locate the Runtime Errors.
C++ STL Vector Class.
C++ STL List Class (Uses Doubly Linked Lists for Enhanced add/remove Efficiency).