home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmtbtree.cc < prev    next >
Encoding:
Text File  |  1994-09-06  |  19.1 KB  |  642 lines

  1. // CmTBTree.cc
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // BTree template implementation.
  7. // -----------------------------------------------------------------
  8.  
  9.  
  10. // "CmTBTree" is the default tree constructor.
  11. //
  12. template <class T> CmTBTree<T>::CmTBTree(unsigned ordr)
  13. {
  14.   _order = (ordr >= 3) ? ordr : 3;
  15.   _root  = NULL;
  16. }
  17.  
  18.  
  19. // "CmTBTree" is the tree copy constructor.
  20. //
  21. template <class T> CmTBTree<T>::CmTBTree(const CmTBTree<T>& Tr)
  22.                               : CmTContainer<T>(Tr)
  23. {
  24.   _order = Tr._order;
  25.   _root  = NULL;
  26.   copy(Tr);
  27. }
  28.  
  29.  
  30. // "~CmTBTree" is the tree destructor.
  31. //
  32. template <class T> CmTBTree<T>::~CmTBTree()
  33. {
  34.   removeAll();
  35. }
  36.  
  37.  
  38. // "=" assignment operator copies the specified tree into this tree.
  39. //
  40. template <class T> CmTBTree<T>& CmTBTree<T>::operator=(const CmTBTree<T>& Tr)
  41. {
  42.   if (&Tr != this)
  43.   {
  44.     removeAll();
  45.     _order = Tr._order;
  46.     copy(Tr);
  47.   }
  48.   return *this;
  49. }
  50.  
  51.  
  52. // "order" returns the tree order.
  53. //
  54. template <class T> unsigned CmTBTree<T>::order() const
  55. {
  56.   return _order;
  57. }
  58.  
  59.  
  60. // "height" returns the current tree height.
  61. //
  62. template <class T> unsigned CmTBTree<T>::height() const
  63. {
  64.   CmTBTreeNode<T> *rover = _root;
  65.   unsigned         ht    = 0;
  66.   while (rover)
  67.   {
  68.     ht++;
  69.     rover = rover->_children[0];
  70.   }
  71.   return ht;
  72. }
  73.  
  74.  
  75. // "add" adds a new item to this tree.
  76. //
  77. template <class T> Bool CmTBTree<T>::add(const T& rObj)
  78. {
  79.   T                data  = rObj;             // Initialize data object.
  80.   CmTBTreeNode<T> *child = NULL;             // Initialize child.
  81.   CmTBTreeNode<T> *rover = nodeSearch(rObj); // Find node to insert into.
  82.   Bool             done  = FALSE;            // Loop flag.
  83.  
  84.   while (rover && !done)                     // Loop.
  85.   {
  86.     int idx = rover->shouldGo(data);         // Get position for new object.
  87.     rover->addAt(idx, data, child, 1);       // Add new data and child to node.
  88.     if (rover->_total <= _order-1)           // Data fits so exit.
  89.       done = TRUE;
  90.     else
  91.     {
  92.       data = rover->_data[(rover->_total) / 2];         // Data doesn't fit.
  93.       CmTBTreeNode<T> *newRight = rover->split(_order); // Split the node.
  94.       if (!newRight) return FALSE;                      // Split unsuccessful.
  95.       child = newRight;                                 // Set new child right.
  96.       rover = rover->_parent;                           // Move to parent.
  97.     }
  98.   }
  99.  
  100.   if (!done)                                    // Not done, create a
  101.   {                                             // new root.
  102.     CmTBTreeNode<T> *newRoot  = new CmTBTreeNode<T>(NULL, _order);
  103.     newRoot->_children[0] = _root;              // Old root is child of new.
  104.     newRoot->_children[1] = child;              // Stray child is also child.
  105.     newRoot->_data    [0] = data;               // Data is lone root object.
  106.     newRoot->_total       = 1;                  // New root contains 1.
  107.  
  108.     if (_root)                                  // Set parentage of children
  109.     {                                           // if not first time in.
  110.       child->_parent = newRoot;
  111.      _root->_parent  = newRoot;
  112.     }
  113.     _root = newRoot;                            // New root is now root.
  114.   }
  115.   _size++;                                      // Bump size and split.
  116.   return TRUE;
  117. }
  118.  
  119.  
  120. // "remove" removes an item equal to the specified item from the tree.
  121. //
  122. template <class T> Bool CmTBTree<T>::remove(const T& rObj)
  123. {
  124.   CmTBTreeNode<T> *node = lookupNode(rObj);     // Find node where object is.
  125.   if (!node) return FALSE;                      // No object, exit.
  126.  
  127.   int idx = node->index(rObj);                  // Get index of object in node.
  128.   if (idx == -1) return FALSE;                  // No object, exit.
  129.   _size--;                                      // Decrement size.
  130.  
  131.   if (node->_children[0])                       // If node is not leaf, swap
  132.   {                                             // object with object at left
  133.     CmTBTreeNode<T> *rover = node->_children[idx+1];  // most side of right.
  134.     while (rover->_children[0]) rover = rover->_children[0];
  135.     node->_data[idx] = rover->_data[0];
  136.     node = rover;
  137.     idx  = 0;
  138.   }
  139.  
  140.   node->removeAt(idx);                         // Remove object from node.
  141.   unsigned minkeys = minKeys(_order);          // Save min allowable keys.
  142.  
  143.   while (node != _root && node->_total < minkeys)  // Start looping if number
  144.   {                                                // of keys fell below min.
  145.     int nodeIdx = node->_parent->index(node);  // Save index of node in parent.
  146.     if (nodeIdx == -1) return FALSE;
  147.  
  148.     if (node->_parent->_children[nodeIdx+1])   // If node has a right sibling,
  149.     {
  150.       CmTBTreeNode<T> *sib = node->_parent->_children[nodeIdx+1];
  151.       CmTBTreeNode<T> *par = node->_parent;
  152.  
  153.       // If the right sibling has keys to spare, move the left most key in
  154.       // the right sibling up to the parent.  Take the parent key parenting
  155.       // this node and move that key into this node.  Exit.
  156.       if (sib->_total > minkeys)
  157.       {
  158.         node->addAt(node->_total, par->_data[nodeIdx], sib->_children[0], 1);
  159.         if (sib->_children[0]) sib->_children[0]->_parent = node;
  160.         par->_data[nodeIdx] = sib->_data[0];
  161.         sib->removeAt(0);
  162.         return TRUE;
  163.       }
  164.  
  165.       // The right sibling has no keys to spare, so we need to combine the
  166.       // remaining keys in this node with the parent key parenting this node
  167.       // and the keys of the right sibling to form one node.
  168.       node->addAt(node->_total, par->_data[nodeIdx], sib->_children[0], 1);
  169.       for (int ii = 0; ii < sib->_total; ii++)
  170.       {
  171.         node->addAt(node->_total, sib->_data[ii], sib->_children[ii+1], 1);
  172.         if (sib->_children[ii+1]) sib->_children[ii+1]->_parent = node;
  173.       }
  174.       delete sib;
  175.       par->removeAt(nodeIdx);
  176.       node = par;
  177.     }
  178.  
  179.     else if (node->_parent->_children[nodeIdx-1]) // If node has left sibling,
  180.     {
  181.       CmTBTreeNode<T> *sib = node->_parent->_children[nodeIdx-1];
  182.       CmTBTreeNode<T> *par = node->_parent;
  183.  
  184.       // If the left sibling has keys to spare, move the right most key in
  185.       // the left sibling up to the parent.  Take the parent key parenting
  186.       // the left sibling and move that key into this node.  Exit.
  187.       if (sib->_total > minkeys)
  188.       {
  189.         node->addAt(0, par->_data[nodeIdx-1], sib->_children[sib->_total], 0);
  190.         if (sib->_children[sib->_total])
  191.           sib->_children[sib->_total]->_parent = node;
  192.         par->_data[nodeIdx-1] = sib->_data[sib->_total-1];
  193.         sib->removeAt(sib->_total-1);
  194.         return TRUE;
  195.       }
  196.  
  197.       // The left sibling has no keys to spare, so we need to combine the
  198.       // keys in the left sibling with the parent key parenting the left
  199.       // sibling and the keys of this node to form one node.
  200.       sib->addAt(sib->_total, par->_data[nodeIdx-1], node->_children[0], 1);
  201.       for (int ii = 0; ii < node->_total; ii++)
  202.       {
  203.         sib->addAt(sib->_total, node->_data[ii], node->_children[ii+1], 1);
  204.         if (node->_children[ii+1]) node->_children[ii+1]->_parent = sib;
  205.       }
  206.       delete node;
  207.       par->removeAt(nodeIdx-1);
  208.       node = par;
  209.     }
  210.   }
  211.  
  212.   if (node->_total == 0)                // If only the root node is left,
  213.   {                                     // and it has no keys, then delete
  214.     CmTBTreeNode<T> *temp = _root;      // delete the root node and make
  215.     _root = _root->_children[0];        // it's left most child the new
  216.     delete temp;                        // root node.
  217.   }
  218.   if (_root && _root->_parent) _root->_parent = NULL;
  219.   return TRUE;
  220. }
  221.  
  222.  
  223. // "lookup" returns an item equal to the specified item in the tree.
  224. //
  225. template <class T> const T& CmTBTree<T>::lookup(const T& rObj) const
  226. {
  227.   if (!_root) return _error;                // Empty tree.
  228.  
  229.   CmTBTreeNode<T> *node = lookupNode(rObj); // Find node where object is.
  230.   if (!node) return _error;
  231.  
  232.   int idx = node->index(rObj);
  233.   return (idx == -1) ? _error : node->_data[idx];
  234. }
  235.  
  236.  
  237. // "contains" checks if the tree contains any items equal to the
  238. // specified item.
  239. //
  240. template <class T> Bool CmTBTree<T>::contains(const T& rObj) const
  241. {
  242.   if (!_root) return NULL;                  // Empty tree.
  243.  
  244.   CmTBTreeNode<T> *node = lookupNode(rObj); // Find node where object is.
  245.   if (!node) return FALSE;
  246.  
  247.   int idx = node->index(rObj);
  248.   return (idx != -1) ? TRUE : FALSE;
  249. }
  250.  
  251.  
  252. // "occurrences" counts the number of items equal to the specified
  253. // item in the tree.
  254. //
  255. template <class T> unsigned CmTBTree<T>::occurrences(const T& rObj) const
  256. {
  257.   unsigned            occur = 0;
  258.   CmTBTreeIterator<T> iterator(*this);
  259.   while (!iterator.done())
  260.     if (rObj == iterator.next()) occur++;
  261.   return occur;
  262. }
  263.  
  264.  
  265. // "removeAll" removes all items from the tree.
  266. //
  267. template <class T> void CmTBTree<T>::removeAll()
  268. {
  269.   removeNodes(_root);
  270.   _root = NULL;
  271.   _size = 0;
  272. }
  273.  
  274.  
  275. // "newIterator" creates and returns a tree iterator.
  276. //
  277. template <class T> CmTIterator<T>* CmTBTree<T>::newIterator() const
  278. {
  279.   return new CmTBTreeIterator<T>(*this);
  280. }
  281.  
  282.  
  283. // "nodeSearch" returns the node where the specified item should be
  284. // inserted.
  285. //
  286. template <class T>
  287. CmTBTreeNode<T>* CmTBTree<T>::nodeSearch(const T& rObj) const
  288. {
  289.   CmTBTreeNode<T> *rover = _root;
  290.   CmTBTreeNode<T> *found = NULL;
  291.  
  292.   while (rover && !found)
  293.   {
  294.     int idx = rover->shouldGo(rObj);
  295.     if (rover->_children[idx]) rover = rover->_children[idx];
  296.     else                       found = rover;
  297.   }
  298.   return found;
  299. }
  300.  
  301.  
  302. // "lookupNode" returns the node where the specified item is located.
  303. //
  304. template <class T>
  305. CmTBTreeNode<T>* CmTBTree<T>::lookupNode(const T& rObj) const
  306. {
  307.   if (!_root) return NULL;
  308.  
  309.   CmTBTreeNode<T> *rover = _root;         // Start at root node.
  310.   CmTBTreeNode<T> *ret   = NULL;
  311.   while (rover && !ret)
  312.   {
  313.     int idx = rover->index(rObj);         // Is object in node?
  314.     if (idx != -1)
  315.       ret = rover;                        // Yes.
  316.     else
  317.     {
  318.       idx   = rover->shouldGo(rObj);      // No.  Set node to point to
  319.       rover = rover->_children[idx];      // child where object would be.
  320.     }
  321.   }
  322.   return ret;
  323. }
  324.  
  325.  
  326. // "removeNodes" removes all the child nodes from the specified node.
  327. //
  328. template <class T> void CmTBTree<T>::removeNodes(CmTBTreeNode<T>* pNode)
  329. {
  330.   if (pNode)
  331.   {
  332.     for (int ii = 0; ii < pNode->_total; ii++)
  333.       removeNodes(pNode->_children[ii]);
  334.     removeNodes(pNode->_children[pNode->_total]);
  335.     delete pNode;
  336.   }
  337. }
  338.  
  339.  
  340. // "minKeys" returns the minimum number of items that a non-root node
  341. // can contain.
  342. //
  343. template <class T> unsigned CmTBTree<T>::minKeys(unsigned ordr)
  344. {
  345.   return (((ordr / 2) * 2) == ordr) ? (ordr / 2) - 1 : (ordr / 2);
  346. }
  347.  
  348.  
  349. // "CmTBTreeNode" is the node constructor.
  350. //
  351. template <class T>
  352. CmTBTreeNode<T>::CmTBTreeNode(CmTBTreeNode<T>* parent, unsigned order)
  353. {
  354.   _total    = 0;
  355.   _parent   = parent;
  356.   _data     = new T[order];
  357.   _children = new CmTBTreeNode<T>*[order+1];
  358.   if (_data && _children) clear(order);
  359. }
  360.  
  361.  
  362. // "~CmTBTreeNode" is the node destructor.
  363. //
  364. template <class T> CmTBTreeNode<T>::~CmTBTreeNode()
  365. {
  366.   delete[] _data;
  367.   delete[] _children;
  368. }
  369.  
  370.  
  371. // "shouldGo" returns the index where the specified object should
  372. // be inserted in the data list.
  373. //
  374. template <class T> int CmTBTreeNode<T>::shouldGo(const T& rObj)
  375. {
  376.   if (_total == 0) return 0;
  377.  
  378.   if (rObj <  _data[0])        return 0;
  379.   if (rObj >= _data[_total-1]) return _total;
  380.  
  381.   int idx = -1, ii = _total - 1;
  382.   while (ii >= 0 && idx == -1)
  383.     if (rObj >= _data[ii--]) idx = ii+2;
  384.   return idx;
  385. }
  386.  
  387.  
  388. // "index" returns the index of the specified item in the data list.
  389. //
  390. template <class T> int CmTBTreeNode<T>::index(const T& rObj)
  391. {
  392.   if (_total == 0) return -1;
  393.   int idx = -1, ii = 0;
  394.   while (ii < _total && idx == -1)
  395.     if (rObj == _data[ii++]) idx = ii-1;
  396.   return idx;
  397. }
  398.  
  399.  
  400. // "index" returns the index of the specified node in the child list.
  401. //
  402. template <class T> int CmTBTreeNode<T>::index(CmTBTreeNode<T>* pNode)
  403. {
  404.   if (_total == 0 || !pNode) return -1;
  405.   int idx = -1, ii = 0;
  406.   while (ii <= _total && idx == -1)
  407.     if (pNode == _children[ii++]) idx = ii-1;
  408.   return idx;
  409. }
  410.  
  411.  
  412. // "addAt" adds the specified item/child pair at the specified index.
  413. //
  414. template <class T>
  415. Bool CmTBTreeNode<T>::addAt(int idx, const T& rObj, CmTBTreeNode<T>* pNode,
  416.                             int offset)
  417. {
  418.   if (offset == 0) _children[_total+1] = _children[_total];
  419.   for (int ii = _total; ii > idx; ii--)     // Slide other stuff to make
  420.   {                                         // room.
  421.     _data    [ii       ] = _data    [ii-1];
  422.     _children[ii+offset] = _children[ii+offset-1];
  423.   }
  424.  
  425.   _data    [idx       ] = rObj;             // Insert object and child.
  426.   _children[idx+offset] = pNode;
  427.   _total++;
  428.   return TRUE;
  429. }
  430.  
  431.  
  432. // "removeAt" removes the item/child pairs at the specified index.
  433. //
  434. template <class T> Bool CmTBTreeNode<T>::removeAt(int idx)
  435. {
  436.   if (idx < 0 || idx >= _total) return FALSE;
  437.  
  438.   for (int ii = idx; ii < _total-1; ii++)
  439.   {
  440.     _data    [ii  ] = _data    [ii+1];
  441.     _children[ii+1] = _children[ii+2];
  442.   }
  443.   _children[_total  ] = NULL;
  444.   _total--;
  445.   return TRUE;
  446. }
  447.  
  448.  
  449. // "clear" nulls out all the child pointers in the node.
  450. //
  451. template <class T> void CmTBTreeNode<T>::clear(int order)
  452. {
  453.   for (int ii = 0; ii <= order; ii++)
  454.     _children[ii] = NULL;
  455. }
  456.  
  457.  
  458. // "split" splits the node returning the new right node.
  459. //
  460. template <class T> CmTBTreeNode<T>* CmTBTreeNode<T>::split(unsigned ordr)
  461. {
  462.   CmTBTreeNode<T> *newRight = new CmTBTreeNode<T>(_parent, ordr);
  463.   if (!newRight) return NULL;
  464.  
  465.   int ix = 0, midIdx = _total / 2;
  466.   for (int ii = midIdx+1; ii <= _total; ii++, ix++)
  467.   {
  468.     if (ii != _total)
  469.     {
  470.       newRight->_data[ix] = _data[ii];
  471.       newRight->_total++;
  472.     }
  473.     newRight->_children[ix] = _children[ii];
  474.     _children[ii] = NULL;
  475.     if (newRight->_children[ix]) newRight->_children[ix]->_parent = newRight;
  476.   }
  477.   _total = midIdx;
  478.   return newRight;
  479. }
  480.  
  481.  
  482. // "CmTBTreeIterator" is the iterator constructor.
  483. //
  484. template <class T> CmTBTreeIterator<T>::CmTBTreeIterator(const CmTBTree<T> &Tr)
  485.                                        : _tree(Tr)
  486. {
  487.   _node  = _tree._root;
  488.   _index = 0;
  489.   if (_node)                                 // Descend all the way down left.
  490.     while (_node->_children[0])
  491.       _node = _node->_children[0];
  492. }
  493.  
  494.  
  495. // "done" checks if the iterator is at the end of the tree.
  496. //
  497. template <class T> Bool CmTBTreeIterator<T>::done() const
  498. {
  499.   return (!_node);
  500. }
  501.  
  502.  
  503. // "next" returns the current item and advances the iterator.
  504. //
  505. template <class T> const T& CmTBTreeIterator<T>::next()
  506. {
  507.   const T& retValue = current();              // Save current item.
  508.  
  509.   if (_node->_children[_index+1])             // Traverse all the way down
  510.   {                                           // the left part of the next
  511.     _node = _node->_children[_index+1];       // child branch.
  512.     while (_node->_children[0])
  513.       _node = _node->_children[0];
  514.     _index = 0;
  515.     return retValue;
  516.   }
  517.  
  518.   if (_index < _node->_total-1)               // No child branches, but there
  519.   {                                           // are still objects in this
  520.     _index++;                                 // node so bump the index and
  521.     return retValue;                          // exit.
  522.   }
  523.  
  524.   Bool done = FALSE;                          // Need to back up the tree.
  525.   while (!done)
  526.   {
  527.     if (!_node->_parent)                      // If node has no parent, we
  528.     {                                         // are done iterating.
  529.       _node = NULL;
  530.       done  = TRUE;
  531.     }
  532.  
  533.     else                                      // Node has parent.
  534.     {
  535.       int idx = _node->_parent->index(_node); // What branch were we just in.
  536.       if (idx == -1)                          // Error! - shouldn't happen.
  537.       {
  538.         _node = NULL;
  539.         done  = TRUE;
  540.       }
  541.       else                                    // Got the branch.
  542.       {
  543.         _node = _node->_parent;               // Move up to parent.
  544.         if (idx < _node->_total)              // If not end of data list,
  545.         {                                     // bump index and exit.
  546.           _index = idx;
  547.           done = TRUE;
  548.         }
  549.       }
  550.     }
  551.   }
  552.   return retValue;                            // Return the object.
  553. }
  554.  
  555.  
  556. // "previous" backs the iterator up one item and returns that item.
  557. //
  558. template <class T> const T& CmTBTreeIterator<T>::previous()
  559. {
  560.   const T& retValue = current();              // Save current item.
  561.  
  562.   if (_node->_children[_index])               // Traverse all the way down
  563.   {                                           // the right part of the
  564.     _node = _node->_children[_index];         // previous child branch.
  565.     while (_node->_total && _node->_children[_node->_total-1])
  566.       _node = _node->_children[_node->_total];
  567.     _index = _node->_total-1;
  568.     return retValue;
  569.   }
  570.  
  571.   if (_index > 0)                             // No child branches, but there
  572.   {                                           // are still objects in this
  573.     _index--;                                 // node so decrement the index
  574.     return retValue;                          // and exit.
  575.   }
  576.  
  577.   Bool done = FALSE;                          // Need to back up the tree.
  578.   while (!done)
  579.   {
  580.     if (!_node->_parent)                      // If node has no parent, we
  581.     {                                         // are done iterating.
  582.       _node = NULL;
  583.       done  = TRUE;
  584.     }
  585.  
  586.     else                                      // Node has parent.
  587.     {
  588.       int idx = _node->_parent->index(_node); // What brach were we just in?
  589.       if (idx == -1)                          // Error! - shouldn't happen.
  590.       {
  591.         _node = NULL;
  592.         done  = TRUE;
  593.       }
  594.       else                                    // Got the branch.
  595.       {
  596.         _node = _node->_parent;               // Move up to parent.
  597.         if (idx > 0)                          // If not at beginning,
  598.         {                                     // decrement index and exit.
  599.           _index = idx - 1;
  600.           done   = TRUE;
  601.         }
  602.       }
  603.     }
  604.   }
  605.   return retValue;                            // Return the item.
  606. }
  607.  
  608.  
  609. // "current" returns the current item.
  610. //
  611. template <class T> const T& CmTBTreeIterator<T>::current() const
  612. {
  613.   return (_node) ? _node->_data[_index] : _tree._error;
  614. }
  615.  
  616.  
  617. // "first" moves the iterator to the first item.
  618. //
  619. template <class T> void CmTBTreeIterator<T>::first()
  620. {
  621.   _node  = _tree._root;
  622.   _index = 0;
  623.  
  624.   if (_node)
  625.     while (_node->_children[0])
  626.       _node = _node->_children[0];
  627. }
  628.  
  629.  
  630. // "last" moves the iterator to the last item.
  631. //
  632. template <class T> void CmTBTreeIterator<T>::last()
  633. {
  634.   _node = _tree._root;
  635.   if (_node)
  636.   {
  637.     while (_node->_children[_node->_total])
  638.       _node = _node->_children[_node->_total];
  639.     _index = _node->_total - 1;
  640.   }
  641. }
  642.