forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of github.com:JuliaLang/julia
- Loading branch information
Showing
4 changed files
with
334 additions
and
186 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,162 +1,312 @@ | ||
# These functions define a heap | ||
# heap.jl | ||
# | ||
# This file defines Heap objects and a variety of utility functions. | ||
# | ||
# Example usage of the Heap object: | ||
# You can create an empty heap this way: | ||
# h = Heap(Float64) | ||
# This defaults to using < for comparison, so is a min-heap. | ||
# You can create an empty min-heap this way: | ||
# h = MinHeap(Float64) | ||
# | ||
# A more complex and complete example, yielding a max-heap: | ||
# h = Heap(>,rand(3)) # initialize heap with 3 random points | ||
# A more complex and complete example with a max-heap: | ||
# h = MaxHeap(rand(3)) # initialize heap with 3 random points | ||
# for i = 1:10 | ||
# push!(h,rand()) # add more points | ||
# end | ||
# length(h) | ||
# max_val = pop!(h) | ||
# | ||
# Example using pure vectors (avoids making any copies): | ||
# | ||
# You can also work with indexed heaps: | ||
# z = rand(8) | ||
# h = MinHeapIndirect(typeof(z)) | ||
# for i = 1:length(z) | ||
# push!(h,z[i]) | ||
# end | ||
# min_index, min_val = pop!(h) | ||
# | ||
# Finally, you can do min-heaps using pure vectors. This avoids the | ||
# need to make a copy of the data: | ||
# z = rand(8) | ||
# vector2heap!(z) | ||
# isheap(z) | ||
# min_val = heap_pop!(z) | ||
# heap2rsorted!(z) | ||
# You can also do indirect min-heaps this way, by supplying an index | ||
# vector as the first argument. | ||
|
||
# Timothy E. Holy, 2012 | ||
|
||
## Function definitions for operating on vectors ## | ||
|
||
# A "direct heap" is represented as a vector, each entry containing | ||
# the "value" (key) of a particular item. An "indirect heap" is | ||
# stored as a vector of "integer pointers" (denoted by the variable | ||
# iptr), and the key of node i is value[iptr[i]]. Representing the | ||
# heap indirectly (requiring lookup of the value) has some cost, but | ||
# is useful when the item index is the more fundamentally-interesting | ||
# quantity. | ||
|
||
# For an indirect heap, note that value stores the entire set of | ||
# values ever added to the heap, whereas iptr reflects the current | ||
# state of the heap. Hence, value may be a longer vector than iptr, | ||
# if items have been popped off the heap. | ||
|
||
# These functions implement a min-heap. You can get a max-heap using | ||
# the Heap objects below. | ||
|
||
|
||
# This is a "percolate down" function, used by several other | ||
# functions. "percolate up" is implemented in heap_push. | ||
function _heapify!{T}(cmp::Function,x::Vector{T},i::Int,len::Int) | ||
il = 2*i # index of left child | ||
# direct version: | ||
function _heapify!{T}(value::Vector{T},i::Int,len::Int) | ||
il = 2*i # node index of left child | ||
while il <= len | ||
# Among node i and its two children, find the extreme value | ||
#(e.g., the smallest when using < for comparison) | ||
iextreme = cmp(x[il],x[i]) ? il : i # index of extreme value | ||
# Among node i and its two children, find the smallest value | ||
ismallest = isless(value[il],value[i]) ? il : i # node index of smallest value | ||
if il < len | ||
iextreme = cmp(x[il+1],x[iextreme]) ? il+1 : iextreme | ||
ismallest = isless(value[il+1],value[ismallest]) ? il+1 : ismallest | ||
end | ||
if iextreme == i | ||
if ismallest == i | ||
return # The heap below this node is fine | ||
end | ||
# Put the extreme value at i via a swap | ||
tmp = x[iextreme] | ||
x[iextreme] = x[i] | ||
x[i] = tmp | ||
# Put the smallest value at i via a swap of their iptrs | ||
value[ismallest], value[i] = value[i], value[ismallest] | ||
# Descend to the modified child | ||
i = iextreme | ||
i = ismallest | ||
il = 2*i | ||
end | ||
end | ||
# indirect version: | ||
function _heapify!{T}(iptr::Vector{Int},value::Vector{T},i::Int,len::Int) | ||
il = 2*i | ||
while il <= len | ||
ismallest = isless(value[iptr[il]],value[iptr[i]]) ? il : i | ||
if il < len | ||
ismallest = isless(value[iptr[il+1]],value[iptr[ismallest]]) ? il+1 : ismallest | ||
end | ||
if ismallest == i | ||
return | ||
end | ||
iptr[ismallest], iptr[i] = iptr[i], iptr[ismallest] | ||
i = ismallest | ||
il = 2*i | ||
end | ||
end | ||
|
||
|
||
# Convert an arbitrary vector into heap storage format | ||
function vector2heap!{T}(cmp::Function, x::Vector{T}) | ||
for i = convert(Int,ifloor(length(x)/2)):-1:1 | ||
_heapify!(cmp,x,i,length(x)) | ||
function vector2heap!{T}(value::Vector{T}) | ||
for i = convert(Int,ifloor(length(value)/2)):-1:1 | ||
_heapify!(value,i,length(value)) | ||
end | ||
end | ||
function vector2heap!{T}(x::Vector{T}) | ||
vector2heap!(<,x) | ||
function vector2heap!{T}(iptr::Vector{Int},value::Vector{T}) | ||
for i = convert(Int,ifloor(length(iptr)/2)):-1:1 | ||
_heapify!(iptr,value,i,length(iptr)) | ||
end | ||
end | ||
|
||
# Test whether a vector is a valid heap | ||
function isheap{T}(cmp::Function, x::Vector{T}) | ||
for i = 1:convert(Int,ifloor(length(x)/2)) | ||
function isheap{T}(value::Vector{T}) | ||
for i = 1:convert(Int,ifloor(length(iptr)/2)) | ||
i2 = 2*i | ||
if !cmp(x[i],x[i2]) | ||
if isless(value[i2],value[i]) | ||
return false | ||
end | ||
if i2 < length(x) && !cmp(x[i],x[i2+1]) | ||
if i2 < length(x) && isless(value[i2+1],value[i]) | ||
return false | ||
end | ||
end | ||
return true | ||
end | ||
function isheap{T}(x::Vector{T}) | ||
isheap(<,x) | ||
function isheap{T}(iptr::Vector{Int},value::Vector{T}) | ||
for i = 1:convert(Int,ifloor(length(iptr)/2)) | ||
i2 = 2*i | ||
if isless(value[iptr[i2]],value[iptr[i]]) | ||
return false | ||
end | ||
if i2 < length(x) && isless(value[iptr[i2+1]],value[iptr[i]]) | ||
return false | ||
end | ||
end | ||
return true | ||
end | ||
|
||
# Add a new item to a heap | ||
function heap_push!{T}(cmp::Function, x::Vector{T},item::T) | ||
# Append new element at the bottom | ||
push(x,item) | ||
function heap_push!{T}(value::Vector{T},newvalue::T) | ||
# Append the new value at the bottom | ||
push(value,newvalue) | ||
# Let the new item percolate up until stopped by a more-extreme parent | ||
i = length(x) | ||
i = length(value) | ||
ip = convert(Int,ifloor(i/2)) # index of parent | ||
while i > 1 && cmp(x[i],x[ip]) | ||
while i > 1 && isless(value[i],value[ip]) | ||
# Swap i and its parent | ||
tmp = x[ip] | ||
x[ip] = x[i] | ||
x[i] = tmp | ||
value[i], value[ip] = value[ip], value[i] | ||
# Traverse up the tree | ||
i = ip | ||
ip = convert(Int,ifloor(i/2)) | ||
end | ||
end | ||
function heap_push!{T}(x::Vector{T},item::T) | ||
heap_push!(<,x,item) | ||
function heap_push!{T}(iptr::Vector{Int},value::Vector{T},newvalue::T) | ||
push(value,newvalue) | ||
push(iptr,length(value)) | ||
i = length(iptr) | ||
ip = convert(Int,ifloor(i/2)) | ||
while i > 1 && isless(value[iptr[i]],value[iptr[ip]]) | ||
iptr[i], iptr[ip] = iptr[ip], iptr[i] | ||
i = ip | ||
ip = convert(Int,ifloor(i/2)) | ||
end | ||
end | ||
|
||
# Remove the root node from the heap, leaving the remaining values in | ||
# a valid heap | ||
function heap_pop!{T}(cmp::Function, x::Vector{T}) | ||
# Save the value we want to return | ||
extreme_item = x[1] | ||
function heap_pop!{T}(value::Vector{T}) | ||
# Save the item we want to return | ||
extreme_item = value[1] | ||
# We need to shorten the list, so replace the former top with the | ||
# last item, then let it percolate down | ||
x[1] = x[end] | ||
pop(x) | ||
_heapify!(cmp,x,1,length(x)) | ||
value[1] = value[end] | ||
pop(value) | ||
_heapify!(value,1,length(value)) | ||
return extreme_item | ||
end | ||
function heap_pop!{T}(x::Vector{T}) | ||
extreme_item = heap_pop!(<,x) | ||
function heap_pop!{T}(iptr::Vector{Int},value::Vector{T}) | ||
extreme_item = iptr[1] | ||
iptr[1] = iptr[end] | ||
pop(iptr) | ||
_heapify!(iptr,value,1,length(iptr)) | ||
return extreme_item | ||
end | ||
|
||
# From a heap, return a sorted vector. This is implemented efficiently | ||
# if the sorting is in the reverse order of the comparison function. | ||
function heap2rsorted!{T}(cmp::Function, x::Vector{T}) | ||
for i = length(x):-1:2 | ||
function heap2rsorted!{T}(value::Vector{T}) | ||
for i = length(value):-1:2 | ||
# Swap the root with i, the last unsorted position | ||
tmp = x[1] | ||
x[1] = x[i] | ||
x[i] = tmp | ||
value[1], value[i] = value[i], value[1] | ||
# The heap portion now has length i-1, but needs fixing up | ||
# starting with the root | ||
_heapify!(cmp,x,1,i-1) | ||
_heapify!(value,1,i-1) | ||
end | ||
end | ||
function heap2rsorted!{T}(x::Vector{T}) | ||
heap2rsorted!(<,x) | ||
function heap2rsorted!{T}(iptr::Vector{Int},value::Vector{T}) | ||
for i = length(iptr):-1:2 | ||
iptr[1], iptr[i] = iptr[i], iptr[1] | ||
_heapify!(iptr,value,1,i-1) | ||
end | ||
end | ||
|
||
|
||
|
||
## Heap object ## | ||
## Heap objects ## | ||
|
||
type Heap{T} | ||
cmp::Function | ||
data::Array{T,1} | ||
abstract Heap | ||
abstract HeapDirect <: Heap | ||
abstract HeapIndirect <: Heap | ||
|
||
function Heap(cmp::Function,x::Array{T,1}) | ||
data = copy(x) | ||
vector2heap!(cmp,data) | ||
new(cmp,data) | ||
# MinHeap | ||
type MinHeap{T} <: HeapDirect | ||
value::Vector{T} | ||
|
||
function MinHeap(v::Vector{T}) | ||
value = copy(v) | ||
vector2heap!(value) | ||
new(value) | ||
end | ||
end | ||
Heap{T}(cmp::Function,x::Vector{T}) = Heap{T}(cmp,x) | ||
Heap{T}(x::Vector{T}) = Heap{T}(<,x) | ||
Heap{T}(cmp::Function,::Type{T}) = Heap{T}(cmp,zeros(T,0)) | ||
Heap{T}(::Type{T}) = Heap{T}(<,zeros(T,0)) | ||
MinHeap{T}(v::Vector{T}) = MinHeap{T}(v) | ||
MinHeap{T}(::Type{T}) = MinHeap{T}(zeros(T,0)) | ||
|
||
function push!{T}(h::Heap{T},item::T) | ||
heap_push!(h.cmp,h.data,item) | ||
function push!{T}(h::MinHeap{T},item::T) | ||
heap_push!(h.data,item) | ||
end | ||
|
||
function pop!{T}(h::Heap{T}) | ||
extreme_item = heap_pop!(h.cmp,h.data) | ||
return extreme_item | ||
function pop!{T}(h::MinHeap{T}) | ||
min_item = heap_pop!(h.data) | ||
return min_item | ||
end | ||
|
||
function length{T}(h::HeapDirect) | ||
return length(h.value) | ||
end | ||
|
||
function isempty{T}(h::HeapDirect) | ||
return isempty(h.value) | ||
end | ||
|
||
# MaxHeap | ||
type MaxHeap{T} <: HeapDirect | ||
value::Vector{T} | ||
|
||
function MaxHeap(v::Vector{T}) | ||
value = copy(v) | ||
vector2heap!(value) | ||
new(value) | ||
end | ||
end | ||
MaxHeap{T}(v::Vector{T}) = MaxHeap{T}(v) | ||
MaxHeap{T}(::Type{T}) = MaxHeap{T}(zeros(T,0)) | ||
|
||
function push!{T}(h::MaxHeap{T},item::T) | ||
heap_push!(h.data,-item) | ||
end | ||
|
||
function pop!{T}(h::MaxHeap{T}) | ||
max_item = -heap_pop!(h.data) | ||
return max_item | ||
end | ||
|
||
# MinHeapIndirect (an indexed heap) | ||
type MinHeapIndirect{T} <: HeapIndirect | ||
index::Vector{Int} | ||
value::Vector{T} | ||
|
||
function MinHeapIndirect(v::Vector{T}) | ||
value = copy(v) | ||
index = linspace(1,length(v),length(v)) | ||
vector2heap!(index,value) | ||
new(index,value) | ||
end | ||
end | ||
#MinHeapIndirect{T}(i::Vector{Int},v::Vector{T}) = MinHeapIndirect{T}(i,v) | ||
MinHeapIndirect{T}(v::Vector{T}) = MinHeapIndirect{T}(v) | ||
MinHeapIndirect{T}(::Type{T}) = MinHeapIndirect{T}(zeros(T,0)) | ||
|
||
function push!{T}(h::MinHeapIndirect{T},newvalue::T) | ||
heap_push!(h.index,h.value,newvalue) | ||
end | ||
|
||
function pop!{T}(h::MinHeapIndirect{T}) | ||
min_index = heap_pop!(h.index,h.value) | ||
return (min_index, h.value[min_index]) | ||
end | ||
|
||
function length{T}(h::HeapIndirect) | ||
return length(h.index) | ||
end | ||
function isempty{T}(h::HeapIndirect) | ||
return isempty(h.index) | ||
end | ||
|
||
# MaxHeapIndirect (an indexed heap) | ||
type MaxHeapIndirect{T} <: HeapIndirect | ||
index::Vector{Int} | ||
value::Vector{T} | ||
|
||
function HeapIndirect(v::Vector{T}) | ||
value = copy(v) | ||
index = linspace(1,length(v),length(v)) | ||
vector2heap!(index,value) | ||
new(index,value) | ||
end | ||
end | ||
MaxHeapIndirect{T}(v::Vector{T}) = MaxHeapIndirect{T}(v) | ||
MaxHeapIndirect{T}(::Type{T}) = MaxHeapIndirect{T}(zeros(T,0)) | ||
|
||
function push!{T}(h::MaxHeapIndirect{T},newvalue::T) | ||
heap_push!(h.index,h.value,-newvalue) | ||
end | ||
|
||
function length{T}(h::Heap{T}) | ||
return length(h.data) | ||
function pop!{T}(h::MaxHeapIndirect{T}) | ||
min_index = heap_pop!(h.index,h.value) | ||
return min_index, -h.value[index] | ||
end |
Oops, something went wrong.