stakach-algorithms 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +97 -0
 - data/Rakefile +27 -0
 - data/ext/containers/deque/deque.c +249 -0
 - data/ext/containers/deque/extconf.rb +4 -0
 - data/ext/containers/rbtree_map/extconf.rb +4 -0
 - data/ext/containers/rbtree_map/rbtree.c +500 -0
 - data/ext/containers/splaytree_map/extconf.rb +4 -0
 - data/ext/containers/splaytree_map/splaytree.c +421 -0
 - data/lib/algorithms/search.rb +86 -0
 - data/lib/algorithms/sort.rb +243 -0
 - data/lib/algorithms/string.rb +8 -0
 - data/lib/algorithms/version.rb +3 -0
 - data/lib/algorithms.rb +69 -0
 - data/lib/containers/deque.rb +176 -0
 - data/lib/containers/heap.rb +507 -0
 - data/lib/containers/kd_tree.rb +113 -0
 - data/lib/containers/priority_queue.rb +117 -0
 - data/lib/containers/queue.rb +72 -0
 - data/lib/containers/rb_tree_map.rb +402 -0
 - data/lib/containers/splay_tree_map.rb +273 -0
 - data/lib/containers/stack.rb +71 -0
 - data/lib/containers/suffix_array.rb +72 -0
 - data/lib/containers/trie.rb +188 -0
 - metadata +100 -0
 
| 
         @@ -0,0 +1,507 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            =begin rdoc
         
     | 
| 
      
 2 
     | 
    
         
            +
                A Heap is a container that satisfies the heap property that nodes are 
         
     | 
| 
      
 3 
     | 
    
         
            +
                always smaller in value than their parent node.
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                The Algorithms::Containers::Heap class is flexible and upon 
         
     | 
| 
      
 6 
     | 
    
         
            +
                initialization, takes an optional block that determines how the items are 
         
     | 
| 
      
 7 
     | 
    
         
            +
                ordered. Two versions that are included are the 
         
     | 
| 
      
 8 
     | 
    
         
            +
                Algorithms::Containers::MaxHeap and Algorithms::Containers::MinHeap that 
         
     | 
| 
      
 9 
     | 
    
         
            +
                return the largest and smallest items on each invocation, respectively.
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                This library implements a Fibonacci heap, which allows O(1) complexity for 
         
     | 
| 
      
 12 
     | 
    
         
            +
                most methods.
         
     | 
| 
      
 13 
     | 
    
         
            +
            =end
         
     | 
| 
      
 14 
     | 
    
         
            +
            module Algorithms
         
     | 
| 
      
 15 
     | 
    
         
            +
              module Containers
         
     | 
| 
      
 16 
     | 
    
         
            +
                class Heap
         
     | 
| 
      
 17 
     | 
    
         
            +
                  include Enumerable
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #     size -> int
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # Return the number of elements in the heap.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  def size
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @size
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  alias_method :length, :size
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #     Heap.new(optional_array) { |x, y| optional_comparison_fn } 
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #     -> new_heap
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # If an optional array is passed, the entries in the array are inserted 
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # into the heap with equal key and value fields. Also, an optional block 
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # can be passed to define the function that maintains heap property. For 
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # example, a min-heap can be created with:
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #     minheap = Heap.new { |x, y| (x <=> y) == -1 }
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #     minheap.push(6)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #     minheap.push(10)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #     minheap.pop #=> 6
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # Thus, smaller elements will be parent nodes. The heap defaults to a 
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # min-heap if no block is given.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  def initialize(ary=[], &block)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    @compare_fn = block || lambda { |x, y| (x <=> y) == -1 }
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @next = nil
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @size = 0
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @stored = {}
         
     | 
| 
      
 49 
     | 
    
         
            +
                
         
     | 
| 
      
 50 
     | 
    
         
            +
                    ary.each { |n| push(n) } unless ary.empty?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
              
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #     push(key, value) -> value
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #     push(value) -> value
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # 
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # Inserts an item with a given key into the heap. If only one parameter 
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # is given, the key is set to the value.
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # Complexity: O(1)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #     heap = MinHeap.new
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #     heap.push(1, "Cat")
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #     heap.push(2)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #     heap.pop #=> "Cat"
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #     heap.pop #=> 2
         
     | 
| 
      
 67 
     | 
    
         
            +
                  def push(key, value=key)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    raise ArgumentError, "Heap keys must not be nil." unless key
         
     | 
| 
      
 69 
     | 
    
         
            +
                    node = Node.new(key, value)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    # Add new node to the left of the @next node
         
     | 
| 
      
 71 
     | 
    
         
            +
                    if @next
         
     | 
| 
      
 72 
     | 
    
         
            +
                      node.right = @next
         
     | 
| 
      
 73 
     | 
    
         
            +
                      node.left = @next.left
         
     | 
| 
      
 74 
     | 
    
         
            +
                      node.left.right = node
         
     | 
| 
      
 75 
     | 
    
         
            +
                      @next.left = node
         
     | 
| 
      
 76 
     | 
    
         
            +
                      if @compare_fn[key, @next.key]
         
     | 
| 
      
 77 
     | 
    
         
            +
                        @next = node
         
     | 
| 
      
 78 
     | 
    
         
            +
                      end
         
     | 
| 
      
 79 
     | 
    
         
            +
                    else
         
     | 
| 
      
 80 
     | 
    
         
            +
                      @next = node
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                    @size += 1
         
     | 
| 
      
 83 
     | 
    
         
            +
                
         
     | 
| 
      
 84 
     | 
    
         
            +
                    arr = []
         
     | 
| 
      
 85 
     | 
    
         
            +
                    w = @next.right
         
     | 
| 
      
 86 
     | 
    
         
            +
                    until w == @next do
         
     | 
| 
      
 87 
     | 
    
         
            +
                      arr << w.value
         
     | 
| 
      
 88 
     | 
    
         
            +
                      w = w.right
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                    arr << @next.value
         
     | 
| 
      
 91 
     | 
    
         
            +
                    @stored[key] ||= []
         
     | 
