Advertisement
Guest User

IterableBinaryHeap

a guest
Nov 7th, 2013
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 12.06 KB | None | 0 0
  1. //////////////////////////////////////////////////////////////////////
  2. /// This file is subject to the terms and conditions defined in    ///
  3. /// file 'LICENSE.txt', which is part of this source code package. ///
  4. //////////////////////////////////////////////////////////////////////
  5. module org.ghrum.utilities.container.iterable_binary_heap;
  6.  
  7. ////////////////////////////////////////////////////////////////
  8. /// IMPORT                                                   ///
  9. ////////////////////////////////////////////////////////////////
  10. public import std.algorithm;
  11. public import std.range;
  12. public import std.exception;
  13. public import std.typecons;
  14. public import std.functional : binaryFun;
  15.  
  16. ////////////////////////////////////////////////////////////////
  17. /// \brief Node of a IterableBinaryHeap
  18. ////////////////////////////////////////////////////////////////
  19. private struct IterableNode(T)
  20. {
  21.     ////////////////////////////////////////////////////////////
  22.     ///!< Underlying container of the node
  23.     ////////////////////////////////////////////////////////////
  24.     T _container;
  25.  
  26.     ////////////////////////////////////////////////////////////
  27.     ///!< Length of the node
  28.     ////////////////////////////////////////////////////////////
  29.     size_t _length;
  30. }
  31.  
  32. ////////////////////////////////////////////////////////////////
  33. /// \brief Represent a binary heap that can be iterate
  34. ////////////////////////////////////////////////////////////////
  35. public struct IterableBinaryHeap(T, alias op = "a < b")
  36.     if (isRandomAccessRange!(T) || isRandomAccessRange!(typeof(T.init[]))) {
  37. private:
  38.     ////////////////////////////////////////////////////////////
  39.     /// \brief The compare binary function
  40.     ////////////////////////////////////////////////////////////
  41.     alias binaryFun!(op) Compare;
  42. public:
  43.     ////////////////////////////////////////////////////////////
  44.     /// \brief Constructor of a iterable binary heap
  45.     ///
  46.     /// \param container   The container to take ownership
  47.     /// \param initialSize The initial size of the heap
  48.     ////////////////////////////////////////////////////////////
  49.     this(T container, size_t initialSize = size_t.max)
  50.     {
  51.         acquire(container, initialSize);
  52.     }
  53.  
  54.     ////////////////////////////////////////////////////////////
  55.     /// \brief Takes ownership of a container.
  56.     ///
  57.     /// \param container   The container to take ownership
  58.     /// \param initialSize The initial size of the heap
  59.     ////////////////////////////////////////////////////////////
  60.     void acquire(T container, size_t initialSize = size_t.max)
  61.     {
  62.         _payload.refCountedStore.ensureInitialized();
  63.         _payload._container = move(container);
  64.         _payload._length = min(_payload._container.length, initialSize);
  65.  
  66.         if (_payload._length < 2)
  67.         {
  68.             return;
  69.         }
  70.  
  71.         for (auto i = (_payload._length - 2) / 2;i > 0; --i)
  72.             percolateDown(_payload._container, i, _payload._length);
  73.     }
  74.  
  75.     ////////////////////////////////////////////////////////////
  76.     /// \brief Takes ownership of a container assuming it was
  77.     ///        already organized as a heap
  78.     ///
  79.     /// \param container   The container to take ownership
  80.     /// \param initialSize The initial size of the heap
  81.     ////////////////////////////////////////////////////////////
  82.     void assume(T container, size_t initialSize = size_t.max)
  83.     {
  84.         _payload.refCountedStore.ensureInitialized();
  85.         _payload._container = container;
  86.         _payload._length = min(_payload._container.length, initialSize);
  87.     }
  88.  
  89.     ////////////////////////////////////////////////////////////
  90.     /// \brief Release the heap
  91.     ///
  92.     /// \return The portion of the heap from 0 ... length
  93.     ////////////////////////////////////////////////////////////
  94.     auto release()
  95.     {
  96.         if (_payload.refCountedStore.isInitialized)
  97.         {
  98.             auto result = _payload._container[0 .. _payload._length];
  99.             _payload = _payload.init;
  100.             return result;
  101.         }
  102.         else
  103.             return typeof(_payload._container[0 .. _payload._length]).init;
  104.     }
  105.  
  106.     ////////////////////////////////////////////////////////////
  107.     /// \brief Returns if the heap is empty
  108.     ///
  109.     /// \return True if the heap is empty
  110.     ////////////////////////////////////////////////////////////
  111.     @property
  112.     bool empty() const
  113.     {
  114.         return !_payload._length;
  115.     }
  116.  
  117.     ////////////////////////////////////////////////////////////
  118.     /// \brief Return a clone of this heap
  119.     ///
  120.     /// \return A clone of this heap
  121.     ////////////////////////////////////////////////////////////
  122.     @property
  123.     IterableBinaryHeap dup()
  124.     {
  125.         IterableBinaryHeap!(T, op) result;
  126.         if (_payload.refCountedStore.isInitialized)
  127.         {
  128.             result.assume(_payload._container.dup, _payload._length);
  129.         }
  130.         return result;
  131.     }
  132.  
  133.     ////////////////////////////////////////////////////////////
  134.     /// \brief Return the capacity of the underlying buffer
  135.     ///
  136.     /// \return The capacity of the underlying buffer
  137.     ////////////////////////////////////////////////////////////
  138.     @property
  139.     size_t capacity() const
  140.     {
  141.         if (!_payload.refCountedStore.isInitialized)
  142.             return 0;
  143.        
  144.         static if (is(typeof(_payload._container.capacity) : size_t))
  145.             return _payload._container.capacity;
  146.         else
  147.             return _payload._container.length;
  148.     }
  149.  
  150.     ////////////////////////////////////////////////////////////
  151.     /// \brief Return a copy of the front item
  152.     ///
  153.     /// \return A copy of the front item
  154.     ////////////////////////////////////////////////////////////
  155.     @property
  156.     ElementType!T front()
  157.     in
  158.     {
  159.         enforce( !empty );
  160.     }
  161.     body
  162.     {
  163.         return _payload._container.front;
  164.     }
  165.  
  166.     ////////////////////////////////////////////////////////////
  167.     /// \brief Clears the heap by deattaching the underlying
  168.     ///        buffer
  169.     ////////////////////////////////////////////////////////////
  170.     void clear()
  171.     {
  172.         _payload = _payload.init;
  173.     }
  174.  
  175.     ////////////////////////////////////////////////////////////
  176.     /// \brief Insert a new element into the heap
  177.     ///
  178.     /// \param item The item to insert to
  179.     ////////////////////////////////////////////////////////////
  180.     void insert(ElementType!T item)
  181.     {
  182.         static if (is(typeof(_payload._container.insertBack(item))))
  183.         {
  184.             _payload.refCountedStore.ensureInitialized();
  185.            
  186.             if (_payload._length == _payload._container.length)
  187.                 _payload._container.insertBack(item);
  188.             else
  189.                 _payload._container[_payload._length] = item;
  190.         }
  191.         else
  192.         {
  193.             enforce(_payload._length < _payload._container.length,
  194.                 "Cannot grow a heap created over a range");
  195.             _payload._container[_payload._length] = item;
  196.         }
  197.  
  198.         for(size_t i = (_payload._length),
  199.                    j = (_payload._length - 1) / 2; i; j = (i - 1) / 2)
  200.         {
  201.             if (!Compare(_payload._container[j], _payload._container[i]))
  202.                 break;
  203.  
  204.             swap(_payload._container, j, i);
  205.             i = j;
  206.         }
  207.         ++_payload._length;
  208.     }
  209.  
  210.     ////////////////////////////////////////////////////////////
  211.     /// \brief Removes the largest element from the heap
  212.     ////////////////////////////////////////////////////////////
  213.     void removeFront()
  214.     in
  215.     {
  216.         enforce( !empty );
  217.     }
  218.     body
  219.     {
  220.         if (_payload._length > 1)
  221.         {
  222.             auto p1 = moveFront(_payload._container[]);
  223.             auto p2 = moveAt(_payload._container, _payload._length - 1);
  224.             _payload._container.front = move(p2);
  225.             _payload._container[_payload._length - 1] = move(p1);
  226.         }
  227.         --_payload._length;
  228.         percolateDown(_payload._container, 0, _payload._length);
  229.     }
  230.  
  231.     ////////////////////////////////////////////////////////////
  232.     /// \brief Removes the largest element from the heap and
  233.     ///        return a copy of it
  234.     ///
  235.     /// \return The copy of the removed item
  236.     ////////////////////////////////////////////////////////////
  237.     ElementType!T removeAny()
  238.     {
  239.         removeFront();
  240.         return _payload._container[_payload._length];
  241.     }
  242.  
  243.     ////////////////////////////////////////////////////////////
  244.     /// \brief Replaces the largest element in the container
  245.     ///
  246.     /// \param item The new item to place the old item
  247.     ////////////////////////////////////////////////////////////
  248.     void replaceFront(ElementType!T item)
  249.     in
  250.     {
  251.         assert( !empty );
  252.     }
  253.     body
  254.     {
  255.         _payload._container.front = item;
  256.         percolateDown(_payload._container, 0, _payload._length);
  257.     }
  258.  
  259.     ////////////////////////////////////////////////////////////
  260.     /// \brief Returns the size of the underlying buffer
  261.     ///
  262.     /// \return The size of the underlying buffer
  263.     ////////////////////////////////////////////////////////////
  264.     @property
  265.     size_t length() const
  266.     {  
  267.         return _payload.refCountedStore.isInitialized ? _payload._length : 0;
  268.     }
  269.  
  270.     int opApply(int delegate(ref ElementType!T) callback)
  271.     {
  272.         int result = 0;
  273.         foreach(item; _payload._container)
  274.         {
  275.             result += callback(item);
  276.         }
  277.         return result;
  278.     }
  279. private:
  280.     ////////////////////////////////////////////////////////////
  281.     /// \brief Percolates the heap down such the heap property is
  282.     ///        restored
  283.     ///
  284.     /// \param container The underlying buffer
  285.     /// \param index     The index of the item
  286.     /// \param length    The length of the buffer
  287.     ////////////////////////////////////////////////////////////
  288.     static void percolateDown(T container, size_t index, size_t length)
  289.     {
  290.         bool isDone = false;
  291.         do
  292.         {
  293.             auto left  = index * 2 + 1;
  294.             auto right = left + 1;
  295.  
  296.             if (right == length)
  297.             {
  298.                 if (Compare(container[index], container[left]))
  299.                     swap(container, index, left);
  300.                 isDone = true;
  301.             }
  302.             else if(right > length)
  303.             {
  304.                 isDone = true;
  305.             }
  306.             else
  307.             {
  308.                 auto largest = Compare(container[index], container[left])
  309.                     ? (Compare(container[left], container[right])
  310.                             ? right : left)
  311.                     : (Compare(container[index], container[right])
  312.                             ? right : index);
  313.                 if (largest != index)
  314.                 {
  315.                     swap(container, index, largest);
  316.                     index = largest;
  317.                 }
  318.                 else
  319.                     isDone = true;
  320.             }
  321.         } while (!isDone);
  322.     }
  323.  
  324.     ////////////////////////////////////////////////////////////
  325.     /// \brief Swap index in a container
  326.     ///
  327.     /// \param container The underlying container
  328.     /// \param index     The index within the container
  329.     /// \param item      The item within the container
  330.     ////////////////////////////////////////////////////////////
  331.     static void swap(T container, size_t index, size_t item)
  332.     {
  333.         static if (is(typeof(container.moveAt(index))) ||
  334.                   !is(typeof(swap(container[index], container[item]))))
  335.         {
  336.             auto p1 = container.moveAt(index);
  337.             auto p2 = container.moveAt(item);
  338.             container[index] = move(p2);
  339.             container[item] = move(p1);
  340.         }
  341.         else
  342.             swap(container[index], container[item]);
  343.     }
  344. private:
  345.     ////////////////////////////////////////////////////////////
  346.     ///!< Payload of the heap
  347.     ////////////////////////////////////////////////////////////
  348.     RefCounted!(IterableNode!(T), RefCountedAutoInitialize.no) _payload;
  349. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement