lib/compsci/heap.rb in compsci-0.0.3.1 vs lib/compsci/heap.rb in compsci-0.1.0.1

- old
+ new

@@ -1,9 +1,7 @@ -require 'compsci/tree' +require 'compsci/complete_tree' -include CompSci - # A Heap is a partially sorted, complete N-ary tree with the property: # * Every node has a value larger (or smaller) than that of its children # (the heap property is satisfied when a parent value equals a child value) # # Implementation details: @@ -18,11 +16,11 @@ # reestablish the heap property. # * Sift_up and sift_down are O(logb n) because they only have to check and # swap nodes at each layer of the tree, and there are log(n, base b) layers # to the tree. # -class Heap < CompleteNaryTree +class CompSci::Heap < CompSci::CompleteNaryTree # * defaults to a MaxHeap, with the largest node at the root # * specify a minheap with minheap: true or cmp_val: -1 # def initialize(cmp_val: 1, minheap: false, child_slots: 2) super(child_slots: child_slots) @@ -37,41 +35,41 @@ # * append to the array # * sift_up -- O(log n) on heap size # def push(node) - @store << node - self.sift_up(@store.size - 1) + @array.push(node) + self.sift_up(@array.size - 1) end # * remove from the front of the array # * move last node to root # * sift_down -- O(log n) on heap size # def pop - node = @store.shift - replacement = @store.pop - @store.unshift replacement if replacement + node = @array.shift + replacement = @array.pop + @array.unshift replacement if replacement self.sift_down(0) node end # * return what pop would return (avoid sifting) # def peek - @store.first + @array.first end # * called recursively # * idx represents the node suspected to violate the heap # * intended to be O(log n) on heap size (log base child_slots) # def sift_up(idx) return self if idx <= 0 pidx = self.class.parent_idx(idx, @child_slots) if !self.heapish?(pidx, idx) - @store[idx], @store[pidx] = @store[pidx], @store[idx] # swap + @array[idx], @array[pidx] = @array[pidx], @array[idx] # swap self.sift_up(pidx) end self end @@ -79,33 +77,33 @@ # * idx represents the node suspected to violate the heap # * intended to be O(log n) on heap size (log base child_slots) # * slower than sift_up because one parent vs multiple children # def sift_down(idx) - return self if idx >= @store.size + return self if idx >= @array.size cidxs = self.class.children_idx(idx, @child_slots) # promote the heapiest child cidx = self.heapiest(cidxs) if !self.heapish?(idx, cidx) - @store[idx], @store[cidx] = @store[cidx], @store[idx] # swap + @array[idx], @array[cidx] = @array[cidx], @array[idx] # swap self.sift_down(cidx) end self end # are values of parent and child (by index) in accordance with heap property? # def heapish?(pidx, cidx) - (@store[pidx] <=> @store[cidx]) != (@cmp_val * -1) + (@array[pidx] <=> @array[cidx]) != (@cmp_val * -1) end # return the heapiest idx in cidxs # def heapiest(cidxs) idx = cidxs.first cidxs.each { |cidx| - idx = cidx if cidx < @store.size and self.heapish?(cidx, idx) + idx = cidx if cidx < @array.size and self.heapish?(cidx, idx) } idx end # * not used internally @@ -114,102 +112,10 @@ # def heap?(idx: 0) check_children = [] self.class.children_idx(idx, @child_slots).each { |cidx| # cidx is arithmetically produced; the corresponding child may not exist - if cidx < @store.size - return false unless self.heapish?(idx, cidx) - check_children << cidx - end - } - check_children.each { |cidx| return false unless self.heap?(idx: cidx) } - true - end -end - -# -# LEGACY BELOW untouched for now -# - -class BinaryHeap < CompleteBinaryTree - # defaults to a MaxHeap, with the largest node at the root - # specify a minheap with minheap: true or cmp_val: -1 - # - def initialize(cmp_val: 1, minheap: false) - super() - cmp_val = -1 if minheap - case cmp_val - when -1, 1 - @cmp_val = cmp_val - else - raise(ArgumentError, "unknown comparison value: #{cmp_val}") - end - end - - # append to the array - # sift_up -- O(log n) on heap size - def push(node) - @store << node - self.sift_up(@store.size - 1) - end - - # remove from the front of the array - # move last node to root - # sift_down -- O(log n) on heap size - def pop - node = @store.shift - replacement = @store.pop - @store.unshift replacement if replacement - self.sift_down(0) - node - end - - # return what pop would return (avoid sifting) - def peek - @store.first - end - - # called recursively - # idx represents the node suspected to violate the heap - # intended to be O(log n) on heap size - def sift_up(idx) - return self if idx <= 0 - pidx = self.class.parent_idx(idx) - if !self.heapish?(pidx, idx) - @store[idx], @store[pidx] = @store[pidx], @store[idx] # swap - self.sift_up(pidx) - end - self - end - - # called recursively - # idx represents the node suspected to violate the heap - # intended to be O(log n) on heap size - def sift_down(idx) - return self if idx >= @store.size - lidx, ridx = self.class.children_idx(idx) - # promote the heapiest child - cidx = self.heapish?(lidx, ridx) ? lidx : ridx - if !self.heapish?(idx, cidx) - @store[idx], @store[cidx] = @store[cidx], @store[idx] # swap - self.sift_down(cidx) - end - self - end - - # are values of parent and child (by index) in accordance with heap property? - def heapish?(pidx, cidx) - (@store[pidx] <=> @store[cidx]) != (@cmp_val * -1) - end - - # not used internally - # checks that every node satisfies the heap property - # calls heapish? on idx's children and then heap? on them recursively - def heap?(idx: 0) - check_children = [] - self.class.children_idx(idx).each { |cidx| - # cidx is arithmetically produced; the corresponding child may not exist - if cidx < @store.size + if cidx < @array.size return false unless self.heapish?(idx, cidx) check_children << cidx end } check_children.each { |cidx| return false unless self.heap?(idx: cidx) }