| 
      
 92 
     | 
    
         
            +
                    @stored[key] << node
         
     | 
| 
      
 93 
     | 
    
         
            +
                    value
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  alias_method :<<, :push
         
     | 
| 
      
 96 
     | 
    
         
            +
              
         
     | 
| 
      
 97 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 98 
     | 
    
         
            +
                  #     has_key?(key) -> true or false
         
     | 
| 
      
 99 
     | 
    
         
            +
                  #
         
     | 
| 
      
 100 
     | 
    
         
            +
                  # Returns true if heap contains the key.
         
     | 
| 
      
 101 
     | 
    
         
            +
                  #
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # Complexity: O(1)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #
         
     | 
| 
      
 104 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2])
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #     minheap.has_key?(2) #=> true
         
     | 
| 
      
 106 
     | 
    
         
            +
                  #     minheap.has_key?(4) #=> false
         
     | 
| 
      
 107 
     | 
    
         
            +
                  def has_key?(key)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    @stored[key] && !@stored[key].empty? ? true : false
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
              
         
     | 
| 
      
 111 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 112 
     | 
    
         
            +
                  #     next -> value
         
     | 
| 
      
 113 
     | 
    
         
            +
                  #     next -> nil
         
     | 
| 
      
 114 
     | 
    
         
            +
                  #
         
     | 
| 
      
 115 
     | 
    
         
            +
                  # Returns the value of the next item in heap order, but does not remove 
         
     | 
| 
      
 116 
     | 
    
         
            +
                  # it.
         
     | 
| 
      
 117 
     | 
    
         
            +
                  #
         
     | 
| 
      
 118 
     | 
    
         
            +
                  # Complexity: O(1)
         
     | 
| 
      
 119 
     | 
    
         
            +
                  #
         
     | 
| 
      
 120 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2])
         
     | 
| 
      
 121 
     | 
    
         
            +
                  #     minheap.next #=> 1
         
     | 
| 
      
 122 
     | 
    
         
            +
                  #     minheap.size #=> 2
         
     | 
| 
      
 123 
     | 
    
         
            +
                  def next
         
     | 
| 
      
 124 
     | 
    
         
            +
                    @next && @next.value
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
      
 126 
     | 
    
         
            +
              
         
     | 
| 
      
 127 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 128 
     | 
    
         
            +
                  #     clear -> nil
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #
         
     | 
| 
      
 130 
     | 
    
         
            +
                  # Removes all elements from the heap, destructively.
         
     | 
| 
      
 131 
     | 
    
         
            +
                  #
         
     | 
| 
      
 132 
     | 
    
         
            +
                  # Complexity: O(1)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  #
         
     | 
| 
      
 134 
     | 
    
         
            +
                  def clear
         
     | 
| 
      
 135 
     | 
    
         
            +
                    @next = nil
         
     | 
| 
      
 136 
     | 
    
         
            +
                    @size = 0
         
     | 
| 
      
 137 
     | 
    
         
            +
                    @stored = {}
         
     | 
| 
      
 138 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
              
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 142 
     | 
    
         
            +
                  #     empty? -> true or false
         
     | 
| 
      
 143 
     | 
    
         
            +
                  #
         
     | 
| 
      
 144 
     | 
    
         
            +
                  # Returns true if the heap is empty, false otherwise.
         
     | 
| 
      
 145 
     | 
    
         
            +
                  def empty?
         
     | 
| 
      
 146 
     | 
    
         
            +
                    @next.nil?
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
              
         
     | 
| 
      
 149 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 150 
     | 
    
         
            +
                  #     merge!(otherheap) -> merged_heap
         
     | 
| 
      
 151 
     | 
    
         
            +
                  #
         
     | 
| 
      
 152 
     | 
    
         
            +
                  # Does a shallow merge of all the nodes in the other heap.
         
     | 
| 
      
 153 
     | 
    
         
            +
                  #
         
     | 
| 
      
 154 
     | 
    
         
            +
                  # Complexity: O(1)
         
     | 
| 
      
 155 
     | 
    
         
            +
                  #
         
     | 
| 
      
 156 
     | 
    
         
            +
                  #     heap = MinHeap.new([5, 6, 7, 8])
         
     | 
| 
      
 157 
     | 
    
         
            +
                  #     otherheap = MinHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 158 
     | 
    
         
            +
                  #     heap.merge!(otherheap)
         
     | 
| 
      
 159 
     | 
    
         
            +
                  #     heap.size #=> 8
         
     | 
| 
      
 160 
     | 
    
         
            +
                  #     heap.pop #=> 1
         
     | 
| 
      
 161 
     | 
    
         
            +
                  def merge!(otherheap)
         
     | 
| 
      
 162 
     | 
    
         
            +
                    raise ArgumentError, "Trying to merge a heap with something not a heap" unless otherheap.kind_of? Heap
         
     | 
| 
      
 163 
     | 
    
         
            +
                    other_root = otherheap.instance_variable_get("@next")
         
     | 
| 
      
 164 
     | 
    
         
            +
                    if other_root
         
     | 
| 
      
 165 
     | 
    
         
            +
                      @stored = @stored.merge(otherheap.instance_variable_get("@stored")) { |key, a, b| (a << b).flatten }
         
     | 
| 
      
 166 
     | 
    
         
            +
                      # Insert othernode's @next node to the left of current @next
         
     | 
| 
      
 167 
     | 
    
         
            +
                      @next.left.right = other_root
         
     | 
| 
      
 168 
     | 
    
         
            +
                      ol = other_root.left
         
     | 
| 
      
 169 
     | 
    
         
            +
                      other_root.left = @next.left
         
     | 
| 
      
 170 
     | 
    
         
            +
                      ol.right = @next
         
     | 
| 
      
 171 
     | 
    
         
            +
                      @next.left = ol
         
     | 
| 
      
 172 
     | 
    
         
            +
                  
         
     | 
| 
      
 173 
     | 
    
         
            +
                      @next = other_root if @compare_fn[other_root.key, @next.key]
         
     | 
