Advanced Programming II, Spring 2002

Programming Assignment 6 - An Example Solution


Table of Contents

Introduction

Design

Implementation

Pickling Graphs

To pickle a graph, order the graph nodes into a list and then output the list. The linear order imposed on the graph nodes doesn't matter much, as long as the root node is the first node in the order. A depth-first order works as well as any other, and it's simple to implement. This functor implements an indirectly recursive call to listify_nodes(). It should be possible to use direct recursion, but apparently the STL freaks out when parameter functions have reference parameters, and listify_nodes() needs to have the node list passed by reference so changes to it are carried outside of listify_nodes(). As discussed in the Design section, the pickle-file format consists of the node count followed by the node data followed by the child data. Another simple functor implementing a function that should be called directly but for a reference parameter. A functor to write a nodes' child information. This needs to be a functor because it uses three arguments, and the STL lets you wrap at most one extra argument. A functor that maps a node pointer to its index and writes the index to the pickle file. The node-list is implemented as a vector of graph-node pointers. Search the given node list for the given graph-node pointer, returning the index of the pointer if it's found or -1 if it isn't. Write an unsigned integer to the pickle file. Write the integer twice to provide a redundant safety check when reading it from the file.

Unpickling Graphs

To unpickle a graph, read the nodes from the pickle file. The first half of the pickle file contains the node data, and the second half contains the child data. The firs node in the file is the root of the graph. Read a node's data from the pickle file and return it in a new graph node. The child data follows the node data in the pickle file, and is given in the same order as the node data. Each nodes child information is stored as a count followed by node indices, which are translated into node pointers using nodes. A functor is best here because three arguments are required to read child data (a pointer to a graph-node, the node list, and the input stream). Read and return an unsigned integer from the pickle file. The integer has been written twice to provide a sanity check on the data in the file. Re-assembling a graph from the pickle file requires translating node indicies (which represent node order in the file) into node pointers. This is most easily done using a vecotr of graph-node pointers and pushing the nodes pointers into the vector in the same order as the nodes are given in the file. The translation is then just indexing.

Also define an abbreviation for the pickle-factory prototype.

main.cc

The test program can pickle or unpickle a graph separately; if neither is specified, both are done. The graph is read from std-in. If a graph is unpickled, the unpickled graph is compared against the input graph. The command-line options are Graphs are input as a sequence of lines, each line describing a node in the graph. Read a node description from the given input stream, storing the node in the given node list. Return true if a node description was read; false otherwise.

Each line of graph input is a sequence of space-separated numbers. The first number is the number of the node being defined. The second number is the count of children for the node. The node numbers of the children, if any, follow.

Read a node number from the given input stream, storing it in the given node list if it isn't already there. Return the node's number or 0 if there no node numbers were read. Create a new graph node with randomly generated data; return a pointer to the new node. Each graph node conatins a string representation of a random integer. The string is pickled in three parts: the size (plus the null byte), followed by the string (including the null byte) followed by the size again to allow for a redundancy check. Create and return pickleable node-data. This is an abuse of the term "factory", but the intention is close. Do a depth-first flatten on the graph rooted at r. Return the linearized node data in a vector. Each node's data is described by a vector; the first (index 0) element is the node's data, the following elements contain the children's data in the left-to-right order given by the children vector. Flatten the tree rooted at r into the data vector v; using the list of nodes nodes. If r is listed in nodes, it has been (or is being) processed and needs no further processing. Test for a match between two pointers. A functor to help create a vector of children data. This needs to be a functor because the changes made to the vector needs to be passed by reference. A functor to help recurse over a node's children.

Index


This page last modified on 28 April 2002.