Project #2: Templated Circular, Doubly Linked List
Background
Project #2 will simulate the Josephus permutation, a mathematical problem modeled after a legend about a small band of zealots in the first century that withstood the Roman army for a long period of time by entrenching themselves on an plateau fortress in the desert mountains. The legend states that after inflicting heavy losses on the Romans, their supplies finally gave out. Becoming weak and unable to fight they made a suicide pact to die rather than be conquered. One of the zealots was Josephus Flavius. Josephus did not prefer death to surrender so he devised a suicide ritual that gave himself and his best friend a way to survive. Josephus suggested they all stand in circle and go around the circle killing every third man until everyone is dead. Josephus was a mathematician and made sure that himself and his friend stood in the two spots that would be the last to kill themselves. Then after everyone else had died, he and his friend surrendered to the Romans. Josephus went on to become one of the greatest historians of that century writing "the Antiquities" and other famous works that have endured till today. The Josephus problem is the prediction of who will be the last man standing given a circle of N men, starting at a given man, and killing every k'th man in some direction CLOCKWISE or COUNTERCLOCKWISE. Our program will not attempt an analytical solution. We will simulate the execution (no pun intended) of the algorithm until only one man remains.
Assignment
Copy the solution executables to THOT. They will not run on any other machine. You must issue a chmod command to make those exe files executable.
% chmod +x string-Josephus.exe
Now look at the sample out run files to see how to run these solution execs on the commnd line. You can run my solutions under valgrind. I compiled with the -g flag so that should an error or leak occur you will see the source line number and can report it to me. You should run my solutions then run yours and compare the ouputs. They must be identical.
You are given several files to work with. The first pair of files cdll.c and cdll.h taken together represent the interface and implementation of a Circular Doubly Linked List. This list will simulate the circle of zealots in the Josephus legend. A circular linked list differs from a plain linked list in that the tail element points back to the first element again. Thus when traversing a circular list you must be careful not to run around in circles.
CIRCULAR LINKED LIST
Our list is also doubly linked which means every list element has a next pointer and a prev pointer. Each element points forward and backward. This list can be traversed in either direction.
CIRCULAR DOUBLY LINKED LIST
Lastly, our list will also be templated. By templated, we mean that this list is a generic container. Each list element has a pointer named data that points off to some data object associated with that list element. That pointer is of type void *. The void * type is a pointer to any type. Our linked list is not limited to being a linked list of strings or a linked list of ints, or a linked list of Foo structs. Our list can store any pointer type because our void * data pointer can have the address of any data type stored in the heap. In effect, the void * type turns off strict type checking by the compiler. No errors or warnings will be generated because of passing various types. The only restriction is that whatever you pass in must be a pointer, not a primitive.
Implications of using void * for Templating
Lets think of our cdll.h and cdll.c files as comprising a class - like in Java. Lets call this "class" CDLL. Classes combine methods (functions) and data. Our CDLL class uses function pointers instead of actual functions because C does not permit functions to be declared inside a struct. Now consider that our list elements can store the address of any type of object in the heap. Suppose that we want to have a function in our CDLL class that prints out the list by printing out the data hanging off each list element. We now have a problem. Our print function has to know the precise data type of the object being printed at each element of the list, but in order to be generic we cannot have any code written inside our CDLL class that makes assumptions about the specific data that is hanging off the list because we are writing only one version of cdll.c and cdll.h The solution to the problem is to have each of the various main programs write their own version of our print function that correctly prints the specific data that it has put into our generic list. Inside the CDLL class there will be a function pointer field named printData. Somewhere early on in each main program this field will be initialized with a pointer to an actual function that correctly prints the data that is about to be put into the list by that main program.
Lets assume we have three different main programs that each wants to use our generic CDLL class to declare a linked list structure.
- string-Josephus.c: uses our CDLL to store a pointer to a string in the data field of each list element
- student-Josephus.c: uses our CDLL to store a pointer to a Student struct in the data field of each list element
Somewhere in each of these 2 programs, a version of some function named "print_???" must be written. A first pass at writing the functions might look something like this:
- string-Josephus.c: in main might write a function such as:
void printString( void * data, int mode ) /* mode parameter explained later */
{ mode=mode; /* just to shut up the compiler warning about unused arg */
printf("%s ", (char*)data);
}
- student-Josephus.c: in main might write a function such as:
void printStudent( void * data, int mode )
{
STUDENT *s = (STUDENT*)data;
if (mode==BRIEF)
printf("%s ", s->andrewID ); /* if brief mode then just print the "key" field of the struct */
else
printf("%s %s %d %f, %s ", s->andrewID, s->name, s->yrOfGrad, s->gpa, s->major ); /* otherwise print all fields */
}
Notice what all these function have in common:
- prototype the incoming data as (void *) because we can only have one function pointer stored in the CDLL class - it must be completely generic and have no mention of specific data types that might actually be stored.
- cast the data back to its actual type before printing it
Be sure to implement your circular doubly linked list as illustrated above. DO NOT USE A HEADER/SENTINEL/DUMMY/EMPTY Node in your CDLL.Every list element is an actual data holding element.
What you'll need to start
The CDLL "class"
- ALREADY WRITTEN: cdll.h The interface file for the templated list and list node.
- YOU FILL THIS IN: cdll.c a starter file for the implementation of the templated list.
The string main program that uses the CDLL "class"
- string-Josephus.c The main program - you fill in the missing code
- strings.txt The input file for this program - you should make up others and test your code
The Student main program that uses the CDLL "class"
- student-Josephus.c The main program - you fill in the missing code
- students.txt The input file for this program - you should make up others and test your code
HERE ARE SOME CONFIGURATIONS I WILL USE TO TEST YOUR PROGRAM
- I'll test YOUR ./string-Josephus.exe strings.txt 2 CW (starting with: Lee) run MY ./string-Jospehus.exe on this configuration and compare output to yours
- I'll test YOUR ./string-Josephus.exe students.txt 3 CCW (starting with: bjoy ) run MY ./student-Jospehus.exe on this configuration and compare output to yours
Complete the two main program files. You are just to fill in the print compare and free functions. Most of the work will be in the "cdll.c" file as you fill out the operations of loading the list, deleting elements from the list and so on. Compare your solution's outputs to my executable's outputs
Handing in your Solution
For this assignment, handin is expecting just 3 files:
- string-Josephus.c (you fill in print, compare and free )
- student-Josephus.c (you fill in print, compare and free )
- cdll.c (fill in all the empty list op methods )