| 
      
 174 
     | 
    
         
            +
                    end
         
     | 
| 
      
 175 
     | 
    
         
            +
                    @size += otherheap.size
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
              
         
     | 
| 
      
 178 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 179 
     | 
    
         
            +
                  #     pop -> value
         
     | 
| 
      
 180 
     | 
    
         
            +
                  #     pop -> nil
         
     | 
| 
      
 181 
     | 
    
         
            +
                  #
         
     | 
| 
      
 182 
     | 
    
         
            +
                  # Returns the value of the next item in heap order and removes it from 
         
     | 
| 
      
 183 
     | 
    
         
            +
                  # the heap.
         
     | 
| 
      
 184 
     | 
    
         
            +
                  #
         
     | 
| 
      
 185 
     | 
    
         
            +
                  # Complexity: O(1)
         
     | 
| 
      
 186 
     | 
    
         
            +
                  #
         
     | 
| 
      
 187 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2])
         
     | 
| 
      
 188 
     | 
    
         
            +
                  #     minheap.pop #=> 1
         
     | 
| 
      
 189 
     | 
    
         
            +
                  #     minheap.size #=> 1
         
     | 
| 
      
 190 
     | 
    
         
            +
                  def pop
         
     | 
| 
      
 191 
     | 
    
         
            +
                    return nil unless @next
         
     | 
| 
      
 192 
     | 
    
         
            +
                    popped = @next
         
     | 
| 
      
 193 
     | 
    
         
            +
                    if @size == 1
         
     | 
| 
      
 194 
     | 
    
         
            +
                      clear
         
     | 
| 
      
 195 
     | 
    
         
            +
                      return popped.value
         
     | 
| 
      
 196 
     | 
    
         
            +
                    end
         
     | 
| 
      
 197 
     | 
    
         
            +
                    # Merge the popped's children into root node
         
     | 
| 
      
 198 
     | 
    
         
            +
                    if @next.child
         
     | 
| 
      
 199 
     | 
    
         
            +
                      @next.child.parent = nil
         
     | 
| 
      
 200 
     | 
    
         
            +
                  
         
     | 
| 
      
 201 
     | 
    
         
            +
                      # get rid of parent
         
     | 
| 
      
 202 
     | 
    
         
            +
                      sibling = @next.child.right
         
     | 
| 
      
 203 
     | 
    
         
            +
                      until sibling == @next.child
         
     | 
| 
      
 204 
     | 
    
         
            +
                        sibling.parent = nil
         
     | 
| 
      
 205 
     | 
    
         
            +
                        sibling = sibling.right
         
     | 
| 
      
 206 
     | 
    
         
            +
                      end
         
     | 
| 
      
 207 
     | 
    
         
            +
                  
         
     | 
| 
      
 208 
     | 
    
         
            +
                      # Merge the children into the root. If @next is the only root node, 
         
     | 
| 
      
 209 
     | 
    
         
            +
                      # make its child the @next node
         
     | 
| 
      
 210 
     | 
    
         
            +
                      if @next.right == @next
         
     | 
| 
      
 211 
     | 
    
         
            +
                        @next = @next.child
         
     | 
| 
      
 212 
     | 
    
         
            +
                      else
         
     | 
| 
      
 213 
     | 
    
         
            +
                        next_left, next_right = @next.left, @next.right
         
     | 
| 
      
 214 
     | 
    
         
            +
                        current_child = @next.child
         
     | 
| 
      
 215 
     | 
    
         
            +
                        @next.right.left = current_child
         
     | 
| 
      
 216 
     | 
    
         
            +
                        @next.left.right = current_child.right
         
     | 
| 
      
 217 
     | 
    
         
            +
                        current_child.right.left = next_left
         
     | 
| 
      
 218 
     | 
    
         
            +
                        current_child.right = next_right
         
     | 
| 
      
 219 
     | 
    
         
            +
                        @next = @next.right
         
     | 
| 
      
 220 
     | 
    
         
            +
                      end
         
     | 
| 
      
 221 
     | 
    
         
            +
                    else
         
     | 
| 
      
 222 
     | 
    
         
            +
                      @next.left.right = @next.right
         
     | 
| 
      
 223 
     | 
    
         
            +
                      @next.right.left = @next.left
         
     | 
| 
      
 224 
     | 
    
         
            +
                      @next = @next.right
         
     | 
| 
      
 225 
     | 
    
         
            +
                    end
         
     | 
| 
      
 226 
     | 
    
         
            +
                    consolidate
         
     | 
| 
      
 227 
     | 
    
         
            +
                
         
     | 
| 
      
 228 
     | 
    
         
            +
                    unless @stored[popped.key].delete(popped)
         
     | 
| 
      
 229 
     | 
    
         
            +
                      raise "Couldn't delete node from stored nodes hash" 
         
     | 
| 
      
 230 
     | 
    
         
            +
                    end
         
     | 
| 
      
 231 
     | 
    
         
            +
                    @size -= 1
         
     | 
| 
      
 232 
     | 
    
         
            +
                
         
     | 
| 
      
 233 
     | 
    
         
            +
                    popped.value
         
     | 
| 
      
 234 
     | 
    
         
            +
                  end
         
     | 
| 
      
 235 
     | 
    
         
            +
                  alias_method :next!, :pop
         
     | 
| 
      
 236 
     | 
    
         
            +
              
         
     | 
| 
      
 237 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 238 
     | 
    
         
            +
                  #     change_key(key, new_key) -> [new_key, value]
         
     | 
| 
      
 239 
     | 
    
         
            +
                  #     change_key(key, new_key) -> nil
         
     | 
| 
      
 240 
     | 
    
         
            +
                  #
         
     | 
| 
      
 241 
     | 
    
         
            +
                  # Changes the key from one to another. Doing so must not violate the 
         
     | 
| 
      
 242 
     | 
    
         
            +
                  # heap property or an exception will be raised. If the key is found, an 
         
     | 
