/*Graph class to construct a graph of edges and nodes
* VERY useful for graph theory courses :)
* Chris LaPointe
* April 2008
* Licence: GPLv3
graph.h is a member of the project GraphClass.
GraphClass is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GraphClass is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GraphClass. If not, see .
*/
#ifndef GRAPH_H_
#define GRAPH_H_
#include
#include
#include
namespace GraphTheory{
template class Graph;
//The actual graph=========================================
template class Graph{
public:
//============================================
//NODES AND EDGES=============================
//============================================
//Nodes or pointers in a given graph
class Node;
class Edge;
class NodeIterator;
class EdgeIterator;
class Node{
public:
Node(): e_first(NULL), e_last(NULL), size_edges(0), next(NULL), prev(NULL){}
Node(const T &ident_){
e_first = e_last = NULL;
next = prev = NULL;
size_edges = 0;
ident = ident_;
}
~Node(){
Edge *temp;
Edge *edge = e_first;
while(edge){
temp = edge->next;
delete edge;
edge = temp;
}
e_first = e_last = NULL;
size_edges = 0;
}
const T &getIdent()const{
return ident;
}
//Add an edge pointing to something, at the end
Edge *AddEdge(Node *to){
if (EdgeExists(to)) //Check if it exists
return NULL;
Edge *nedge = new Edge(this,to); //Create new edge
nedge->prev = e_last; //set the prev to point here
if (e_last) e_last->next = nedge; //and the e_last to point to new one
e_last = nedge; //Set e_last to new last
if (!e_first) e_first = nedge; //If this is the only one, set it to first, too
size_edges++; //iterate
return nedge;
}
Edge *AddEdge(Node *to, const S &value){
Edge *nedge = AddEdge(to); //Make edge
nedge->evalue = value; //Set initial value
return nedge;
}
//Deletes an edge out of existance (MUST BELONG TO US!)
bool DelEdge(Edge *e){
if (!e) return false;
//Set new pointers
if (e->prev)
e->prev->next = e->next;
if (e->next)
e->next->prev = e->prev;
//Change e_first or e_last if needed
if (e == e_first) e_first = e->next;
if (e == e_last) e_last = e->prev;
delete e;
//decrement
size_edges--;
return true;
}
//Delete an edge based on a pointer to another node
bool DelEdge(Node *to){
return DelEdge(FindEdge(to));
}
//Check if an edge exists that points to another node
Edge *FindEdge(Node *to)const{
for (Edge *i = e_first; i != NULL; i=i->next){
if (i->dst == to)
return i;
}
return NULL;
}
bool EdgeExists(Node *to)const{
return FindEdge(to) ? true : false;
}
//Iterators----
EdgeIterator begin_edge()const{
return EdgeIterator(e_first);
}
EdgeIterator end_edge()const{
return EdgeIterator();
}
//Number of edges
int EdgeCount()const{
return size_edges;
}
//Public variables
T ident; //Identification name or number, or whatever
//Friendships :)
friend class Graph;
friend class EdgeIterator;
friend class NodeIterator;
private:
Edge *e_first; //Head of edge list
Edge *e_last; //Last edge contained
int size_edges; //Number of edges contained
Node *next; //Next in the list of nodes
Node *prev; //The previous node
};
//Edges various nodes can point to
class Edge{
public:
Edge(): dst(NULL), owner(NULL), next(NULL), prev(NULL){}
Edge(Node *own_, Node *pt_): owner(own_), dst(pt_), next(NULL), prev(NULL){}
Node *owner; //The owner node of this edge
Node *dst; //Destination node
S evalue; //Edge identification value
friend class Node;
friend class EdgeIterator;
friend class NodeIterator;
private:
Edge *next; //Next edge in sequence
Edge *prev; //The previous edge
};
//=======================================
//Iterators==============================
//=======================================
//The fancy iterators!!
//The below iterator is more of a wrapper to navigate accross edges
//Has capabilities to navigate across edges in only a single node, or across all nodes
class EdgeIterator{
public:
//Constructors
EdgeIterator(): e(0), n(0){}
EdgeIterator(Edge *start){
e = start;
n = NULL;
}
EdgeIterator(Node *start){
if (start){
n = start;
e = n->e_first;
while(!e){
n = n->next;
if (n) e = n->e_first;
else break;
}
}else{
e = NULL;
n = NULL;
}
}
EdgeIterator &operator++(){
this->next();
return *this;
}
EdgeIterator &operator++(int){
this->next();
return *this;
}
void next(){
if (e){ //if have e
e = e->next; //iterator e
if (!e && n){ //if e=NULL, but node exists
while(!e){
n = n-> next;
if (n) e = n->e_first;
else break;
}
}
}//e
}
//Accessors
Edge &operator*(){
return *e;
}
const Edge &operator*()const{
return *e;
}
Edge *operator->()const{
return e;
}
Edge *ptr()const{
return e;
}
//comparisons
//NOTE: Because this is an edge iterator, only edges need to be compared
bool operator==(const EdgeIterator &a)const{
return a.e == e;
}
bool operator!=(const EdgeIterator &a)const{
return a.e != e;
}
private:
Edge *e;
Node *n;
};
class NodeIterator{
public:
NodeIterator(): n(0){}
NodeIterator(Node *start): n(start){}
//Iterations
NodeIterator &operator++(){
if (n) n = n->next;
return *this;
}
NodeIterator &operator++(int){
if (n) n = n->next;
return *this;
}
//Accessors
Node &operator*(){
return *n;
}
const Node &operator*()const{
return *n;
}
Node *operator->()const{
return n;
}
Node *ptr(){
return n;
}
//Comparisons
bool operator==(const NodeIterator &a)const{
return a.n == n;
}
bool operator!=(const NodeIterator &a)const{
return a.n != n;
}
private:
Node *n;
};
//============================================
//The graph class=============================
//============================================
Graph(){
size_nodes = 0;
n_first = n_last = NULL;
}
Graph(const Graph &a): n_first(NULL), n_last(NULL), size_nodes(0){
Copy(a);
}
~Graph(){
Destroy();
}
//Memory==============================
//Copy a graph
void Copy(const Graph &from){
Destroy(); //clear us
//start copying
for (NodeIterator i = from.begin(); i != from.end(); ++i)
AddNode(i->ident);
for (EdgeIterator i = from.begin_edge(); i != from.end_edge(); ++i)
AddEdge(i->owner->ident, i->dst->ident, i->evalue);
}
void Destroy(){
Node *node = n_first;
Node *temp;
while(node){
temp = node->next;
delete node;
node = temp;
}
n_first = n_last = NULL;
size_nodes = 0;
}
void Clear(){
Destroy();
}
//Operators============================
//overloaded operators
Graph &operator=(const Graph &a){
Copy(a);
return *this;
}
Node &operator[](const T &i){
return *FindNode(i);
}
//Counters================================================
//The size of the graph is the number of nodes
int size()const{
return size_nodes;
}
int NodeCount()const{
return size_nodes;
}
int EdgeCount()const{
int sum = 0;
for (Node *i = n_first; i != NULL; i=i->next)
sum += i->size_edges;
return sum;
}
//Adding=====================================================
//Add node to graph checking for duplicate nodes
Node *AddNode(const T &id){
if (NodeExists(id)) return NULL;
Node *nnode = new Node(id);
nnode->prev = n_last;
if (n_last) n_last->next = nnode;
n_last = nnode;
if (!n_first) n_first = nnode;
size_nodes++;
return nnode;
}
//Add an edge connecting two nodes
Edge *AddEdge(Node *from, Node *to){
return from->AddEdge(to);
}
Edge *AddEdge(const T &from, const T &to){
Node *n_from = FindNode(from);
Node *n_to = FindNode(to);
if (!n_from || !n_to)
return NULL;
return n_from->AddEdge(n_to);
}
Edge *AddEdge(Node *from, Node *to, const S &value){
Edge *nedge = AddEdge(from,to);
if (nedge) nedge->evalue = value;
return nedge;
}
Edge *AddEdge(const T &from, const T &to, const S &value){
Edge *nedge = AddEdge(from,to);
if (nedge) nedge->evalue = value;
return nedge;
}
//Removal==========================================
bool RemoveNode(Node *node){
if (!node) return false;
//Destroy all edges pointing to it..
for (Node *i = n_first; i != NULL; i = i->next)
i->DelEdge(node);
//Delete me
if (node->prev) node->prev->next = node->next;
if (node->next) node->next->prev = node->prev;
if (node == n_first) n_first = node->next;
if (node == n_last) n_last = node->prev;
//Remove
delete node;
size_nodes--;
return true;
}
bool RemoveNode(const T &id){
return RemoveNode(FindNode(id));
}
//Finding==========================================
//Looking for an edge
Edge *FindEdge(Node *from, Node *to)const{
if (!from || !to) return NULL;
for (Node *i = n_first; i != NULL; i=i->next){
Edge *e = i->FindEdge(to);
if (e) return e;
}
return NULL;
}
Edge *FindEdge(const T &from, const T &to)const{
return FindEdge(FindNode(from), FindNode(to));
}
//Look for a node based on the ident
Node *FindNode(const T &id)const{
for (Node *i = n_first; i != NULL; i=i->next){
if ( i->getIdent() == id)
return i;
}
return NULL;
}
//Check if a node exists
bool NodeExists(const T &id)const{
return FindNode(id) ? true : false;
}
//Accessor operators=======================================
//Used with node iterators
NodeIterator begin()const{
return NodeIterator(n_first);
}
NodeIterator end()const{
return NodeIterator();
}
EdgeIterator begin_edge()const{
return EdgeIterator(n_first);
}
EdgeIterator end_edge()const{
return EdgeIterator();
}
private:
Node *n_first; //Nodes contained in this graph
Node *n_last; //Last node contained in graph
int size_nodes; //Number of containg nodes
};
//=================================================================
//GRAPH DATA STRUCTURES
//=================================================================
//NOTE:
//Edge data structures need streaming operator <<
//Node operators need streaming operator<< as well as operator==
//T can be anything (with comparison and streaming ops), S must be some numerical value to compare distances
template class WeightedNode{
public:
WeightedNode(){}
WeightedNode(const T n): name(n){}
WeightedNode(const T n, const S d): name(n), dist(d){}
bool operator==(const WeightedNode &a)const{return a.name == name;}
T name;
S dist;
};
template std::ostream &operator<<(std::ostream &os, const WeightedNode &ewd){
os << "{" << ewd.name << ", dist: " << ewd.dist << "}";
return os;
}
//=================================================================
//=========ALGORITHMS==============================================
//=================================================================
template class PQ_CompareVertex{
public:
bool operator()(const T &n1, const T &n2){
return n1->ident.dist < n2->ident.dist;
}
};
//Shortest path algorithm when S is WeightedNode and S is a numerical type, matching N
template void Dijkstra(const GraphTheory::Graph &input, const T &source){
//Create the priority queue
std::priority_queue::Node*, std::vector::Node* >, PQ_CompareVertex::Node*> > vqueue;
//Set all distances to -1
for (typename Graph::NodeIterator i = input.begin(); i != input.end(); ++i)
i->ident.dist = -1;
//Get the source
typename Graph::Node *first = input.FindNode(source);
first->ident.dist = 0;
vqueue.push( first );
//loop through queue until empty
while (!vqueue.empty()){
typename Graph::Node *curr = vqueue.top();
vqueue.pop();
//Go through each edge connecting curr
for (typename Graph::EdgeIterator e = curr->begin_edge(); e != curr->end_edge(); ++e){
if (e->dst->ident.dist == -1 || e->dst->ident.dist > curr->ident.dist + e->evalue){
e->dst->ident.dist = curr->ident.dist + e->evalue;
vqueue.push(e->dst);
}
}
}
//DONE
}
//=================================================================
//=================================================================
};
template std::ostream &operator<< (std::ostream &os, const GraphTheory::Graph &graph){
unsigned int nodecount = graph.NodeCount();
unsigned int edgecount = graph.EdgeCount();
os << "Graph has " << nodecount << " node" << (nodecount != 1 ? "s" : "") << " and " << edgecount << " edge" << (edgecount != 1 ? "s" : "") << "." << std::endl;
for (typename GraphTheory::Graph::NodeIterator i = graph.begin(); i != graph.end(); ++i){
os << " Node " << i->getIdent() << ":" << std::endl;
for (typename GraphTheory::Graph::EdgeIterator j = i->begin_edge(); j != i->end_edge(); ++j){
os << " Edge to " << j->dst->getIdent() << " with value " << j->evalue << std::endl;
}
}
return os;
}
#endif /*GRAPH_H_*/