Logo Search packages:      
Sourcecode: scamper version File versions  Download package

mjl_heap.c

/*
 * heap routines
 * by Matthew Luckie
 *
 * Adapted from the priority queue in "Robert Sedgewick's Algorithms in C++"
 *
 * Copyright (C) 2006-2007 Matthew Luckie. All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY Matthew Luckie ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL Matthew Luckie BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id: mjl_heap.c,v 1.3 2007/05/10 02:24:03 mjl Exp $
 *
 */

#include <stdlib.h>
#include <assert.h>

#if defined(DMALLOC)
#include <dmalloc.h>
#endif

#include "mjl_heap.h"

#define HEAP_GROWBY 128

struct heap_node
{
  int   id;
  void *item;
};

struct heap
{
  heap_node_t **a;
  int           N;
  int           max;
  heap_cmp_t    cmp;
};

#ifndef NDEBUG
static void heap_assert(const heap_t *heap)
{
  int i;
  for(i=1; i <= heap->N; i++)
    {
      assert(heap->a[i]->id == i);

      /* parent has to have higher priority than its children */
      if(i+i <= heap->N)
      {
        assert(heap->cmp(heap->a[i]->item, heap->a[i+i]->item) >= 0);
      }
      if(i+i+1 <= heap->N)
      {
        assert(heap->cmp(heap->a[i]->item, heap->a[i+i+1]->item) >= 0);
      }
    }
  return;
}
#else
#define heap_assert(heap)((void)0)
#endif

static void upheap(heap_t *heap, int k)
{
  heap_node_t *v = heap->a[k];

  while(k > 1 && heap->cmp(heap->a[k/2]->item, v->item) <= 0)
    {
      heap->a[k] = heap->a[k/2];
      heap->a[k]->id = k;

      k = k/2;
    }

  heap->a[k] = v;
  v->id = k;

  return;
}

static void downheap(heap_t *heap, int k)
{
  heap_node_t *v = heap->a[k];
  int j;

  while(k <= heap->N/2)
    {
      j = k+k;

      if(j < heap->N && heap->cmp(heap->a[j]->item, heap->a[j+1]->item) < 0)
      {
        j++;
      }

      if(heap->cmp(v->item, heap->a[j]->item) >= 0)
      {
        break;
      }

      heap->a[k] = heap->a[j];
      heap->a[k]->id = k;

      k = j;
    }

  heap->a[k] = v;
  heap->a[k]->id = k;

  return;
}

heap_t *heap_alloc(heap_cmp_t cmp)
{
  heap_t *heap = NULL;

  if((heap = malloc(sizeof(heap_t))) == NULL)
    {
      goto err;
    }

  heap->N   = 0;
  heap->max = HEAP_GROWBY;
  heap->cmp = cmp;

  if((heap->a = malloc(sizeof(heap_node_t *) * heap->max)) == NULL)
    {
      goto err;
    }

  return heap;

 err:
  heap_free(heap, NULL);
  return NULL;
}

void heap_free(heap_t *heap, heap_free_t free_func)
{
  int i;

  if(heap != NULL)
    {
      if(heap->a != NULL)
      {
        for(i=1; i <= heap->N; i++)
          {
            if(free_func != NULL)
            {
              free_func(heap->a[i]->item);
            }
            free(heap->a[i]);
          }

        free(heap->a);
      }
      free(heap);
    }

  return;
}

heap_node_t *heap_insert(heap_t *heap, void *ptr)
{
  heap_node_t *node = NULL;
  void *tmp;
  size_t size;

  heap_assert(heap);

  /* allocate a new node */
  if((node = malloc(sizeof(heap_node_t))) == NULL)
    {
      goto err;
    }
  node->id   = heap->N+1;
  node->item = ptr;

  /* determine if we need to increase the size of the array for this node */
  if(node->id >= heap->max)
    {
      size = (heap->max + HEAP_GROWBY) * sizeof(heap_node_t *);
      if((tmp = realloc(heap->a, size)) == NULL)
      {
        goto err;
      }

      heap->max += HEAP_GROWBY;
      heap->a = (heap_node_t **)tmp;
    }

  /* insert the new node, and then satisfy the heap condition */
  heap->a[node->id] = node;
  heap->N++;
  upheap(heap, heap->N);

  heap_assert(heap);

  return node;

 err:
  if(node != NULL) free(node);
  return NULL;
}

/*
 * heap_head_node
 *
 * return the node at the top of the heap, without removing it.
 */
heap_node_t *heap_head_node(heap_t *heap)
{
  heap_assert(heap);

  if(heap->N == 0)
    {
      return NULL;
    }

  return heap->a[1];
}

/*
 * heap_head_item
 *
 * return the item at the top of the heap, without removing it.
 */
void *heap_head_item(heap_t *heap)
{
  heap_assert(heap);

  if(heap->N == 0)
    {
      return NULL;
    }

  return heap->a[1]->item;
}

void *heap_remove(heap_t *heap)
{
  heap_node_t *v;
  void *item;

  heap_assert(heap);

  if(heap->N == 0)
    {
      return NULL;
    }

  v = heap->a[1];

  heap->a[1] = heap->a[heap->N--];
  heap->a[1]->id = 1;

  downheap(heap, 1);

  item = v->item;
  free(v);

  heap_assert(heap);

  return item;
}

void heap_foreach(heap_t *heap, void *param, heap_foreach_t func)
{
  int i;

  for(i=1; i <= heap->N; i++)
    {
      func(param, heap->a[i]->item);
    }

  return;
}

int heap_count(heap_t *heap)
{
  return heap->N;
}

void *heap_node_item(heap_node_t *node)
{
  return node->item;
}

int heap_node_id(heap_node_t *node)
{
  return node->id;
}

/*
 * heap_delete
 *
 * take the last node in the heap and replace the node to be deleted with
 * it.  then, satisfy the heap condition.
 */
void heap_delete(heap_t *heap, heap_node_t *node)
{
  heap_node_t *v;
  int i;

  heap_assert(heap);

  if(node->id == heap->N)
    {
      heap->N--;
    }
  else
    {
      /*
       * take the last node and put it in the array where the value being
       * deleted is
       */
      heap->a[node->id] = v = heap->a[heap->N--];
      heap->a[node->id]->id = node->id;

      /* if the priority of the item being replaced is raised, upheap */
      if((i = heap->cmp(v->item, node->item)) > 0)
      {
        upheap(heap, node->id);
      }
      /* if the priority of the item being replaced is lowered, downheap */
      else if(i < 0)
      {
        downheap(heap, node->id);
      }
    }

  free(node);

  heap_assert(heap);

  return;
}

Generated by  Doxygen 1.6.0   Back to index