| 
      
 243 
     | 
    
         
            +
                  # array containing the new key and  value pair is returned, otherwise 
         
     | 
| 
      
 244 
     | 
    
         
            +
                  # nil is returned. 
         
     | 
| 
      
 245 
     | 
    
         
            +
                  #
         
     | 
| 
      
 246 
     | 
    
         
            +
                  # In the case of duplicate keys, an arbitrary key is changed. This will 
         
     | 
| 
      
 247 
     | 
    
         
            +
                  # be investigated more in the future.
         
     | 
| 
      
 248 
     | 
    
         
            +
                  #
         
     | 
| 
      
 249 
     | 
    
         
            +
                  # Complexity: amortized O(1)
         
     | 
| 
      
 250 
     | 
    
         
            +
                  # 
         
     | 
| 
      
 251 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2])
         
     | 
| 
      
 252 
     | 
    
         
            +
                  #     minheap.change_key(2, 3) #=> raise error since we can't increase the value in a min-heap
         
     | 
| 
      
 253 
     | 
    
         
            +
                  #     minheap.change_key(2, 0) #=> [0, 2]
         
     | 
| 
      
 254 
     | 
    
         
            +
                  #     minheap.pop #=> 2
         
     | 
| 
      
 255 
     | 
    
         
            +
                  #     minheap.pop #=> 1
         
     | 
| 
      
 256 
     | 
    
         
            +
                  def change_key(key, new_key, delete=false)
         
     | 
| 
      
 257 
     | 
    
         
            +
                    return if @stored[key].nil? || @stored[key].empty? || (key == new_key)
         
     | 
| 
      
 258 
     | 
    
         
            +
                
         
     | 
| 
      
 259 
     | 
    
         
            +
                    # Must maintain heap property
         
     | 
| 
      
 260 
     | 
    
         
            +
                    raise "Changing this key would not maintain heap property!" unless (delete || @compare_fn[new_key, key])
         
     | 
| 
      
 261 
     | 
    
         
            +
                    node = @stored[key].shift
         
     | 
| 
      
 262 
     | 
    
         
            +
                    if node
         
     | 
| 
      
 263 
     | 
    
         
            +
                      node.key = new_key
         
     | 
| 
      
 264 
     | 
    
         
            +
                      @stored[new_key] ||= []
         
     | 
| 
      
 265 
     | 
    
         
            +
                      @stored[new_key] << node
         
     | 
| 
      
 266 
     | 
    
         
            +
                      parent = node.parent
         
     | 
| 
      
 267 
     | 
    
         
            +
                      if parent
         
     | 
| 
      
 268 
     | 
    
         
            +
                        # if heap property is violated
         
     | 
| 
      
 269 
     | 
    
         
            +
                        if delete || @compare_fn[new_key, parent.key]
         
     | 
| 
      
 270 
     | 
    
         
            +
                          cut(node, parent)
         
     | 
| 
      
 271 
     | 
    
         
            +
                          cascading_cut(parent)
         
     | 
| 
      
 272 
     | 
    
         
            +
                        end
         
     | 
| 
      
 273 
     | 
    
         
            +
                      end
         
     | 
| 
      
 274 
     | 
    
         
            +
                      if delete || @compare_fn[node.key, @next.key]
         
     | 
| 
      
 275 
     | 
    
         
            +
                        @next = node
         
     | 
| 
      
 276 
     | 
    
         
            +
                      end
         
     | 
| 
      
 277 
     | 
    
         
            +
                      return [node.key, node.value]
         
     | 
| 
      
 278 
     | 
    
         
            +
                    end
         
     | 
| 
      
 279 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 280 
     | 
    
         
            +
                  end
         
     | 
| 
      
 281 
     | 
    
         
            +
              
         
     | 
| 
      
 282 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 283 
     | 
    
         
            +
                  #     delete(key) -> value
         
     | 
| 
      
 284 
     | 
    
         
            +
                  #     delete(key) -> nil
         
     | 
| 
      
 285 
     | 
    
         
            +
                  #
         
     | 
| 
      
 286 
     | 
    
         
            +
                  # Deletes the item with associated key and returns it. nil is returned 
         
     | 
| 
      
 287 
     | 
    
         
            +
                  # if the keyis not found. In the case of nodes with duplicate keys, an 
         
     | 
| 
      
 288 
     | 
    
         
            +
                  # arbitrary one is deleted.
         
     | 
| 
      
 289 
     | 
    
         
            +
                  #
         
     | 
| 
      
 290 
     | 
    
         
            +
                  # Complexity: amortized O(log n)
         
     | 
| 
      
 291 
     | 
    
         
            +
                  #
         
     | 
| 
      
 292 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2])
         
     | 
| 
      
 293 
     | 
    
         
            +
                  #     minheap.delete(1) #=> 1
         
     | 
| 
      
 294 
     | 
    
         
            +
                  #     minheap.size #=> 1
         
     | 
| 
      
 295 
     | 
    
         
            +
                  def delete(key)
         
     | 
| 
      
 296 
     | 
    
         
            +
                    pop if change_key(key, nil, true)
         
     | 
| 
      
 297 
     | 
    
         
            +
                  end
         
     | 
| 
      
 298 
     | 
    
         
            +
              
         
     | 
| 
      
 299 
     | 
    
         
            +
                  # Node class used internally
         
     | 
| 
      
 300 
     | 
    
         
            +
                  class Node # :nodoc:
         
     | 
| 
      
 301 
     | 
    
         
            +
                    attr_accessor :parent, :child, :left, :right, :key, :value, :degree, :marked
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                    def initialize(key, value)
         
     | 
| 
      
 304 
     | 
    
         
            +
                      @key = key
         
     | 
| 
      
 305 
     | 
    
         
            +
                      @value = value
         
     | 
| 
      
 306 
     | 
    
         
            +
                      @degree = 0
         
     | 
| 
      
 307 
     | 
    
         
            +
                      @marked = false
         
     | 
| 
      
 308 
     | 
    
         
            +
                      @right = self
         
     | 
