(Last Revision: 11/09/2005)
Discussion of Classes
Information Hiding
The database we are working with is a multi-linked structure. It links data
together in many different ways to express different relationships among the
data elements.
We need to have one data set with three major kinds of operations implemented on this data:
- memory allocation/deallocation
- tree operations
- ring operations
It may not be in keeping with the best principles of information hiding to put
all those operations inside just one class. But if we use separate classes,
how can all the methods operate on the same data? Below I relate one way to
accomplish that. The idea is to create three classes that can all operate on
the same array of "nodes".
I build "nodes" in layers. I have a class "FamInfo" with three string data
members: one for first name, one for last name, and one for storing a search
key: the upcase version of the last name with the upcase version of
the first name appended to it. I also have a class TreeNode. Each TreeNode
contains a "FamInfo" and an array of seven integers which are used as
pointers:
typedef
enum {leftL, rightR, mother, father, mSib, pSib, child} ptrNameType ;
typedef int ptrArrayType[7] ;
I also have a class called SpaceNode. Each SpaceNode contains a TreeNode plus
a bool "inUse" flag and an int "link" field which my program uses to link the
elements of the free list together.
NodeSpace
In your solution program you can declare a NodeSpace class. It can have data
members:
- a dynamically allocated array of nodes
- a size field that keeps track of how big the array is
- an integer that keeps track of the index of the first element of the free
list.
and methods:
- constructor
- destructor
- allocate a node
- de-allocate a node
- mark all nodes free
- rebuild the free list
- copy node information from a stream into one slot in the array
- copy node information from one slot in the array to a stream
- print the indices of the elements in the free list (debugging aid).
You can also declare a tree class and a sibling ring class that are friend
classes to the NodeSpace class. In the main function of the program, you can
declare a NodeSpace object - let's call it theNodeSpace.
myTreeCls
My tree class could have data members:
- an integer that denotes the array index that contains the root of the BST.
- a pointer to a NodeSpace object
Some of the methods of my tree class can be:
- constructor
- destructor
- Load at tree from a stream
- Store a tree to a stream
- Print all maternal or paternal siblings of a person
- Print all children of a person
- Print the family tree or the BST (determined by parameters) from some
given person down to a given number of levels.
- Insert a node with a given name if not there already
- Print a message about creation of parent-child relationship
- Print a message about creation of sibling relationship(s)
- Make one person parent of another
- Make one person sibling of another
- Delete a node by name (if found) - "fix" all pointers - not just left and
right tree pointers.
You can write the constructor so that it takes a parameter which is a pointer
to a NodeSpace. Then in the main function of the program, you can have
statements like:
NodeSpace theNodeSpace ;
myTreeCls theTree(&theNodeSpace);
If you set it all up correctly, this will make the pointer in theTree point to
theNodeSpace so it can use theNodeSpace as the place where all the tree nodes
"live". Methods of myTreeCls can use the operations of the NodeSpace class to
allocate and deallocate memory, and so forth.
sibRingClass
The sibling ring class could have data members:
- a pointer to a NodeSpace
- int startPtr /* index of one of the ring elements within the NodeSpace */
- ptrNameType next /* indicates whether this is a maternal or paternal
sibling ring */
Some of the methods of the sibling ring class could be:
- constructors
- destructor
- isEmpty
- isSingleton
- PrintSiblings
- MergeRings
- PrintRing
- Traverse a ring, setting all mother or father pointers to some value
- UnLink start node from ring (bypass)
The implementation can be set up so the same NodeSpace is shared by the tree
object and all sibling ring objects.
In my design of the solution code, methods in the tree class declare ring
objects when needed. For example, when a method in the tree class needs to
merge two sets of siblings, it creates two sibling rings and uses a ring
method to merge them into one ring.
The constructor of the ring class gives a ring a specific NodeSpace, value for
"startPtr", and value of "next". These things are parameters of the
constructor. This allows objects of the ring class to share the same
NodeSpace with the tree. It also allows a ring to represent any maternal or
paternal sibling ring contained in the database.
The program creates sibling ring objects as needed - using whatever start node
is desired. Then the program uses sibling ring methods to help complete
ring-oriented tasks that need to be done as part of executing the basic
command set of the program -- for example printing the elements of a ring.