/****************************************************************************
 *   ggraph.h : 
 *   		header file for GFC graph.
 *
 *   Change Log :
 *		 Aug 10, 1998 Initial version,  Liujian Qian
 *
 *   $Id: ggraph.h,v 1.14 1999/02/15 09:13:44 qian Exp $
 ***************************************************************************/
#ifndef _GADTGRAPH_H_
#define _GADTGRAPH_H_

#include <memory.h>
#include "gcxx.h"

#ifndef NOP
#define NOP	
#endif

class ostream;

class GNode;
class GWire;
class GGraph;

//
// GUtilData.
// This is provided for defining various utility data
// associated with nodes/wires. The exact meaning of these
// utility data is up to the interpretation of the type
// of graphs and the algorithms of concern.
union GUtilData
{
    GNode	*n;
    GWire	*w;
    GGraph	*g;
    char	*s;
    float	f;
    int		i;
};


/**
 * GNode represents a node (vertex) in the graph.
 * All the nodes of a graph are linked together
 * in a list. Each node points to a list of wires (arcs) 
 * of its own (which are all started from this node).
 * The receiving node (end) of a wire is accessed by 
 * the wire's 'tip' field.
 * 
 * Each node has a name and a (graph-wide) unique ID
 * which is an integer. 
 */
class GNode
{
    friend class GGraph;

public:
    GUtilData	u,v,w,  //util data used & interpreted by
	        x,y,z;  //all sorts of graphs/algorithms
    char	name[64];
    int		id;	//unique id in a graph 
    GNode	*next;  //next in the graph's node list

    GWire	*wire_list;  //the wire list

public:
    GNode();
    /**
     * just removes the wire from the node's wire_list.
     * The wire object may still hang around in the memory.
     */
    void	removeWire(GWire* w);
    /**
     * custom memory allocator for graph nodes.
     */
    //void * 		operator new(size_t);
    /**
     * custom memory deallocator for graph nodes.
     */
    //void  		operator delete(void* ep, size_t);
};


/**
 * GWire represents a wire (or edge, or arc) in the graph.
 * Each wire has two integers representing its origin and
 * destination node. It also points to the memory addr of receiving
 * node (through the field 'tip')\. The data field w is used to
 * store the weight (if any) on that wire. Default weight of a wire
 * is 1.0.
 */
class GWire
{
    friend class GGraph;

public:
    GUtilData	u,v,w;  //util data provided for convenience

    int		orig, dest;  	//id for the two ends of the wire
    GNode	*tip; 		//where this wire points to. 
    GWire	*next;		//next wire with same origin (node)

    GWire();
};

/**
 * GGraph
 * The general graph class. A graph has a list of nodes.
 * Each node has its own list of wires that start from it.
 * 
 * Many public methods have two versions, one based on the
 * memory address of the nodes, one based on the id of the
 * nodes. The second one is less efficient since a lookup based
 * on the integer id is necessary. The advantage of id-based
 * methods is that we can perform algorithms on disk-based
 * (huge) graphs where the memory-address-based methods may
 * fall short due to memory stress.
 *
 * (The structure of the GNode/GWire/GGraph is similar to those
 * in The Stanford Graphbase, Knuth '94.)
 *
 */
class GGraph 
{
protected:
    int		n_nodes;
    int		n_wires;
    
    GNode	*node_list;	//the global list of nodes
    int		next_node_id;	//for auto-incremental ID. Never reused.
    
    struct {
	bool 	directed;
	bool 	dynamic;
	bool 	weighted_wire;
	bool 	weighted_node;
    }flags;

public:
    NOP		GGraph		(bool _directed = false, 
				 int _next_node_id = 0);
    virtual	~GGraph		();
    
    // node-related methods.

    /**
     * add a node to the graph. The node id is automatically
     * assigned by the graph.
     */
    virtual void	addNode		(GNode* nd);
    /**
     * same as above, except use the given node id.
     */
    virtual void	addNode		(GNode* nd, int id);

    /**
     * delete a node (and all of related wires). The node
     * object is completely vanished from the memory-space
     * after this.
     */
    virtual void	delNode		(GNode* nd);
    /**
     * same as above, provided for convenience.
     */
    virtual void	delNode		(int id);
    /**
     * check if the given node is isolated or not connected to
     * any other node.
     */
    virtual bool	isIsolated	(int node_id);
    virtual bool	isIsolated	(GNode* nd);

    // wire-related methods.

    /**
     * establish connection between orig and dest. For undirected
     * graph this actually adds two wires to the graph, one from
     * orig->dest, another dest->orig. Weight is the weight to be
     * assigned to the new wire(s).
     * The new wire corresponding to the new connection is returned.
     */
    virtual GWire*	connect		(GNode* orig, GNode* dest, float weight=1.0);
    /**
     * same as above, provided for convenience.
     */
    virtual GWire*	connect		(int orig_id, int dest_id, float weight=1.0);

    /**
     * disconnect a pair of nodes. For undirected it deletes two
     * wires from the graph.
     */
    virtual void	disconnect	(GNode* orgi, GNode* dest);
    virtual void	disconnect	(int orig_id, int dest_id);
    
    // graph house-keeping methods

    int		numNodes	()   const {return n_nodes; }
    int		numWires	()   const {return n_wires; }
    bool	isDirected	() const {return flags.directed; }

    // completely wipes out all nodes
    void	freeNodes();
    // completely wipe out all the wires.
    void	freeWires();
    
    /**
     * lookup and return the memory address of the 
     * node with the given id. 
     */
    GNode*	lookup		(int id) const;
    
    /**
     * check wether a node is a root node. This is only meaningful
     * for directed graphs.
     * A root node is not the 'tip' or destination of any wires in 
     * the graph.
     */
    bool	isRoot		(GNode* nd) const;
    bool	isRoot		(int id) const;

    /**
     * check if a node is a leaf node. This is only meaningful 
     * for directed graphs.
     * A leaf node is a node that has no out-going wires. 
     */
    bool	isLeaf		(GNode* nd) const;
    bool	isLeaf		(int id) const;

    /**
     * check wether two nodes are neighbor.
     * Neighboring nodes have a direct wire between them.
     */
    bool	isNeighbor	(GNode* nd1, GNode* nd2);
    bool	isNeighbor	(int id1, int id2);
    
    /**
     * check wether two nodes are connected. Two nodes are
     * connected if they are either 1) neighbors, or 2)
     * there exists a path from nd1--->nd2. For digraph
     * nd1 must be the origin node, and nd2 the destination
     * node for the path.
     */
    bool	isConnected	(GNode* nd1, GNode* nd2);
    bool	isConnected	(int id1, int id2);

    /**
     * calculate the diameter of the graph.
     * The diameter of a graph is the longest path from
     * one node to another.
     */
    int		diameter	();

    //////////////////////////////////////////////////
    // Graph Algorithms

    /**
     * find out the shortest path from orig to dest.
     * A linked list of nodes on the desired path, starting
     * with 'orig', is returned when successful. The utility 
     * data field GNode::z is used to link all the nodes on 
     * the path together. Also note that the weight is stored
     * in each wire's GWire::w.f field.
     */
    GNode*	shortestPath	(GNode* orig, GNode* dest);
    GNode*	shortestPath	(int orig_id, int dest_id);    

    /**
     * check whether the graph is a planar one.
     */
    bool 	isPlanar	() const;


    friend 
    ostream&	operator<<(ostream& os, const GGraph& g);
    
protected:
    //stuff that does the dirty work
    GWire*	_connect1	(GNode* orig, GNode* dest, float weight);
    void	_disconnect1    (GNode* orig, GNode* dest);
};

#endif

Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999