| 
      
 309 
     | 
    
         
            +
                      @left = self
         
     | 
| 
      
 310 
     | 
    
         
            +
                    end
         
     | 
| 
      
 311 
     | 
    
         
            +
                
         
     | 
| 
      
 312 
     | 
    
         
            +
                    def marked?
         
     | 
| 
      
 313 
     | 
    
         
            +
                      @marked == true
         
     | 
| 
      
 314 
     | 
    
         
            +
                    end
         
     | 
| 
      
 315 
     | 
    
         
            +
                
         
     | 
| 
      
 316 
     | 
    
         
            +
                  end
         
     | 
| 
      
 317 
     | 
    
         
            +
              
         
     | 
| 
      
 318 
     | 
    
         
            +
                  # make node a child of a parent node
         
     | 
| 
      
 319 
     | 
    
         
            +
                  def link_nodes(child, parent)
         
     | 
| 
      
 320 
     | 
    
         
            +
                    # link the child's siblings
         
     | 
| 
      
 321 
     | 
    
         
            +
                    child.left.right = child.right
         
     | 
| 
      
 322 
     | 
    
         
            +
                    child.right.left = child.left
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                    child.parent = parent
         
     | 
| 
      
 325 
     | 
    
         
            +
                
         
     | 
| 
      
 326 
     | 
    
         
            +
                    # if parent doesn't have children, make new child its only child
         
     | 
| 
      
 327 
     | 
    
         
            +
                    if parent.child.nil?
         
     | 
| 
      
 328 
     | 
    
         
            +
                      parent.child = child.right = child.left = child
         
     | 
| 
      
 329 
     | 
    
         
            +
                    else # otherwise insert new child into parent's children list
         
     | 
| 
      
 330 
     | 
    
         
            +
                      current_child = parent.child
         
     | 
| 
      
 331 
     | 
    
         
            +
                      child.left = current_child
         
     | 
| 
      
 332 
     | 
    
         
            +
                      child.right = current_child.right
         
     | 
| 
      
 333 
     | 
    
         
            +
                      current_child.right.left = child
         
     | 
| 
      
 334 
     | 
    
         
            +
                      current_child.right = child
         
     | 
| 
      
 335 
     | 
    
         
            +
                    end
         
     | 
| 
      
 336 
     | 
    
         
            +
                    parent.degree += 1
         
     | 
| 
      
 337 
     | 
    
         
            +
                    child.marked = false
         
     | 
| 
      
 338 
     | 
    
         
            +
                  end
         
     | 
| 
      
 339 
     | 
    
         
            +
                  private :link_nodes
         
     | 
| 
      
 340 
     | 
    
         
            +
              
         
     | 
| 
      
 341 
     | 
    
         
            +
                  # Makes sure the structure does not contain nodes in the root list with 
         
     | 
| 
      
 342 
     | 
    
         
            +
                  # equal degrees
         
     | 
| 
      
 343 
     | 
    
         
            +
                  def consolidate
         
     | 
| 
      
 344 
     | 
    
         
            +
                    roots = []
         
     | 
| 
      
 345 
     | 
    
         
            +
                    root = @next
         
     | 
| 
      
 346 
     | 
    
         
            +
                    min = root
         
     | 
| 
      
 347 
     | 
    
         
            +
                    # find the nodes in the list
         
     | 
| 
      
 348 
     | 
    
         
            +
                    loop do
         
     | 
| 
      
 349 
     | 
    
         
            +
                      roots << root
         
     | 
| 
      
 350 
     | 
    
         
            +
                      root = root.right
         
     | 
| 
      
 351 
     | 
    
         
            +
                      break if root == @next
         
     | 
| 
      
 352 
     | 
    
         
            +
                    end
         
     | 
| 
      
 353 
     | 
    
         
            +
                    degrees = []
         
     | 
| 
      
 354 
     | 
    
         
            +
                    roots.each do |root|
         
     | 
| 
      
 355 
     | 
    
         
            +
                      min = root if @compare_fn[root.key, min.key]
         
     | 
| 
      
 356 
     | 
    
         
            +
                      # check if we need to merge
         
     | 
| 
      
 357 
     | 
    
         
            +
                      if degrees[root.degree].nil?  # no other node with the same degree
         
     | 
| 
      
 358 
     | 
    
         
            +
                        degrees[root.degree] = root
         
     | 
| 
      
 359 
     | 
    
         
            +
                        next
         
     | 
| 
      
 360 
     | 
    
         
            +
                      else  # there is another node with the same degree, consolidate them
         
     | 
| 
      
 361 
     | 
    
         
            +
                        degree = root.degree
         
     | 
| 
      
 362 
     | 
    
         
            +
                        until degrees[degree].nil? do
         
     | 
| 
      
 363 
     | 
    
         
            +
                          other_root_with_degree = degrees[degree]
         
     | 
| 
      
 364 
     | 
    
         
            +
                          if @compare_fn[root.key, other_root_with_degree.key]  # determine which node is the parent, which one is the child
         
     | 
| 
      
 365 
     | 
    
         
            +
                            smaller, larger = root, other_root_with_degree
         
     | 
| 
      
 366 
     | 
    
         
            +
                          else
         
     | 
| 
      
 367 
     | 
    
         
            +
                            smaller, larger = other_root_with_degree, root
         
     | 
| 
      
 368 
     | 
    
         
            +
                          end
         
     | 
| 
      
 369 
     | 
    
         
            +
                          link_nodes(larger, smaller)
         
     | 
| 
      
 370 
     | 
    
         
            +
                          degrees[degree] = nil
         
     | 
| 
      
 371 
     | 
    
         
            +
                          root = smaller
         
     | 
| 
      
 372 
     | 
    
         
            +
                          degree += 1
         
     | 
| 
      
 373 
     | 
    
         
            +
                        end
         
     | 
| 
      
 374 
     | 
    
         
            +
                        degrees[degree] = root
         
     | 
| 
      
 375 
     | 
    
         
            +
                        min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
         
     | 
| 
      
 376 
     | 
    
         
            +
                      end
         
     | 
