123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- {floor, min} = Math
- ###
- Default comparison function to be used
- ###
- defaultCmp = (x, y) ->
- return -1 if x < y
- return 1 if x > y
- 0
- ###
- Insert item x in list a, and keep it sorted assuming a is sorted.
- If x is already in a, insert it to the right of the rightmost x.
- Optional args lo (default 0) and hi (default a.length) bound the slice
- of a to be searched.
- ###
- insort = (a, x, lo=0, hi, cmp=defaultCmp) ->
- throw new Error('lo must be non-negative') if lo < 0
- hi ?= a.length
- while lo < hi
- mid = floor((lo + hi) / 2)
- if cmp(x, a[mid]) < 0
- hi = mid
- else
- lo = mid + 1
- a[lo...lo] = x
- ###
- Push item onto heap, maintaining the heap invariant.
- ###
- heappush = (array, item, cmp=defaultCmp) ->
- array.push(item)
- _siftdown(array, 0, array.length - 1, cmp)
- ###
- Pop the smallest item off the heap, maintaining the heap invariant.
- ###
- heappop = (array, cmp=defaultCmp) ->
- lastelt = array.pop()
- if array.length
- returnitem = array[0]
- array[0] = lastelt
- _siftup(array, 0, cmp)
- else
- returnitem = lastelt
- returnitem
- ###
- Pop and return the current smallest value, and add the new item.
- This is more efficient than heappop() followed by heappush(), and can be
- more appropriate when using a fixed size heap. Note that the value
- returned may be larger than item! That constrains reasonable use of
- this routine unless written as part of a conditional replacement:
- if item > array[0]
- item = heapreplace(array, item)
- ###
- heapreplace = (array, item, cmp=defaultCmp) ->
- returnitem = array[0]
- array[0] = item
- _siftup(array, 0, cmp)
- returnitem
- ###
- Fast version of a heappush followed by a heappop.
- ###
- heappushpop = (array, item, cmp=defaultCmp) ->
- if array.length and cmp(array[0], item) < 0
- [item, array[0]] = [array[0], item]
- _siftup(array, 0, cmp)
- item
- ###
- Transform list into a heap, in-place, in O(array.length) time.
- ###
- heapify = (array, cmp=defaultCmp) ->
- for i in [0...floor(array.length / 2)].reverse()
- _siftup(array, i, cmp)
- ###
- Update the position of the given item in the heap.
- This function should be called every time the item is being modified.
- ###
- updateItem = (array, item, cmp=defaultCmp) ->
- pos = array.indexOf(item)
- return if pos is -1
- _siftdown(array, 0, pos, cmp)
- _siftup(array, pos, cmp)
- ###
- Find the n largest elements in a dataset.
- ###
- nlargest = (array, n, cmp=defaultCmp) ->
- result = array[0...n]
- return result unless result.length
- heapify(result, cmp)
- heappushpop(result, elem, cmp) for elem in array[n..]
- result.sort(cmp).reverse()
- ###
- Find the n smallest elements in a dataset.
- ###
- nsmallest = (array, n, cmp=defaultCmp) ->
- if n * 10 <= array.length
- result = array[0...n].sort(cmp)
- return result unless result.length
- los = result[result.length - 1]
- for elem in array[n..]
- if cmp(elem, los) < 0
- insort(result, elem, 0, null, cmp)
- result.pop()
- los = result[result.length - 1]
- return result
- heapify(array, cmp)
- (heappop(array, cmp) for i in [0...min(n, array.length)])
- _siftdown = (array, startpos, pos, cmp=defaultCmp) ->
- newitem = array[pos]
- while pos > startpos
- parentpos = (pos - 1) >> 1
- parent = array[parentpos]
- if cmp(newitem, parent) < 0
- array[pos] = parent
- pos = parentpos
- continue
- break
- array[pos] = newitem
- _siftup = (array, pos, cmp=defaultCmp) ->
- endpos = array.length
- startpos = pos
- newitem = array[pos]
- childpos = 2 * pos + 1
- while childpos < endpos
- rightpos = childpos + 1
- if rightpos < endpos and not (cmp(array[childpos], array[rightpos]) < 0)
- childpos = rightpos
- array[pos] = array[childpos]
- pos = childpos
- childpos = 2 * pos + 1
- array[pos] = newitem
- _siftdown(array, startpos, pos, cmp)
- class Heap
- @push: heappush
- @pop: heappop
- @replace: heapreplace
- @pushpop: heappushpop
- @heapify: heapify
- @updateItem: updateItem
- @nlargest: nlargest
- @nsmallest: nsmallest
- constructor: (@cmp=defaultCmp) ->
- @nodes = []
- push: (x) ->
- heappush(@nodes, x, @cmp)
- pop: ->
- heappop(@nodes, @cmp)
- peek: ->
- @nodes[0]
- contains: (x) ->
- @nodes.indexOf(x) isnt -1
- replace: (x) ->
- heapreplace(@nodes, x, @cmp)
- pushpop: (x) ->
- heappushpop(@nodes, x, @cmp)
- heapify: ->
- heapify(@nodes, @cmp)
- updateItem: (x) ->
- updateItem(@nodes, x, @cmp)
- clear: ->
- @nodes = []
- empty: ->
- @nodes.length is 0
- size: ->
- @nodes.length
- clone: ->
- heap = new Heap()
- heap.nodes = @nodes.slice(0)
- heap
- toArray: ->
- @nodes.slice(0)
- # aliases
- insert: @::push
- top: @::peek
- front: @::peek
- has: @::contains
- copy: @::clone
- # exports to global
- ((root, factory) ->
- if typeof define is 'function' and define.amd
- define [], factory
- else if typeof exports is 'object'
- module.exports = factory()
- else
- root.Heap = factory()
- ) @, -> Heap
|