! Implements a heap using an array; top of the heap is the item ! with minimum key value module minheap_module use datatype_module use module_debug ! Maximum heap size -- maybe make this magically dynamic somehow? integer, parameter :: HEAPSIZE = 10000 ! Type of item to be stored in the heap type heap_object type (data_node), pointer :: object end type heap_object ! The heap itself type (heap_object), allocatable, dimension(:) :: heap ! Index of last item in the heap integer :: end_of_heap contains ! Initialize the heap; current functionality can be had without ! the need for init function, but we may want more things later subroutine init_heap() implicit none end_of_heap = 0 allocate(heap(HEAPSIZE)) end subroutine init_heap subroutine heap_destroy() implicit none deallocate(heap) end subroutine heap_destroy subroutine add_to_heap(x) implicit none ! Arguments type (data_node), pointer :: x ! Local variables integer :: idx, parent call mprintf((end_of_heap == HEAPSIZE),ERROR, 'add_to_heap(): Maximum heap size exceeded') end_of_heap = end_of_heap + 1 idx = end_of_heap heap(idx)%object => x heap(idx)%object%heap_index = idx do while (idx > 1) parent = floor(real(idx)/2.) if (heap(idx)%object%last_used < heap(parent)%object%last_used) then heap(idx)%object => heap(parent)%object heap(idx)%object%heap_index = idx heap(parent)%object => x heap(parent)%object%heap_index = parent idx = parent else idx = 1 end if end do end subroutine add_to_heap subroutine remove_index(idx) implicit none ! Arguments integer, intent(in) :: idx ! Local variables integer :: indx, left, right type (data_node), pointer :: temp heap(idx)%object => heap(end_of_heap)%object heap(idx)%object%heap_index = idx end_of_heap = end_of_heap - 1 indx = idx do while (indx <= end_of_heap) left = indx*2 right = indx*2+1 if (right <= end_of_heap) then if (heap(right)%object%last_used < heap(left)%object%last_used) then if (heap(right)%object%last_used < heap(indx)%object%last_used) then temp => heap(indx)%object heap(indx)%object => heap(right)%object heap(indx)%object%heap_index = indx heap(right)%object => temp heap(right)%object%heap_index = right indx = right else indx = end_of_heap + 1 end if else if (heap(left)%object%last_used < heap(indx)%object%last_used) then temp => heap(indx)%object heap(indx)%object => heap(left)%object heap(indx)%object%heap_index = indx heap(left)%object => temp heap(left)%object%heap_index = left indx = left else indx = end_of_heap + 1 end if end if else if (left <= end_of_heap) then if (heap(left)%object%last_used < heap(indx)%object%last_used) then temp => heap(indx)%object heap(indx)%object => heap(left)%object heap(indx)%object%heap_index = indx heap(left)%object => temp heap(left)%object%heap_index = left indx = left else indx = end_of_heap + 1 end if else indx = end_of_heap + 1 end if end do end subroutine remove_index subroutine get_min(x) implicit none ! Arguments type (data_node), pointer :: x ! Local variables integer :: idx, left, right type (data_node), pointer :: temp call mprintf((end_of_heap <= 0),ERROR, 'get_min(): No items left in the heap.') x => heap(1)%object heap(1)%object => heap(end_of_heap)%object heap(1)%object%heap_index = 1 end_of_heap = end_of_heap - 1 idx = 1 do while (idx <= end_of_heap) left = idx*2 right = idx*2+1 if (right <= end_of_heap) then if (heap(right)%object%last_used < heap(left)%object%last_used) then if (heap(right)%object%last_used < heap(idx)%object%last_used) then temp => heap(idx)%object heap(idx)%object => heap(right)%object heap(idx)%object%heap_index = idx heap(right)%object => temp heap(right)%object%heap_index = right idx = right else idx = end_of_heap + 1 end if else if (heap(left)%object%last_used < heap(idx)%object%last_used) then temp => heap(idx)%object heap(idx)%object => heap(left)%object heap(idx)%object%heap_index = idx heap(left)%object => temp heap(left)%object%heap_index = left idx = left else idx = end_of_heap + 1 end if end if else if (left <= end_of_heap) then if (heap(left)%object%last_used < heap(idx)%object%last_used) then temp => heap(idx)%object heap(idx)%object => heap(left)%object heap(idx)%object%heap_index = idx heap(left)%object => temp heap(left)%object%heap_index = left idx = left else idx = end_of_heap + 1 end if else idx = end_of_heap + 1 end if end do end subroutine get_min end module minheap_module