| 
      
 377 
     | 
    
         
            +
                    end
         
     | 
| 
      
 378 
     | 
    
         
            +
                    @next = min
         
     | 
| 
      
 379 
     | 
    
         
            +
                  end
         
     | 
| 
      
 380 
     | 
    
         
            +
                  private :consolidate
         
     | 
| 
      
 381 
     | 
    
         
            +
              
         
     | 
| 
      
 382 
     | 
    
         
            +
                  def cascading_cut(node)
         
     | 
| 
      
 383 
     | 
    
         
            +
                    p = node.parent
         
     | 
| 
      
 384 
     | 
    
         
            +
                    if p
         
     | 
| 
      
 385 
     | 
    
         
            +
                      if node.marked?
         
     | 
| 
      
 386 
     | 
    
         
            +
                        cut(node, p)
         
     | 
| 
      
 387 
     | 
    
         
            +
                        cascading_cut(p)
         
     | 
| 
      
 388 
     | 
    
         
            +
                      else
         
     | 
| 
      
 389 
     | 
    
         
            +
                        node.marked = true
         
     | 
| 
      
 390 
     | 
    
         
            +
                      end
         
     | 
| 
      
 391 
     | 
    
         
            +
                    end
         
     | 
| 
      
 392 
     | 
    
         
            +
                  end
         
     | 
| 
      
 393 
     | 
    
         
            +
                  private :cascading_cut
         
     | 
| 
      
 394 
     | 
    
         
            +
              
         
     | 
| 
      
 395 
     | 
    
         
            +
                  # remove x from y's children and add x to the root list
         
     | 
| 
      
 396 
     | 
    
         
            +
                  def cut(x, y)
         
     | 
| 
      
 397 
     | 
    
         
            +
                    x.left.right = x.right
         
     | 
| 
      
 398 
     | 
    
         
            +
                    x.right.left = x.left
         
     | 
| 
      
 399 
     | 
    
         
            +
                    y.degree -= 1
         
     | 
| 
      
 400 
     | 
    
         
            +
                    if (y.degree == 0)
         
     | 
| 
      
 401 
     | 
    
         
            +
                      y.child = nil
         
     | 
| 
      
 402 
     | 
    
         
            +
                    elsif (y.child == x)
         
     | 
| 
      
 403 
     | 
    
         
            +
                      y.child = x.right
         
     | 
| 
      
 404 
     | 
    
         
            +
                    end
         
     | 
| 
      
 405 
     | 
    
         
            +
                    x.right = @next
         
     | 
| 
      
 406 
     | 
    
         
            +
                    x.left = @next.left
         
     | 
| 
      
 407 
     | 
    
         
            +
                    @next.left = x
         
     | 
| 
      
 408 
     | 
    
         
            +
                    x.left.right = x
         
     | 
| 
      
 409 
     | 
    
         
            +
                    x.parent = nil
         
     | 
| 
      
 410 
     | 
    
         
            +
                    x.marked = false
         
     | 
| 
      
 411 
     | 
    
         
            +
                  end
         
     | 
| 
      
 412 
     | 
    
         
            +
                  private :cut
         
     | 
| 
      
 413 
     | 
    
         
            +
              
         
     | 
| 
      
 414 
     | 
    
         
            +
                end
         
     | 
| 
      
 415 
     | 
    
         
            +
             
     | 
| 
      
 416 
     | 
    
         
            +
                # A MaxHeap is a heap where the items are returned in descending order of 
         
     | 
| 
      
 417 
     | 
    
         
            +
                # key value.
         
     | 
| 
      
 418 
     | 
    
         
            +
                class MaxHeap < Heap
         
     | 
| 
      
 419 
     | 
    
         
            +
              
         
     | 
| 
      
 420 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 421 
     | 
    
         
            +
                  #     MaxHeap.new(ary) -> new_heap
         
     | 
| 
      
 422 
     | 
    
         
            +
                  #
         
     | 
| 
      
 423 
     | 
    
         
            +
                  # Creates a new MaxHeap with an optional array parameter of items to 
         
     | 
| 
      
 424 
     | 
    
         
            +
                  # insert into the heap. A MaxHeap is created by calling 
         
     | 
| 
      
 425 
     | 
    
         
            +
                  # Heap.new { |x, y| (x <=> y) == 1 }, so this is a convenience class.
         
     | 
| 
      
 426 
     | 
    
         
            +
                  #
         
     | 
| 
      
 427 
     | 
    
         
            +
                  #     maxheap = MaxHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 428 
     | 
    
         
            +
                  #     maxheap.pop #=> 4
         
     | 
| 
      
 429 
     | 
    
         
            +
                  #     maxheap.pop #=> 3
         
     | 
| 
      
 430 
     | 
    
         
            +
                  def initialize(ary=[])
         
     | 
| 
      
 431 
     | 
    
         
            +
                    super(ary) { |x, y| (x <=> y) == 1 }
         
     | 
| 
      
 432 
     | 
    
         
            +
                  end
         
     | 
| 
      
 433 
     | 
    
         
            +
              
         
     | 
| 
      
 434 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 435 
     | 
    
         
            +
                  #     max -> value
         
     | 
| 
      
 436 
     | 
    
         
            +
                  #     max -> nil
         
     | 
| 
      
 437 
     | 
    
         
            +
                  #
         
     | 
| 
      
 438 
     | 
    
         
            +
                  # Returns the item with the largest key, but does not remove it from the 
         
     | 
| 
      
 439 
     | 
    
         
            +
                  # heap.
         
     | 
| 
      
 440 
     | 
    
         
            +
                  #
         
     | 
| 
      
 441 
     | 
    
         
            +
                  #     maxheap = MaxHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 442 
     | 
    
         
            +
                  #     maxheap.max #=> 4
         
     | 
| 
      
 443 
     | 
    
         
            +
                  def max
         
     | 
| 
      
 444 
     | 
    
         
            +
                    self.next
         
     | 
| 
      
 445 
     | 
    
         
            +
                  end
         
     | 
