/**************************************************************************** * * MODULE: r.cost * * AUTHOR(S): Antony Awaida - IESL - M.I.T. * James Westervelt - CERL * Pierre de Mouveaux * Eric G. Miller * * min heap by Markus Metz * * PURPOSE: Outputs a raster map layer showing the cumulative cost * of moving between different geographic locations on an * input raster map layer whose cell category values * represent cost. * * COPYRIGHT: (C) 2006-2009 by the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS * for details. * ***************************************************************************/ /* These routines manage the list of grid-cell candidates for * visiting to calculate distances to surrounding cells. * A min-heap approach is used. Components are * sorted first by distance then by the order in which they were added. * * insert () * inserts a new row-col with its distance value into the heap * * delete() * deletes a row-col entry in the heap * * get_lowest() * retrieves the entry with the smallest distance value */ #include #include #include #include "cost.h" #define GET_PARENT(c) (((c) - 2) / 3 + 1) #define GET_CHILD(p) (((p) * 3) - 1) static long next_point = 0; static long heap_size = 0; static long heap_alloced = 0; static struct cost **heap_index, *free_point; int init_heap(void) { next_point = 0; heap_size = 0; heap_alloced = 1000; heap_index = (struct cost **) G_malloc(heap_alloced * sizeof(struct cost *)); free_point = NULL; return 0; } int free_heap(void) { if (heap_alloced) G_free(heap_index); if (free_point) G_free(free_point); return 0; } /* compare two costs * return 1 if a < b else 0 */ int cmp_costs(struct cost *a, struct cost *b) { if (a->min_cost < b->min_cost) return 1; else if (a->min_cost == b->min_cost) { if (a->age < b->age) return 1; } return 0; } long sift_up(long start, struct cost * child_pnt) { register long parent, child; child = start; while (child > 1) { parent = GET_PARENT(child); /* child is smaller */ if (cmp_costs(child_pnt, heap_index[parent])) { /* push parent point down */ heap_index[child] = heap_index[parent]; child = parent; } else /* no more sifting up, found new slot for child */ break; } /* put point in new slot */ if (child < start) { heap_index[child] = child_pnt; } return child; } struct cost *insert(double min_cost, int row, int col) { struct cost *new_cell; if (free_point) { new_cell = free_point; free_point = NULL; } else new_cell = (struct cost *)(G_malloc(sizeof(struct cost))); new_cell->min_cost = min_cost; new_cell->age = next_point; new_cell->row = row; new_cell->col = col; next_point++; heap_size++; if (heap_size >= heap_alloced) { heap_alloced += 1000; heap_index = (struct cost **) G_realloc((void *)heap_index, heap_alloced * sizeof(struct cost *)); } heap_index[heap_size] = new_cell; sift_up(heap_size, new_cell); return (new_cell); } struct cost *get_lowest(void) { struct cost *next_cell; register long parent, child, childr, i; if (heap_size == 0) return NULL; next_cell = heap_index[1]; heap_index[0] = next_cell; if (heap_size == 1) { heap_size--; heap_index[1] = NULL; return next_cell; } /* start with root */ parent = 1; /* sift down: move hole back towards bottom of heap */ while ((child = GET_CHILD(parent)) <= heap_size) { /* select smallest child */ if (child < heap_size) { childr = child + 1; i = child + 3; while (childr < i && childr <= heap_size) { /* get smallest child */ if (cmp_costs(heap_index[childr], heap_index[child])) { child = childr; } childr++; } } /* move hole down */ heap_index[parent] = heap_index[child]; parent = child; } /* hole is in lowest layer, move to heap end */ if (parent < heap_size) { heap_index[parent] = heap_index[heap_size]; /* sift up last swapped point, only necessary if hole moved to heap end */ sift_up(parent, heap_index[parent]); } /* the actual drop */ heap_size--; return next_cell; } int delete(struct cost *delete_cell) { if (free_point) G_free(delete_cell); else free_point = delete_cell; return 0; }