ALStructure.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 CSIRO ICT Centre
00003  *
00004  * $Id: ALStructure.cpp 587 2004-12-03 15:06:33Z nch $
00005  */
00006 
00007 /* ALStructure is the main class in the implementation of the
00008  * data structure used by IndexedActiveList.  This data
00009  * structure is a collection of elements linked by two doubly
00010  * linked lists.  One of these lists is sorted by right
00011  * ascension, while the other is sorted by declination.  In
00012  * addition, a binary tree indexes the list on right ascension.
00013  * 
00014  * This data structure assumes that objects are added in
00015  * ascending order of declination.  If objects will not be added
00016  * in ascending order of declination, then do not use this data
00017  * structure: it won't work.
00018  *
00019  * Consequently, every insertion and deletion involves three
00020  * separate operations.  The binary tree operations tend to
00021  * be a tad complex, so if you intend to edit this file, I
00022  * suggest that you familiarise yourself with binary trees
00023  * first.
00024  *
00025  * The only other detail worth mentioning is this: in order
00026  * to simplify the specification of insertion objects, it
00027  * was convenient to implement this class with a sentinel
00028  * element.  That is, a dud element that contains no data
00029  * but merely indicates the end of a list.  Because of the
00030  * presence of this sentinel element, the lists should never
00031  * be completely empty.  Also, because of the sentinal element,
00032  * the tails of the list necessarily coincide at all times;
00033  * hence there are two head objects: raHead and decHead, but
00034  * only a single tail object: tail.
00035  */
00036 #include <iostream>
00037 
00038 #include "ALStructure.h"
00039 
00040 
00041 ALStructure::ALStructure()
00042     : size(0),
00043       sentinel(0, 0, 0, 0, 0),
00044       raHead(&sentinel),
00045       decHead(&sentinel),
00046       tail(&sentinel),
00047       rootNode(0)
00048 {
00049   rootNode = new ALNode(&sentinel, 0, 0);
00050 }
00051 
00052 ALStructure::~ALStructure()
00053 {
00054   delete rootNode;
00055 }
00056 
00057 /* find the element whose active object has the smallest ra
00058  * greater than or equal to ra */
00059 ALElement * ALStructure::findLeastGE(double ra)
00060 {
00061   return findLowerBound(ra, true);
00062 }
00063 
00064 /* find the element whose active object has the smallest ra
00065  * greater than ra */
00066 ALElement * ALStructure::findLeastG(double ra)
00067 {
00068   return findLowerBound(ra, false);
00069 }
00070 
00071 /* find the element whose active object has the smallest ra
00072  * greater than ra.  The boolean flag indicates whether
00073  * equality is permitted. */
00074 
00075 ALElement * ALStructure::findLowerBound(double ra, bool allowEquality)
00076 {
00077   /* Start at the root */
00078   ALNode * currentNode = rootNode;
00079 
00080   /* Keep track of the best element found so far. */
00081   ALElement * bestSoFar = 0;
00082 
00083   /* Until we have walked all the way down to a leaf... */
00084   while (currentNode != 0)
00085   {
00086     ALElement * i = currentNode->getElement();
00087 
00088     if (i == tail)
00089     {
00090       // this is the sentinel node, which is by definition greater than c.
00091       // This is the best lower bound so far. 
00092       // Take a note of it, and look to the left for something smaller still.
00093       bestSoFar = i;
00094       currentNode = currentNode->getLeftChild();
00095     }
00096     else
00097     {
00098       // this is a normal node.  Check its value.
00099       ActiveObject * content = i->getContent();
00100       double contentRa = content->getObject()->getRa();
00101       if (contentRa > ra)
00102       {
00103         // This is greater than the bound, as required.
00104         // Since we always step to the left once a
00105         // suitable element has been found, this must
00106         // be the best so far. Take a note of it, and
00107         // look to the left for something smaller still.
00108         bestSoFar = i;
00109         currentNode = currentNode->getLeftChild();
00110       }
00111       else if (contentRa < ra)
00112       {
00113         // Oops, this is less than the bound.  We have
00114         // searched too far to the left.  Look right.
00115         currentNode = currentNode->getRightChild();
00116       }
00117       else if (allowEquality)
00118       {
00119         // We have found an element equal to the bound,
00120         // and this is permitted.  Since we always step
00121         // to the left when a suitable element has been
00122         // found, this must be the best so far.
00123         // Take a note of it, and look to the left.
00124         // We continue searching because if there are
00125         // many objects with the same ra, we want to find
00126         // the leftmost one.
00127         bestSoFar = i;
00128         currentNode = currentNode->getLeftChild();
00129       }
00130       else
00131       {
00132         // Oops, we have found an element equal to the
00133         // bound, and this is not permitted.  We have
00134         // searched too far to the left.  Look right.
00135         currentNode = currentNode->getRightChild();
00136       }
00137     }
00138   }
00139 
00140   // bestSoFar now contains the smallest element meeting
00141   // the provided condition.  If there is no such element,
00142   // the sentinel will be returned.
00143   return bestSoFar;
00144 }
00145 
00146 
00147 /* remove an element from the data structure. */
00148 void ALStructure::remove(ALElement * element)
00149 {
00150   ALElement * prevRa = element->getPrevRa();
00151   ALElement * nextRa = element->getNextRa();
00152   ALElement * prevDec = element->getPrevDec();
00153   ALElement * nextDec = element->getNextDec();
00154 
00155   // update the lists.
00156 
00157   // element is guaranteed to have a next, because it is not the
00158   // sentinel (presumably).  But there's no guarantee that prevRa
00159   // or prevDec aren't 0, since element might be at the head of
00160   // one or both lists.  We therefore need to be careful when
00161   // removing elements.
00162  
00163   nextRa->setPrevRa(prevRa);
00164   if (prevRa == 0)
00165     raHead = nextRa;
00166   else
00167     prevRa->setNextRa(nextRa);
00168 
00169   nextDec->setPrevDec(prevDec);
00170 
00171   if (prevDec == 0)
00172     decHead = nextDec;
00173   else
00174     prevDec->setNextDec(nextDec);
00175 
00176   // now remove the node from the index.
00177   removeNode(element);
00178 
00179   delete element;
00180 
00181   size--;
00182 }
00183 
00184 void ALStructure::removeNode(ALElement * element)
00185 {
00186   ALNode * target;
00187 
00188   if (rootNode->getElement() == element)
00189   {
00190 
00191 // this stuff commented out because its only use is
00192 // for deletion of the sentinel element.  This code
00193 // does actually work, but if a calling function
00194 // demands deletion of the sentinel, I'd rather
00195 // fail fast, than robustly delete the sentinel
00196 // then fail later in some strange way.
00197 //
00198 //    target = rootNode;
00199 //    if ((rootNode->getLeftChild() == 0)
00200 //    && (rootNode->getRightChild() == 0)) {
00201 //      rootNode = 0;
00202 //    } else if (rootNode->getRightChild() == 0) {
00203 //      rootNode = rootNode->getLeftChild();
00204 //    } else if (rootNode->getLeftChild() == 0) {
00205 //      rootNode = rootNode->getRightChild();
00206 //    } else {
00207 //      ALNode * successor = grabSuccessor(target);
00208 //      
00209 //      rootNode = successor;
00210 //    }
00211 
00212     std::cout << "Error: trying to delete the sentinel!\n";
00213   }
00214   else
00215   {
00216     ALNode * parent;
00217     Child child;
00218 
00219     // find the node to be deleted.  Return the result
00220     // as a objecter to the node's parent, and an
00221     // indication of which child the node is.
00222     findNode(element, rootNode, &parent, &child);
00223 
00224     // make target object to the node to be removed.
00225     if (child == left)
00226       target = parent->getLeftChild();
00227     else
00228       target = parent->getRightChild();
00229     
00230     if ((target->getLeftChild() == 0) &&
00231         (target->getRightChild() == 0))
00232     {
00233       // target has no children, so simply delete
00234       if (child == left)
00235         parent->setLeftChild(0);
00236       else
00237         parent->setRightChild(0);
00238     }
00239     else if (target->getRightChild() == 0)
00240     {
00241       // target has no right subtree, so replace with left subtree
00242       if (child == left)
00243         parent->setLeftChild(target->getLeftChild());
00244       else
00245         parent->setRightChild(target->getLeftChild());
00246     }
00247     else if (target->getLeftChild() == 0)
00248     {
00249       // target has no left subtree, so replace with right subtree
00250       if (child == left)
00251         parent->setLeftChild(target->getRightChild());
00252       else
00253         parent->setRightChild(target->getRightChild());
00254     }
00255     else
00256     {
00257       // target has two children, so replace with inorder successor
00258       ALNode * successor = grabSuccessor(target);
00259 
00260       // connect parent to successor.
00261       if (child == left)
00262         parent->setLeftChild(successor);
00263       else
00264         parent->setRightChild(successor);
00265 
00266       // connect successor to target's left child
00267       successor->setLeftChild(target->getLeftChild());
00268     }
00269     delete target;
00270   }
00271 }
00272 
00273 /* Find the node containing a given element, and return
00274  * the answer as the parent of the node, and an indication
00275  * of which child the node is.  This is safe because we'll
00276  * never go looking for the root node, since this is the
00277  * sentinel. */
00278 void ALStructure::findNode(ALElement * element,
00279                            ALNode * root,
00280                            ALNode * * parent,
00281                            ALStructure::Child * child)
00282 {
00283   // at entry, element != root->getElement, so there's no
00284   // need to check
00285   ActiveObject * content = element->getContent();
00286   ActiveObject * rootContent = root->getElement()->getContent();
00287 
00288   // compare the content of the element to be found with the
00289   // content of the current root.  This will tell us whether
00290   // to search left, right, or both.
00291   int comp;
00292   if (rootContent == 0)
00293     comp = -1;
00294   else if (content->getObject()->getRa() < rootContent->getObject()->getRa())
00295     comp = -1;
00296   else if (content->getObject()->getRa() > rootContent->getObject()->getRa())
00297     comp = 1;
00298   else
00299     comp = 0;
00300 
00301   if (comp <= 0)
00302   {
00303     // we need to search to the left.
00304     ALNode * leftChild = root->getLeftChild();
00305     if (leftChild != 0)
00306     {
00307       // there is a left child, so check if it is the
00308       // element we're looking for.
00309       if (leftChild->getElement() == element)
00310       {
00311         // found it!  return the results.
00312         *parent = root;
00313         *child = left;
00314         return;
00315       }
00316       // there's a left child, but it isn't the
00317       // one we're looking for.  Recursively search
00318       // for the node in this subtree.
00319       findNode(element, leftChild, parent, child);
00320 
00321       // our recursive search succeeded.
00322       // Don't search any further.
00323       if (*parent != 0)
00324         return;
00325     }
00326   }
00327 
00328   if (comp >= 0)
00329   {
00330     // we need to search to the right.
00331     ALNode * rightChild = root->getRightChild();
00332     if (rightChild != 0)
00333     {
00334       // there is a right child, so check if it is the
00335       // element we're looking for.
00336       if (rightChild->getElement() == element)
00337       {
00338         // found it!  return the results.
00339         *parent = root;
00340         *child = right;
00341         return;
00342       }
00343       // there's a right child, but it isn't the
00344       // one we're looking for.  Recursively search
00345       // for the node in this subtree.
00346       findNode(element, rightChild, parent, child);
00347 
00348       // our recursive search succeeded.
00349       // Don't search any further.
00350       if (*parent != 0)
00351         return;
00352     }
00353   }
00354 
00355   // our search failed.  This subtree does not contain
00356   // the node we are looking for.  Return null.
00357   *parent = 0;
00358 
00359   return;
00360 }
00361 
00362 /* Find the inorder successor of a given node. */
00363 ALNode * ALStructure::grabSuccessor(ALNode * delNode)
00364 {
00365   ALNode * successorParent = delNode;
00366   ALNode * successor = delNode;
00367   ALNode * current = delNode->getRightChild();
00368 
00369   while (current != 0)
00370   {
00371     successorParent = successor;
00372     successor = current;
00373     current = current->getLeftChild();
00374   }
00375 
00376   if (successor != delNode->getRightChild())
00377   {
00378     successorParent->setLeftChild(successor->getRightChild());
00379     successor->setRightChild(delNode->getRightChild());
00380   }
00381 
00382   return successor;
00383 }
00384 
00385 
00386 /* Add a object to the data structure.  This involves
00387  * three steps.  First we append it to the dec list --
00388  * this is always correct because objects are presented
00389  * in dec order.  Second we insert it into the ra list.
00390  * And finally we update the ra index. */
00391 void ALStructure::add(ActiveObject * object)
00392 {
00393   ALNode * currentNode = rootNode;
00394   ALNode * parentNode;
00395 
00396   double ra = object->getObject()->getRa();
00397 
00398   /* search the ra index for an insertion object. */
00399   while (true)
00400   {
00401     parentNode = currentNode;
00402     ALElement * element = currentNode->getElement();
00403     if (element == tail)
00404     {
00405       // this is the sentinel node, which is by definition
00406       // greater than c.  So search to the left.
00407       currentNode = currentNode->getLeftChild();
00408       if (currentNode == 0)
00409       {
00410         // we're at a leaf.  Insert an element into
00411         // the lists here...
00412         ALElement * newElement = insertNew(object, parentNode->getElement(), tail);
00413 
00414         // ... then update the index.
00415         ALNode * newNode = new ALNode(newElement, 0, 0);
00416         parentNode->setLeftChild(newNode);
00417         return;
00418       }
00419     }
00420     else
00421     {
00422       // this is a normal element.  Check the content to
00423       // determine whether to insert our new element
00424       // before or after this element.
00425       ActiveObject * current = element->getContent();
00426       if (ra < current->getObject()->getRa())
00427       {
00428         // we'll need to insert before.  Look to the left.
00429         currentNode = currentNode->getLeftChild();
00430         if (currentNode == 0)
00431         {
00432           // we're at a leaf, insert an element into
00433           // the lists here...
00434           ALElement * newElement = insertNew(object, parentNode->getElement(), tail);
00435 
00436           // ... then update the index.
00437           ALNode * newNode = new ALNode(newElement, 0, 0);
00438           parentNode->setLeftChild(newNode);
00439           return;
00440         }
00441       }
00442       else
00443       {
00444         // we'll need to insert after.  Look to the right.
00445         currentNode = currentNode->getRightChild();
00446         if (currentNode == 0)
00447         {
00448           // we're at a leaf.  Insert an element into
00449           // the lists here...
00450           ALElement * newElement = insertNew(object, parentNode->getElement()->getNextRa(), tail);
00451 
00452           // ... then update the index.
00453           ALNode * newNode = new ALNode(newElement, 0, 0);
00454           parentNode->setRightChild(newNode);
00455           return;
00456         }
00457       }
00458     }
00459   }
00460 }
00461 
00462 /* This method just handles the list insertion component of adding
00463  * a new element to the data structure.  nextRa and nextDec are
00464  * guaranteed to be non-null, because of the existence of the
00465  * sentinel, but there is no guarantee that prevRa and prevDec are
00466  * non-null.  So we have to be careful */
00467 ALElement * ALStructure::insertNew(ActiveObject * object,
00468                                    ALElement * nextRa,
00469                                    ALElement * nextDec)
00470 {
00471   // locate the previous elements.
00472   ALElement * prevRa = nextRa->getPrevRa();
00473   ALElement * prevDec = nextDec->getPrevDec();
00474 
00475   // create a new element.
00476   ALElement * element = new ALElement(object, prevRa, nextRa, prevDec, nextDec);
00477 
00478   // correct the next elements' previous objecters.
00479   nextRa->setPrevRa(element);
00480   nextDec->setPrevDec(element);
00481 
00482   // if we are inserting at the head, then there is no
00483   // previous element needing to be updated, but we do
00484   // have to update the head objecters
00485   if (prevRa == 0)
00486   {
00487     raHead = element;
00488   }
00489   else      // otherwise, correct the previous elements' next objecters.
00490   {
00491     prevRa->setNextRa(element);
00492   }
00493 
00494   // if we are inserting at the head, then there is no
00495   // previous element needing to be updated, but we do
00496   // have to update the head objecters
00497   if (prevDec == 0)
00498   {
00499     decHead = element;
00500   }
00501   else
00502   {         // otherwise, correct the previous elements' next pointers.
00503     prevDec->setNextDec(element);
00504   }
00505 
00506   size++;
00507 
00508   return element;
00509 }
00510 
00511 unsigned int ALStructure::getSize()
00512 {
00513   return size;
00514 }
Generated on Mon Oct 4 10:39:55 2010 for Matching.kdevelop by  doxygen 1.6.3