| 
      
 446 
     | 
    
         
            +
              
         
     | 
| 
      
 447 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 448 
     | 
    
         
            +
                  #     max! -> value
         
     | 
| 
      
 449 
     | 
    
         
            +
                  #     max! -> nil
         
     | 
| 
      
 450 
     | 
    
         
            +
                  #
         
     | 
| 
      
 451 
     | 
    
         
            +
                  # Returns the item with the largest key and removes it from the heap.
         
     | 
| 
      
 452 
     | 
    
         
            +
                  #
         
     | 
| 
      
 453 
     | 
    
         
            +
                  #     maxheap = MaxHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 454 
     | 
    
         
            +
                  #     maxheap.max! #=> 4
         
     | 
| 
      
 455 
     | 
    
         
            +
                  #     maxheap.size #=> 3
         
     | 
| 
      
 456 
     | 
    
         
            +
                  def max!
         
     | 
| 
      
 457 
     | 
    
         
            +
                    self.pop
         
     | 
| 
      
 458 
     | 
    
         
            +
                  end
         
     | 
| 
      
 459 
     | 
    
         
            +
                end
         
     | 
| 
      
 460 
     | 
    
         
            +
             
     | 
| 
      
 461 
     | 
    
         
            +
                # A MinHeap is a heap where the items are returned in ascending order of 
         
     | 
| 
      
 462 
     | 
    
         
            +
                # key value.
         
     | 
| 
      
 463 
     | 
    
         
            +
                class MinHeap < Heap
         
     | 
| 
      
 464 
     | 
    
         
            +
              
         
     | 
| 
      
 465 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 466 
     | 
    
         
            +
                  #     MinHeap.new(ary) -> new_heap
         
     | 
| 
      
 467 
     | 
    
         
            +
                  #
         
     | 
| 
      
 468 
     | 
    
         
            +
                  # Creates a new MinHeap with an optional array parameter of items to 
         
     | 
| 
      
 469 
     | 
    
         
            +
                  # insert into the heap.
         
     | 
| 
      
 470 
     | 
    
         
            +
                  # A MinHeap is created by calling Heap.new { |x, y| (x <=> y) == -1 }, 
         
     | 
| 
      
 471 
     | 
    
         
            +
                  # so this is a convenience class.
         
     | 
| 
      
 472 
     | 
    
         
            +
                  #
         
     | 
| 
      
 473 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 474 
     | 
    
         
            +
                  #     minheap.pop #=> 1
         
     | 
| 
      
 475 
     | 
    
         
            +
                  #     minheap.pop #=> 2
         
     | 
| 
      
 476 
     | 
    
         
            +
                  def initialize(ary=[])
         
     | 
| 
      
 477 
     | 
    
         
            +
                    super(ary) { |x, y| (x <=> y) == -1 }
         
     | 
| 
      
 478 
     | 
    
         
            +
                  end
         
     | 
| 
      
 479 
     | 
    
         
            +
              
         
     | 
| 
      
 480 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 481 
     | 
    
         
            +
                  #     min -> value
         
     | 
| 
      
 482 
     | 
    
         
            +
                  #     min -> nil
         
     | 
| 
      
 483 
     | 
    
         
            +
                  #
         
     | 
| 
      
 484 
     | 
    
         
            +
                  # Returns the item with the smallest key, but does not remove it from 
         
     | 
| 
      
 485 
     | 
    
         
            +
                  # the heap.
         
     | 
| 
      
 486 
     | 
    
         
            +
                  #
         
     | 
| 
      
 487 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 488 
     | 
    
         
            +
                  #     minheap.min #=> 1
         
     | 
| 
      
 489 
     | 
    
         
            +
                  def min
         
     | 
| 
      
 490 
     | 
    
         
            +
                    self.next
         
     | 
| 
      
 491 
     | 
    
         
            +
                  end
         
     | 
| 
      
 492 
     | 
    
         
            +
              
         
     | 
| 
      
 493 
     | 
    
         
            +
                  # call-seq:
         
     | 
| 
      
 494 
     | 
    
         
            +
                  #     min! -> value
         
     | 
| 
      
 495 
     | 
    
         
            +
                  #     min! -> nil
         
     | 
| 
      
 496 
     | 
    
         
            +
                  #
         
     | 
| 
      
 497 
     | 
    
         
            +
                  # Returns the item with the smallest key and removes it from the heap.
         
     | 
| 
      
 498 
     | 
    
         
            +
                  #
         
     | 
| 
      
 499 
     | 
    
         
            +
                  #     minheap = MinHeap.new([1, 2, 3, 4])
         
     | 
| 
      
 500 
     | 
    
         
            +
                  #     minheap.min! #=> 1
         
     | 
| 
      
 501 
     | 
    
         
            +
                  #     minheap.size #=> 3
         
     | 
| 
      
 502 
     | 
    
         
            +
                  def min!
         
     | 
| 
      
 503 
     | 
    
         
            +
                    self.pop
         
     | 
| 
      
 504 
     | 
    
         
            +
                  end
         
     | 
| 
      
 505 
     | 
    
         
            +
                end
         
     | 
| 
      
 506 
     | 
    
         
            +
              end
         
     | 
| 
      
 507 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,113 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            =begin rdoc
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
                A kd-tree is a binary tree that allows one to store points (of any space dimension: 2D, 3D, etc). 
         
     | 
| 
      
 4 
     | 
    
         
            +
                The structure of the resulting tree makes it so that large portions of the tree are pruned
         
     | 
| 
      
 5 
     | 
    
         
            +
                during queries.
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                One very good use of the tree is to allow nearest neighbor searching. Let's say you have a number
         
     | 
| 
      
 8 
     | 
    
         
            +
                of points in 2D space, and you want to find the nearest 2 points from a specific point:
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                First, put the points into the tree:
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
      
 12 
     | 
    
         
            +
                  kdtree = Algorithms::Containers::KDTree.new( {0 => [4, 3], 1 => [3, 4], 2 => [-1, 2], 3 => [6, 4],
         
     | 
| 
      
 13 
     | 
    
         
            +
                                                   4 => [3, -5], 5 => [-2, -5] })
         
     | 
