CSCI 260 Fall 2010: Minimal spanning trees

(description coming shortly) The implementation below is a revision of the adjacency-matrix graphs we've discussed previously. Some of the changes include:

/**********************************************************/
/************** EDGELIST HEAP CLASS ***********************/
/**********************************************************/

// define the contents of an edge,
//    used for building edgelists
//    (for use in spanning tree algorithms)
struct edgenode {
   int src;
   int dest;
   float weight;
};

// define a heap, used to store edges with
//    the minimum weight edge on top
class heap {
   private:
      int maxsize;
      int cursize;
      edgenode* *edges;
   public:
      heap(int sz = 0);
      ~heap() { delete edges; }
      bool insert(edgenode *e);
      edgenode *remove();
};

edgenode *heap::remove()
{
   if ((cursize >= maxsize) || (!edges)) return NULL;
   edgenode *victim = edges[0];
   edges[0] = edges[--cursize];
   edgenode *e = edges[0];
   if (!e) return NULL;
   edges[cursize] = NULL;
   int pos = 0;
   do {

      // see if e needs to swap with either of its children
      int left = 2 * pos + 1;
      int right = left + 1;

      // quit if there are no children
      if ((left >= cursize) || (edges[left] == NULL)) break;

      // check against a lone left child
      else if (left == (cursize-1)) {
          edgenode *tmp = edges[left];
          if (tmp->weight < e->weight) {
             edges[left] = e;
             edges[pos] = tmp;
             pos = left;
          } else break;
      } 

      // check against the larger of two children
      else {
         edgenode *l = edges[left];
         edgenode *r = edges[right];
         if (!l || !r) break;
         if ((l->weight > r->weight) && (l->weight > e->weight)) {
            edges[left] = e;
            edges[pos] = l;
            pos = left;
         } 
         else if (r->weight > e->weight) {
            edges[right] = e;
            edges[pos] = r;
            pos = right;
         } 
         else break;
      }

   } while (pos < cursize);
   return victim;
}

bool heap::insert(edgenode *e)
{
   // make sure we have an edge to insert
   if (!e) return false;

   // insert the new edge
   edges[cursize++] = e;

   // percolate the edge up the heap
   int pos = cursize - 1;
   while (pos > 0) {
      // figure out the position of the parent 
      int parent = (pos - 1) / 2;
      // if the parent is null there's an error
      //    (there should be no nulls between 
      //     the heap root and the insert point)
      if (!edges[parent]) return false;
      // if the parent weight is no bigger than e's
      //    then e is as far up the heap as it needs to go
      if (edges[parent]->weight <= e->weight) return true;
      // otherwise swap e and its parent
      edges[pos] = edges[parent];
      edges[parent] = e;
      pos = parent;
   }
   return true;
}

heap::heap(int sz)
{
   if (sz < 0) sz = 0;
   if (sz == 0) edges = NULL;
   else edges = new (edgenode*)[sz];
   if (!edges) maxsize = 0;
   else maxsize = sz;
   cursize = 0;
   for (int i = 0; i < maxsize; i++) edges[i] = NULL;
}
/**********************************************************/
/************** MINIMAL SPANNING TREE FUNCTION ************/
/**********************************************************/
// if the graph has a minimal spanning tree,
//    display the list of edges in the tree
//       and return true
// otherwise return false
bool mst()
{
   // initialize every node's spanning tree flag to false
   for (int i = 0; i < VERTICES; i++) {
       if (Graph[i] != NULL) {
          Graph[i]->inmst = false;
       }
   }

   // create a heap of edgelists, large enough to
   //    store all the edges currently in the graph
   heap edgelist(get_numedges());

   // find a starting node and mark it as in the mst
   int pos = 0;
   int cursize = get_graphsize();
   while ((Graph[pos] == NULL) && (pos < cursize)) pos++;
   // if there were no nodes then the graph is empty
   if (pos >= cursize) return true;

   // use a queue of edgenodes to keep track of our mst
   deque mst;

   // keep track of the number of nodes in our mst
   int mstsize = 1;

   // keep a pointer to the current node
   node *curr = Graph[pos];
   do {
      // mark the current node as part of the mst
      if (!curr) break;
      else curr->inmst = true;

      // put the current node's edges in the heap
      for (int i = 0; i < VERTICES; i++) {
          if (Edges[pos][i] > 0) {
             edgenode *new_e = new edgenode;
             if (new_e) {
                new_e->src = pos;
                new_e->dest = i;
                new_e->weight = Edges[pos][i]; 
                edgelist.insert(new_e);
             }
          }
      }

      // find the top heaped edge that connects an mst node
      //    to a non-mst node (quit if there is none)
      edgenode *nexte;
      node *n1, *n2;
      while ((nexte = edgelist.remove()) != NULL) {
         n1 = Graph[nexte->src];
         n2 = Graph[nexte->dest];
         if ((!n1) || (!n2))  {
            delete nexte;
            continue;
         }
         if (n1->inmst != n2->inmst) break;
      }
      if (!nexte) break;

      // add the selected edge to the mst
      mst.push_front(nexte);
      mstsize++;

      // make the new current node the one the new edge
      //   adds to the tree
      if (n1->inmst) {
         n2->inmst = true;  
         pos = n2->nodeid;
         curr = n2;
      } else  {
         n1->inmst = true;  
         pos = n1->nodeid;
         curr = n1;
      }
   } while(mstsize < get_graphsize());

   // if we couldn't build the entire spanning tree
   //    then the final result is false
   // otherwise the mst is now complete, so display it
   //    and set the final result to true
   bool result = false;
   if (mstsize >= (get_graphsize() - 1)) {
        result = true;
        cout << "The complete spanning tree is" << endl;
   } else cout << "The partial spanning tree is" << endl;
   while (!mst.empty()) {
      edgenode *e = mst.front();
      mst.pop_front();
      if (e) {
         cout << e->src << "->" << e->dest << " (" << e->weight << ")" << endl;
         delete e;
      }
   }
   return result;
}