| 
      
 14 
     | 
    
         
            +
                
         
     | 
| 
      
 15 
     | 
    
         
            +
                Then, query on the tree:
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                  puts kd.find_nearest([0, 0], 2) => [[5, 2], [9, 1]]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  
         
     | 
| 
      
 19 
     | 
    
         
            +
                The result is an array of [distance, id] pairs. There seems to be a bug in this version.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  
         
     | 
| 
      
 21 
     | 
    
         
            +
                Note that the point queried on does not have to exist in the tree. However, if it does exist,
         
     | 
| 
      
 22 
     | 
    
         
            +
                it will be returned.
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            =end
         
     | 
| 
      
 25 
     | 
    
         
            +
            module Algorithms
         
     | 
| 
      
 26 
     | 
    
         
            +
              module Containers
         
     | 
| 
      
 27 
     | 
    
         
            +
                class KDTree
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Node = Struct.new(:id, :coords, :left, :right)
         
     | 
| 
      
 29 
     | 
    
         
            +
              
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # Points is a hash of id => [coord, coord] pairs.
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def initialize(points)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    raise "must pass in a hash" unless points.kind_of?(Hash)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @dimensions = points[ points.keys.first ].size
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @root = build_tree(points.to_a)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @nearest = []
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
              
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # Find k closest points to given coordinates 
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def find_nearest(target, k_nearest)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @nearest = []
         
     | 
| 
      
 41 
     | 
    
         
            +
                    nearest(@root, target, k_nearest, 0)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
              
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # points is an array
         
     | 
| 
      
 45 
     | 
    
         
            +
                  def build_tree(points, depth=0)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return if points.empty?
         
     | 
| 
      
 47 
     | 
    
         
            +
                
         
     | 
| 
      
 48 
     | 
    
         
            +
                    axis = depth % @dimensions
         
     | 
| 
      
 49 
     | 
    
         
            +
                
         
     | 
| 
      
 50 
     | 
    
         
            +
                    points.sort! { |a, b| a.last[axis] <=> b.last[axis] }
         
     | 
| 
      
 51 
     | 
    
         
            +
                    median = points.size / 2
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
                    node = Node.new(points[median].first, points[median].last, nil, nil)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    node.left = build_tree(points[0...median], depth+1)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    node.right = build_tree(points[median+1..-1], depth+1)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    node
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  private :build_tree
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  # Euclidian distanced, squared, between a node and target coords
         
     | 
| 
      
 61 
     | 
    
         
            +
                  def distance2(node, target)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    return nil if node.nil? or target.nil?
         
     | 
| 
      
 63 
     | 
    
         
            +
                    c = (node.coords[0] - target[0])
         
     | 
| 
      
 64 
     | 
    
         
            +
                    d = (node.coords[1] - target[1])
         
     | 
| 
      
 65 
     | 
    
         
            +
                    c * c + d * d
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  private :distance2
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  # Update array of nearest elements if necessary
         
     | 
| 
      
 70 
     | 
    
         
            +
                  def check_nearest(nearest, node, target, k_nearest)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    d = distance2(node, target) 
         
     | 
| 
      
 72 
     | 
    
         
            +
                    if nearest.size < k_nearest || d < nearest.last[0]
         
     | 
| 
      
 73 
     | 
    
         
            +
                      nearest.pop if nearest.size >= k_nearest
         
     | 
| 
      
 74 
     | 
    
         
            +
                      nearest << [d, node.id]
         
     | 
| 
      
 75 
     | 
    
         
            +
                      nearest.sort! { |a, b| a[0] <=> b[0] }
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                    nearest
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                  private :check_nearest
         
     | 
| 
      
 80 
     | 
    
         
            +
              
         
     | 
| 
      
 81 
     | 
    
         
            +
                  # Recursively find nearest coordinates, going down the appropriate branch as needed
         
     | 
| 
      
 82 
     | 
    
         
            +
                  def nearest(node, target, k_nearest, depth)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    axis = depth % @dimensions
         
     | 
| 
      
 84 
     | 
    
         
            +
              
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if node.left.nil? && node.right.nil? # Leaf node
         
     | 
| 
      
 86 
     | 
    
         
            +
                      @nearest = check_nearest(@nearest, node, target, k_nearest)
         
     | 
| 
      
 87 
     | 
    
         
            +
                      return
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
              
         
     | 
| 
      
 90 
     | 
    
         
            +
                    # Go down the nearest split
         
     | 
| 
      
 91 
     | 
    
         
            +
                    if node.right.nil? || (node.left && target[axis] <= node.coords[axis])
         
     | 
| 
      
 92 
     | 
    
         
            +
                      nearer = node.left
         
     | 
| 
      
 93 
     | 
    
         
            +
                      further = node.right
         
     | 
| 
      
 94 
     | 
    
         
            +
                    else
         
     | 
| 
      
 95 
     | 
    
         
            +
                      nearer = node.right
         
     | 
| 
      
 96 
     | 
    
         
            +
                      further = node.left
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                    nearest(nearer, target, k_nearest, depth+1)
         
     | 
| 
      
 99 
     | 
    
         
            +
              
         
     | 
| 
      
 100 
     | 
    
         
            +
                    # See if we have to check other side
         
     | 
| 
      
 101 
     | 
    
         
            +
                    if further
         
     | 
| 
      
 102 
     | 
    
         
            +
                      if @nearest.size < k_nearest || (target[axis] - node.coords[axis])**2 < @nearest.last[0]
         
     | 
| 
      
 103 
     | 
    
         
            +
                        nearest(further, target, k_nearest, depth+1)
         
     | 
| 
      
 104 
     | 
    
         
            +
                      end
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
              
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @nearest = check_nearest(@nearest, node, target, k_nearest)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                  private :nearest
         
     | 
| 
      
 110 
     | 
    
         
            +
              
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
            end
         
     |